事情是这样的:
今天看到了一句话,说的是“抽象类的抽象方法可以用 public / protected / default 访问修饰符来修饰;接口的抽象方法默认是 public 访问修饰符,并且不能使用其他访问修饰符 ”,我就纳闷了同样是抽象方法为什么支持的访问修饰符却不一样呢?
网上说这是思想,这是规定,一时之间让人无法理解。
我首先想到的是,是不是我对4个访问修饰符的作用范围理解的不透彻呢,所以我决定先写个demo做一个权限修饰符的比较(结果确实是没有理解透彻,但这并不是本问题的答案,没有理解透彻的部分后面会展开)
这里先说一下如何理解吧,通过使用场景的方式。
根据网上所说“接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,主要用于实现代码的重用”
针对前一句,项目人员A写了个API模块,里面声明了一些接口,打包后供项目人员B在业务模块中去实现,如果A用默认修饰符修饰接口里的抽象方法的话,那么B必然不可能访问得到该抽象方法,更不用说去重写了。
因为接口里不能使用public以外的访问修饰符,所以接下来用抽象类来代替该业务场景
public abstract class UserApi{
abstract void login();
}
然后在另一个模块下对该接口进行实现,发现报错了。
A去写接口,目的就是让B去实现,但是根据上面的测试发现,如果可以在接口中使用default访问修饰符的话,那么B就无法对其进行实现,这显然不符合我们的初衷,而且也没有使用的必要。抽象类的使用场景这里不做尝试。
接下来是刚才的理解误区,为什么不同包中的子类无法访问父类的protected成员?
网上搜访问修饰符作用范围可以搜到大致长成下面这样的总结,在写demo期间发现我的红色框框的位置报了错
代码如下:
public class Father {
public void m1() {
}
protected void m2() {
}
void m3() {
}
private void m4() {
}
}
结果发现不同包下的子类居然无法访问到其父类的protected方法…很尴尬
这样的结果和不同包下的无关类的结果一模一样
最后得知,是使用的方式有问题,一张图确实可以把访问权限的作用范围说得明明白白,但不理解其访问方式的话还是会出现上面这样的问题的,正确的不同包下的子类的代码如下
附上访问权限的相关代码供大家玩耍
本包下:
package com.test;
public class Father {
//若不声明为public,则不同包下子类访问不到,无法继承
public void m1() {
}
protected void m2() {
}
void m3() {
}
private void m4() {
}
//本类下访问
public void m() {
m1();
m2();
m3();
m4();
//若方法m1m2m3m4都为static类型,则各类的m方法中通过Father.的方式也可以达到相同结果
}
}
class SonInTheSamePackage extends Father {
//相同包下子类访问
public void m() {
m1();
m2();
m3();
m4();//Father里被private修饰的方法报错
}
}
class UnrelatedClassInTheSamePackage {
//相同包下无关类访问
public void m() {
Father father = new Father();
father.m1();
father.m2();
father.m3();
father.m4();//Father里被private修饰的方法报错
}
}
其他包下:
package com.test2;
import com.test.Father;
class SonInDifferentPackage extends Father {
//不同包下子类访问
public void m() {
m1();
m2();
m3();//Father里被默认修饰符修饰的方法报错
m4();//Father里被private修饰的方法报错
}
}
class UnrelatedClassInDifferentPackage {
//不同包下无关类访问
public void m() {
Father father = new Father();
father.m1();
father.m2();//Father里被protected修饰的方法报错
father.m3();//Father里被默认修饰符修饰的方法报错
father.m4();//Father里被private修饰的方法报错
}
}
最后还有一个疑问,为什么不同包下子类,通过new Father()去访问m2()会失败(即上述我的理解误区),但是m2被修饰为静态的话,却能够访问成功呢(修饰为静态后类名.静态方法或实例对象.静态方法去访问都能成功,这相对于前者失败的情况来说,是为什么呢(不过不同包下的无关类依旧会访问失败))
本包下:
package com.test;
public class Father {
protected static void m2() {
}
}
其他包下:
package com.test2;
import com.test.Father;
class SonInDifferentPackage extends Father {
//不同包下子类访问
public void m() {
Father father = new Father();
father.m2();//不报错
Father.m2();//不报错
}
}
class UnrelatedClassInDifferentPackage {
//不同包下无关类访问
public void m() {
Father father = new Father();
father.m2();//报错
Father.m2();//报错
}
}
其实还是使用方式的问题,子类下访问应该去new子类对象然后访问(或者直接调用)!而不是在子类new父类对象再去访问!
但无关类去new子类对象或是父类对象然后访问,得到的结果是一样的
本包下:
package com.example.demo.test;
public class Father {
protected void m2() {
}
}
其它包下:
package com.example.demo.test2;
import com.example.demo.test.Father;
class SonInDifferentPackage extends Father {
//不同包下子类访问
public void m() {
Father father = new Father();
father.m2();//报错
SonInDifferentPackage son = new SonInDifferentPackage();
son.m2();//不报错
m2();//不报错
}
}
class UnrelatedClassInDifferentPackage {
//不同包下无关类访问
public void m() {
Father father = new Father();
father.m2();//报错
SonInDifferentPackage son = new SonInDifferentPackage();
son.m2();//报错
}
}
写的有点啰嗦了,反正就是那几种情况来回尝试,望多多包涵!