1. 四种访问权限修饰符
1.1 类关系
自身 : 指的是当前类自己。
同包子类 : 子类 , 并且处于同一个包下。
同包其他类 : 没有继承关系 , 但是处于同一个包下。
不同包子类 : 子类 , 但是在另一个包下。
不同包其他类 : 没有继承关系 , 并且在另一个包下。
1.2 四种访问权限控制
Java 中一共有四种访问权限控制,其权限控制的大小情况是这样的:
public > protected > default(包访问权限) > private 。
- private:私有的;只在本类中可以使用;
- package/friendly/default/不写:默认访问权限,也叫做包访问权限;只对同包的类具有访问的权限,外包的所有类都不能访问。
- protected:受保护的;这种权限是为继承而设计的,protected所修饰的成员,对同包下的所有类是可访问的,对所有子类是可访问的。言外之意,它对外包下的非子类是不可访问的。
- public:公共的;所修饰的类、变量、方法,在整个工程中即内外包均具有访问权限。
注:当类、接口、枚举类、方法、成员变量等没有明确使用public、protected、private等权限修饰符进行修饰,就是default权限。
注意区分protected 权限和包访问权限,正确使用它们:
当某个成员能被所有的子类继承,但不能被外包的非子类访问,就是用protected;
当某个成员的访问权限只对同包的类开放,包括不能让外包的类继承这个成员,就用包访问权限;
2. 使用访问权限修饰符的原因
封装,将某些逻辑封装在类的内部,从而保障:
- 保证内部的逻辑更改对外部的使用是透明的;
- 限制外部随意访问内部逻辑。
3. 访问权限修饰符场景
3.1 对外部类的访问权限修饰符
java中对 类、枚举类、接口,只能使用两种访问权限修饰符:public、default。
- public修饰的类所在的*.java文件名称必须和该类名称相同,且一个java源文件中最多只能有一个public修饰的类。
- default修饰的类所在的*.java文件名称不用和该类名称相同,一个java源文件中可以包含多个default修饰的类。
3.2 对类内部成员的访问权限修饰符
一个类的内部成员一般包括:成员内部类、成员变量、成员方法、构造方法。
tips:内部类的优点即,能够方便的在多个内部类之间共享外部类的数据,这在实现多线程那块尤其有用。
java中对 内部类、成员变量、成员方法、构造方法 可以使用所有访问权限修饰符:public、protected、default、private。
下面的访问权限修饰符针对的是class中的成员内部类、成员变量(属性、静态成员)、成员方法(方法、动态成员)、构造方法而言的:
注意点:
此处类里面的成员,指的是类的全局成员,而不是局部变量、局部内部类等。换句话说,局部的东西只在其作用域生效,不可能被其他类访问,因此不需要访问权限修饰符。
3.3 对抽象方法的访问权限修饰符
普通方法是可以使用四种访问权限的,但抽象方法是有一个限制:不能用 private 来修饰,也即抽象方法不能是私有的,否则,子类就无法继承实现抽象方法。
3.4 对接口成员的访问权限修饰符
接口本身具备特殊性,接口中成员规定是固定的,即接口中包含:
- 公共的静态的全局常量;
- 公共的非静态的抽象方法。
所以,说白了,接口中强制规定所有成员的访问权限修饰符只能是 public ,而且是默认规定,如果不显式书写,则编译器默认帮我们编译成public static的。
因此,对于接口中的成员,可以少些修饰符,但不能写错修饰符。
4. 你真的了解protected访问权限吗?
参考:
Java 访问权限控制:你真的了解 protected 关键字吗?
关于java中的protected访问权限
Java 权限protected关键字纠正
Java访问控制中private,default,protected和public的区别
java基础(七) java四种访问权限
从前面的访问权限,甚至随便一本java书籍或者访问权限相关的文章可知:
protected修饰符修饰的成员,表示可以被同一个包中的类(当然包括同包中的子类)和其他包中的子类访问。
这个解释很模糊。
我们会轻易的产生一种误解: 我们总以为protected修饰的父类中的成员,在外包中的子类是可以随便访问的。只要这个子类继承了父类,就能像在同一个包中一样,随便的访问父类中的protected成员。
直到有一天,你偶然的写了一个子类 Class A,然后覆盖了父类Object的clone()方法。
不过你大意了,忘记把Object类中clone方法原有的protected权限给扩大为public了。
不过在类A中复写clone方法时,权限没有扩大也不影响访问Object的clone()方法。
于是你的复写如下:
package a1;
class A{
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
如果按照java上标准的写法,覆盖clone()方法应该是下面这个样子的:
package a1;
class A{
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
我们知道,在覆盖父类方法时,对应方法的权限不能小于父类中该方法的权限。
当然,我们还知道,往往我们在覆盖父类方法时,当父类和我们的子类在同一个包中定义,父类方法是default修饰时,子类总会将权限扩大为public。
这样做的目的很明显,因为父类中该方法是default,即只能在同一个包中访问,因此子类扩大权限,就是想让外部类能够访问子类覆盖后的该方法。
但是,这次我们没注意,在复写 clone 方法时,没有将覆盖后的方法扩大为 public 权限。 可转念一想,Object类中的clone方法本来就是protected的啊,那就不用扩大为public啊,任何类都是Object的子类,而protected是任何子类都可以访问的。
因此,就这么写,没任何问题。
恍然大悟,顺带还ma了一句,其他人真sha啊,每次复写protected还必须扩大为public,这样不是sha吗。
于是,你在另外一个包中,写了main方法,准备调用A类中覆盖的clone方法:
package a2;
class Main extends A{
public static void main(String args[]){
A a = new A();
// 虽然A类没有将clone方法扩展为public,但是此时类Main继承了A,所以Main类中完全可以通过A的对象访问A中的方法。
// 然而,此处报错了。编译不过,直接飘红。
a.clone();
}
}
文档信息
- 本文作者:Marshall