访问控制修饰符:
用来控制对类、方法和变量访问权限的修饰符。
Java 支持 4 种不同的访问权限:
default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
public : 对所有类可见。使用对象:类、接口、变量、方法
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。注意:不能修饰类(外部类)
访问控制
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public |
Y | Y | Y | Y | Y |
protected |
Y | Y | Y | Y/N | N |
default |
Y | Y | Y | N | N |
private |
Y | N | N | N | N |
- 其中,
protected
访问控制修饰符子孙类不同包时访问权限为Y/N
是指:
当子类与基类在不同包时,那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法(Y),而不能访问基类实例的protected方法(N)。
示例
- default:
- 同包父子类
package pA;
public class Father {
String defaultName = "default-name";
void printDefaultName() {
System.out.println("Father's name : " + defaultName);
}
}
package pA;
public class Son extends Father {
@Override
void printDefaultName() {
super.printDefaultName();
System.out.println("Son's name : " + defaultName);
}
}
- 不同包的子类:
package pB;
import pA.Father;
public class AnotherSon extends Father {
@Override
void printDefaultName() {
super.printdefaultName();
System.out.println("Another son's name : " + defaultName);
}
}
此时出现错误了:
如上图,不同包子类不能访问父类的
default
变量和方法,因此printName()
不能调用也不能重写,defaultNmae
也不能访问。
- 与
Father
类同包的测试:
package pA;
public class Test {
public static void main(String[] args) {
Father father = new Father();
Son son = new Son();
father.printDefaultName();
son.printDefaultName();
}
}
运行结果:
- protected
- 同包父子类
package pA;
public class Father {
protected String protectedName = "protected-name";
protected void printProtectedName() {
System.out.println("Father's name : " + protectedName);
}
}
package pA;
public class Son extends Father {
@Override
protected void printProtectedName() {
super.printProtectedName();
System.out.println("Son's name : " + protectedName);
}
}
- 不同包子类
package pB;
import pA.Father;
public class AnotherSon extends Father {
public void printAnother() {
System.out.println("Another son从父类继承来的protected方法:");
printProtectedName();
System.out.println("访问父类实例的protected方法:");
Father father = new Father();
father.printProtectedName(); // 第12行
}
}
- Father同包测试:
package pA;
import pB.AnotherSon;
public class Test {
public static void main(String[] args) {
Father father = new Father();
Son son = new Son();
AnotherSon anotherSon = new AnotherSon();
father.printProtectedName();
son.printProtectedName();
anotherSon.printProtectedName();
anotherSon.printAnother();
}
}
- 运行结果:
image.png
AnotherSon
类第12行报错,因为不同包子类不能访问父类实例的protected
方法。但是AnotherSon
可以访问自己继承的父类的protected
方法。
另外,在测试Test
中,访问了不同包的AnotherSon
实例的protected
方法anotherSon.printProtectedName();
却没有报错,这是因为它的anotherSon
的printProtectedName()
方法是继承自与Test
同包的Father
,因此没有报错。
- private
-
Father
可以访问当前类的private
变量; -
同包子类
不能访问(重写,调用)父类的private
方法和private
变量; -
不同包的子类
不能访问(重写,调用)父类的private
方法和private
变量; -
同包
Test
不能访问father
的private
方法和变量。
- public
- Father
package pA;
public class Father {
public String publicName = "public-name";
public void printPublicName() {
System.out.println("Father's name : " + publicName);
}
}
- 同包的子类
package pA;
public class Son extends Father {
@Override
public void printPublicName() {
System.out.println("同包子类可以调用父类public方法:");
super.printPublicName();
System.out.println("Son's name : " + publicName);
}
}
- 不同包的子类
package pB;
import pA.Father;
public class AnotherSon extends Father {
@Override
public void printPublicName() {
System.out.println("不同包的子类访问父类的public方法:");
super.printPublicName();
System.out.println("Another son's name : " + publicName);
}
}
- 同包测试:
package pA;
import pB.AnotherSon;
public class Test {
public static void main(String[] args) {
Father father = new Father();
Son son = new Son();
AnotherSon anotherSon = new AnotherSon();
father.printPublicName();
System.out.println();
son.printPublicName();
System.out.println();
anotherSon.printPublicName();
}
}
运行结果:
另外,补充:
- 如果子类不能访问父类的某方法或变量,则子类也不能继承;
- 对于不能被外部直接访问的变量,可以通过
getter
方法访问; -
静态方法不能使用类的非静态变量,因此,在
mian
函数中,要访问当前类的非静态变量,要先生成一个当前类的实例,然后访问实例的变量才可。