- 要學會把變動的代碼與保持不變的代碼區分開來。
- 如果有必要,你盡可能将一切方法都定為private。
- 非public類在其它包中是通路不到的。
- 所有預設包的類都是屬于同一個包,盡管它們在不同的檔案夾下面。
- private,隻允許本類所有對象可通路,其他任何類都不能通路,哪怕是它的子類或同一包中的類都不行。
- 如果一類繼承自不同包中的類,則該子類不能繼承與通路父類中的“包通路權限或預設通路權限”的屬性與方法,隻能繼承與通路protected或public的屬性與方法。
- 設計一個類時一般按照public、protected、預設、private的順序來定義屬性與方法,這樣讓人最先注意到公開的,當然,我們一般把接口與實作分離更好,這樣使用者隻關心他所需要的接口,而對實作不必理會。
- 控制對成員的通路權限有兩個原因:第一是為了使使用者不必關心那此不必關心的private部分,而隻關心類提供了哪些服務接口,即public修飾的部分。第二就是讓類庫設計者可以更改類的内部工作方式,而不必擔心這樣會客戶程式産生重大的影響。
關于protected修飾符
定義規則前,我這裡約定有三個類,一個是Base類,一個是Base類的子類Sub類,一個是Sub類的子類SubSub類,另一個是Other類且與Base、Sub、SubSub沒有繼承關系,并假設Base中有protected方法與屬性,都叫YYY吧。
- 先看看protected規則:首先要搞清楚什麼叫通路?這裡在講到的通路是有二種的:
- 一、就是在類中通過“XXX x = new XXX(); x.YYY;”的形式來通路(不妨叫此種形式為“外部通路”吧,此種通路形式除了可以應用到自己與子類中外,還可以應用在其他類中通路,其中XXX表示定義的類型,這裡可為Base與Sub、SubSub,YYY為方法或屬性);
- 二、就是this.YYY的形式來通路(不妨叫此種形式為“内部通路”吧,不過這種通路形式隻能應用在在自己的類或是子類中)。
- protected方法與屬性可通路的地方有三個:
- 1.在自己的類Base中:上面的“XXX x = new XXX(); x.YYY;”與“this.YYY”兩種通路形式都可以通路的到自己定義的portected方法或屬性;
- 2.二是子類Sub、SubSub中,這要分三種通路方式:
- a.在Sub、SubSub 中的“this.YYY”内部通路形式:在此種方式形式下,不管是否重寫或重新定義過父類Base中protected方法與屬性,子類Sub、SubSub一定可以通路的。
- b.在Sub、SubSub 中“
”外部通路形式:此種形式就不一定的能通路的到了,這要看父類Base與子類Sub、SubSub是否在同一包(注意,此時與是否重寫或重新定義過這些protedted方法與屬性沒有關系);Base x = new XXX (); x.YYY;
- c.在SubSub 中“
Sub x = new XXX (); x.YYY;
” 外部通路形式:此種通路形式能否通路關鍵看Sub是否重寫或重新定義過Base的屬性與方法:
i.如果重寫或重新定義過,則看Sub與SubSub是否在同包中
ii.如果沒有,則看Base與SubSub是否在同包中
- 3.在其他類Other中:此時隻支援外部通路形式,不過到底是要求Other與Base同包還是要求Other與Sub同包,則要依你通路方式而定了:
- a.如果是通過父類引用“
”形式來通路的,則要求Other與Base同包;Base x = new XXX (); x.YYY;
- b.如果是通過子類引用“
Sub x = new Sub (); x.YYY;
”形式來通路的,情況又會比較複雜了,此時關鍵是看子類Sub是否重寫或重新定義過父類Base中的protected方法與屬性:
i.如果重寫或重新定義過了,則要求Other與Sub同包即可;
ii.如果沒有重寫或重新定義過了,則要求Other與Base同包即可;
- a.如果是通過父類引用“
規則總結肯定有遺漏的地方,不過我隻想到這些,希望大家一起看看。看文字比較繞,下面來應用上面的規則看看這些執行個體也許會好了解一些:
package pk1.a;
public class Base {
protected int i = 1;
protected void protect() {
System.out.println("Base::protect");
}
}
package pk1.a;
import pk1.b.Sub;
public class SubSub extends Sub {
void g() {
Sub s = new SubSub();
//!! s.protect();//規則2.c.i
System.out.println(s.i);//規則2.c.ii
}
}
package pk1.b;
import pk1.a.Base;
public class Sub extends Base {
private void prt() {}
protected void protect() {
System.out.println("Base::protect");
}
void f() {
//規則2.a
this.protect();
this.i = 2;
//規則2.b
Base a2 = new Sub();
//!! a2.protect();
//!! System.out.println(a2.i);
//規則1
Sub b = new Sub();
b.protect();
b.i = 1;
b.prt();
}
}
package pk1.b;
public class SubSub extends Sub {
void g() {
Sub s = new SubSub();
s.protect();//規則2.c.i
//!! System.out.println(s.i);//規則2.c.ii
}
}
package pk1.c;
import pk1.a.Base;
import pk1.b.Sub;
public class SubSub extends Sub {
void g() {
this.protect();//規則2.a
//規則2.b
Base b = new SubSub();
//!! b.protect();
//!! System.out.println(b.i);
//規則2.b
Sub s = new SubSub();
//!! s.protect();
//!! System.out.println(s.i);
}
}
package pk2.a;
public class Base {
protected int i = 1;
protected void protect() {
System.out.println("Base::protect");
}
}
package pk2.a;
import pk2.b.Sub;
public class Other {
void g() {
//規則3.a
Base b = new Sub();
b.protect();
System.out.println(b.i);
//規則3.b.ii
Sub s = new Sub();
s.protect();
System.out.println(s.i);
}
}
package pk2.b;
import pk2.a.Base;
public class Other {
void g() {
//規則3.a
Base b = new Sub();
//!! b.protect();
//!! System.out.println(b.i);
//規則3.b.ii
Sub s = new Sub();
//!! s.protect();
//!! System.out.println(s.i);
}
}
package pk2.b;
import pk2.a.Base;
public class Sub extends Base {}
package pk3.a;
import pk3.b.Sub;
public class Base {
protected int i = 1;
protected void protect() {
System.out.println("Base::protect");
}
static protected int i_s = 1;
static protected void protect_s() {
System.out.println("Static:Base::protect");
}
void f() {
//!! Sub.i_s = 2; //規則3.b.i
Sub.protect_s();//規則3.b.ii
}
}
package pk3.a;
import pk3.b.Sub;
public class Other {
void g() {
Sub s = new Sub();
//!! s.protect();//規則3.b.i
System.out.println(s.i);//規則3.b.ii
}
void f() {
//!! Sub.i_s = 2; //規則3.b.i
Sub.protect_s();//規則3.b.ii
Base.i_s = 2;//規則3.a
Base.protect_s();//規則3.a
}
}
package pk3.b;
import pk3.a.Base;
public class Other {
void f() {
Sub.i_s = 2;//規則3.b.i
//!! Sub.protect1();//規則3.b.ii
//!! Base.i1 = 2;//規則3.a
//!! Base.protect1();//規則3.a
}
}
package pk3.b;
import pk3.a.Base;
public class Sub extends Base {
protected void protect() {
System.out.println("Base::protect");
}
static protected int i_s = 2;
void f() {
/*
* 在子類中可能通過子類類型或父類類型來來通路父類中protected靜态
* 成員,而不管子類與父類是否在同一包中,或是子類重新定義了這些成員
*
* 注,在父類或子類中通路時後面的規則不再适用
*/
System.out.println(Sub.i_s);//2
Sub.protect_s();
System.out.println(Base.i_s);//1
Base.protect_s();
}
}
- 最後,通過上面的規我們可以很好的解釋
類似的問題:Object.clone()
通路修飾符為protected,如果某個類沒有重寫此方法,則Object中的clone()方法除被自己與子類能調用方法外,其他不管與這個類在同一包還是不同包都是不可見的,因為未重寫,還是屬于Object中的方法,又Object在java.lang包中,與我們定義的包又不在java.lang包中,是以不能通路到(這也與你在在程式裡定義了Object.clone()
你還是不能在目前類中調用o.clone();一樣)。是以如果要能被不同包中的非子類克隆,則需重寫Object.clone()并設定通路權限為public(如果重寫後還是protected,則還是隻能被同一包通路)。Object o = new Object();
package a;
public class A {
protected void f() {}
void g() {}
private void p(A a) {}
private void m(A a) {
p(a);
}
public static void main(String[] args) {
A a = new A();
a.m(a);
}
}
package b;
import a.A;
public class B extends A {
protected void f() {}
private void p() {}
public void call1(B b) {
b.f();// 此種通路方式屬于通路同類中方式,是沒有問題的
f();// 屬于通路自已的方法
// !! g();// 父類中的包通路權限方法不能被子類繼承通路
b.p();//在同一類中是可以通路私有方法的,通路控制是針對整個類來說的,而不是某個對象
}
public void call12(A a) {
/*
* 即使是f()是父類中的protected方法,并且子類還重寫過了 ,但
* 是這種以父類類型執行個體通路父類中的protected方式屬于不同包非
* 子 類通路方式,是以不能通路,即使通路的代碼在子類中!
*/
// !! a.f();
A a1 = new B();
// 此種通路與上面是一樣也不能編譯
// !! a1.f();
}
public static void main(String[] args) {
B b = new B();
b.f();
A a = new B();
// 與上面 call2方法中的調用一樣,也是不能通路的
// !! a.f();
}
}