- 要学会把变动的代码与保持不变的代码区分开来。
- 如果有必要,你尽可能将一切方法都定为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();
}
}