关于Java接口中静态变量和静态方法的访问问题

qingliang4321 2019-04-09 09:36:00
先描述一下我的困惑:
接口中静态变量可以通过实现类或者实现类的实例访问到,而静态方法就不能通过实现类或者实现类的实例调用,这是为什么呢,原理是什么?求大神解释!

上代码:

public interface DemoA {
static String a = "123";

static String test() {
return "静态方法test()";
}
}

class DemoB implements DemoA {

public static void main(String[] args) {
DemoB demoB = new DemoB();
System.out.println(demoB.a); //实现类的实例可以调用接口中的静态变量
System.out.println(DemoB.a); //实现类可以直接调用接口中的静态变量
// System.out.println(demoB.test()); //实现类的实例不可以调用接口中的静态方法
// System.out.println(DemoB.test()); //实现类不可以直接调用接口的静态方法
}

}

interface DemoC {
static String a = "456";
}

class DemoD implements DemoA, DemoC {
public static void main(String[] args) {
DemoD demoD = new DemoD();
//当实现类实现了两个接口,两个接口有一样的成员变量的时候,此时实现类和实现类的实例都无法调用接口的静态变量了,因为编译器无法选择
// System.out.println(demoD.a);
// System.out.println(DemoD.a);
}
}


上述代码中,DemoB实现了DemoA接口,但是DemoB和DemoB的实例demoB都可以访问到DemoA接口中的静态变量(IDE无报错提示,可以编译通过并运行),但是无法调用DemoA接口中的静态方法(无法通过编译)。
我从网上搜的资料就是静态方法无法通过实现类去访问是因为接口可以多实现,当实现的两个接口里,有相同的静态方法的时候,直接用实现类去调用静态方法,虚拟机无法判断是哪一个接口的静态方法了。
但是接口中静态变量存在同样的问题啊,比如DemoD实现了DemoA接口和DemoC接口,两个接口有相同的成员变量a,此时实现类就无法区分到底是哪个接口里的成员变量,就会报错了。按常理来说,接口静态变量应该和静态方法一样啊,所以比较困惑,求大神解释!
...全文
1508 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
黄河边 2020-03-23
  • 打赏
  • 举报
回复
接口中的函数需要继承类去实现,仅仅是一个函数原型,无法直接调用。
qq_43464974 2019-04-23
  • 打赏
  • 举报
回复
引用 楼主 qingliang4321的回复:
先描述一下我的困惑:
接口中静态变量可以通过实现类或者实现类的实例访问到,而静态方法就不能通过实现类或者实现类的实例调用,这是为什么呢,原理是什么?求大神解释!

上代码:

public interface DemoA {
static String a = "123";

static String test() {
return "静态方法test()";
}
}

class DemoB implements DemoA {

public static void main(String[] args) {
DemoB demoB = new DemoB();
System.out.println(demoB.a); //实现类的实例可以调用接口中的静态变量
System.out.println(DemoB.a); //实现类可以直接调用接口中的静态变量
// System.out.println(demoB.test()); //实现类的实例不可以调用接口中的静态方法
// System.out.println(DemoB.test()); //实现类不可以直接调用接口的静态方法
}

}

interface DemoC {
static String a = "456";
}

class DemoD implements DemoA, DemoC {
public static void main(String[] args) {
DemoD demoD = new DemoD();
//当实现类实现了两个接口,两个接口有一样的成员变量的时候,此时实现类和实现类的实例都无法调用接口的静态变量了,因为编译器无法选择
// System.out.println(demoD.a);
// System.out.println(DemoD.a);
}
}


上述代码中,DemoB实现了DemoA接口,但是DemoB和DemoB的实例demoB都可以访问到DemoA接口中的静态变量(IDE无报错提示,可以编译通过并运行),但是无法调用DemoA接口中的静态方法(无法通过编译)。
我从网上搜的资料就是静态方法无法通过实现类去访问是因为接口可以多实现,当实现的两个接口里,有相同的静态方法的时候,直接用实现类去调用静态方法,虚拟机无法判断是哪一个接口的静态方法了。
但是接口中静态变量存在同样的问题啊,比如DemoD实现了DemoA接口和DemoC接口,两个接口有相同的成员变量a,此时实现类就无法区分到底是哪个接口里的成员变量,就会报错了。按常理来说,接口静态变量应该和静态方法一样啊,所以比较困惑,求大神解释!
5.将n个数据存放到数组中(其中n是小于等于100的整数),找出数组中比这n个数 小的数。
qq_39936465 2019-04-15
  • 打赏
  • 举报
回复
引用 9 楼 qingliang4321 的回复:
[quote=引用 7 楼 qq_39936465 的回复:]
因为静态变量本身就可以直接调用无需实例化,当产生多接口变量名重复时,可以直接使用接口.变量名直接使用,没必要用实例变量名。

那你不觉得很奇怪吗,之所以静态方法不能通过实现类和实例来调用,就是怕实现多接口的时候有重复的问题。而静态变量也有这个问题,但是静态变量居然没有和静态方法一样禁止通过实现类来调用。[/quote]

因为接口本来的定义都是抽象类的集合,需要子类重写的,但是加入了静态方法后,静态方法不能被重写。所以这里只是继承但是不能使用,如果要使用的话需要从父类调用,这里其实把静态方法看成了父类的私有方法。
qingliang4321 2019-04-15
  • 打赏
  • 举报
回复
引用 14 楼 qq_39936465 的回复:
[quote=引用 13 楼 qingliang4321 的回复:] 谢谢回复,但是你不觉得你的表述有很大的问题吗? 我的问题很明确了,就是问接口中静态变量引用的问题。你上来直接就讲静态方法,丝毫没说静态变量的引用问题,你直接说静态变量允许调用是1.0就定下的不就可以了... 再问一下,继承和实现还是不太一样吧,继承子类中静态变量和静态方法在接口的实现类中都一样吗? 编译器对静态变量和静态方法编译有啥不一样,这个我搜过,搜不到才来问的。
静态变量可以被子类继承并使用,静态方法可以被子类继承并被隐藏不可以被直接使用,不管父类是接口还是其他类都是一样的,这个可能是当初设计java者的设定,目前还未改变。 虽然子类继承了父类的全部,但是不能代表全部可以以子类的名义直接使用,例如:父类的私有变量和静态方法,这些在子类初始化后被隐藏了,都不能子类直接使用。[/quote] 谢了
qq_39936465 2019-04-15
  • 打赏
  • 举报
回复
引用 13 楼 qingliang4321 的回复:
谢谢回复,但是你不觉得你的表述有很大的问题吗? 我的问题很明确了,就是问接口中静态变量引用的问题。你上来直接就讲静态方法,丝毫没说静态变量的引用问题,你直接说静态变量允许调用是1.0就定下的不就可以了... 再问一下,继承和实现还是不太一样吧,继承子类中静态变量和静态方法在接口的实现类中都一样吗? 编译器对静态变量和静态方法编译有啥不一样,这个我搜过,搜不到才来问的。
静态变量可以被子类继承并使用,静态方法可以被子类继承并被隐藏不可以被直接使用,不管父类是接口还是其他类都是一样的,这个可能是当初设计java者的设定,目前还未改变。 虽然子类继承了父类的全部,但是不能代表全部可以以子类的名义直接使用,例如:父类的私有变量和静态方法,这些在子类初始化后被隐藏了,都不能子类直接使用。
qingliang4321 2019-04-15
  • 打赏
  • 举报
回复
引用 12 楼 qq_39936465 的回复:
[quote=引用 11 楼 qingliang4321 的回复:] [quote=引用 10 楼 qq_39936465 的回复:] [quote=引用 9 楼 qingliang4321 的回复:] [quote=引用 7 楼 qq_39936465 的回复:] 因为静态变量本身就可以直接调用无需实例化,当产生多接口变量名重复时,可以直接使用接口.变量名直接使用,没必要用实例变量名。
那你不觉得很奇怪吗,之所以静态方法不能通过实现类和实例来调用,就是怕实现多接口的时候有重复的问题。而静态变量也有这个问题,但是静态变量居然没有和静态方法一样禁止通过实现类来调用。[/quote] 因为接口本来的定义都是抽象类的集合,需要子类重写的,但是加入了静态方法后,静态方法不能被重写。所以这里只是继承但是不能使用,如果要使用的话需要从父类调用,这里其实把静态方法看成了父类的私有方法。[/quote] 老哥,我问的不是静态方法,是静态变量!静态变量!静态变量! 问题是:静态变量为啥不是必须通过父类调用?你们回答问题不看题的吗。。。醉了[/quote] 你还没理解我意思,接口在java1.0 就允许使用静态变量的不允许使用静态方法,编译器对静态变量和静态方法编译都不同的, 静态方法子类只可继承不可直接使用这个是最初对静态方法的设定。java8里不过沿用了普通类对静态方法的使用,没有从根本上改写静态方法的使用,所以静态变量和静态方法对编译器来说是2种性质的东西,你非要放在一起说。[/quote] 谢谢回复,但是你不觉得你的表述有很大的问题吗? 我的问题很明确了,就是问接口中静态变量引用的问题。你上来直接就讲静态方法,丝毫没说静态变量的引用问题,你直接说静态变量允许调用是1.0就定下的不就可以了... 再问一下,继承和实现还是不太一样吧,继承子类中静态变量和静态方法在接口的实现类中都一样吗? 编译器对静态变量和静态方法编译有啥不一样,这个我搜过,搜不到才来问的。
qq_39936465 2019-04-15
  • 打赏
  • 举报
回复
引用 11 楼 qingliang4321 的回复:
[quote=引用 10 楼 qq_39936465 的回复:] [quote=引用 9 楼 qingliang4321 的回复:] [quote=引用 7 楼 qq_39936465 的回复:] 因为静态变量本身就可以直接调用无需实例化,当产生多接口变量名重复时,可以直接使用接口.变量名直接使用,没必要用实例变量名。
那你不觉得很奇怪吗,之所以静态方法不能通过实现类和实例来调用,就是怕实现多接口的时候有重复的问题。而静态变量也有这个问题,但是静态变量居然没有和静态方法一样禁止通过实现类来调用。[/quote] 因为接口本来的定义都是抽象类的集合,需要子类重写的,但是加入了静态方法后,静态方法不能被重写。所以这里只是继承但是不能使用,如果要使用的话需要从父类调用,这里其实把静态方法看成了父类的私有方法。[/quote] 老哥,我问的不是静态方法,是静态变量!静态变量!静态变量! 问题是:静态变量为啥不是必须通过父类调用?你们回答问题不看题的吗。。。醉了[/quote] 你还没理解我意思,接口在java1.0 就允许使用静态变量的不允许使用静态方法,编译器对静态变量和静态方法编译都不同的, 静态方法子类只可继承不可直接使用这个是最初对静态方法的设定。java8里不过沿用了普通类对静态方法的使用,没有从根本上改写静态方法的使用,所以静态变量和静态方法对编译器来说是2种性质的东西,你非要放在一起说。
qingliang4321 2019-04-15
  • 打赏
  • 举报
回复
引用 10 楼 qq_39936465 的回复:
[quote=引用 9 楼 qingliang4321 的回复:] [quote=引用 7 楼 qq_39936465 的回复:] 因为静态变量本身就可以直接调用无需实例化,当产生多接口变量名重复时,可以直接使用接口.变量名直接使用,没必要用实例变量名。
那你不觉得很奇怪吗,之所以静态方法不能通过实现类和实例来调用,就是怕实现多接口的时候有重复的问题。而静态变量也有这个问题,但是静态变量居然没有和静态方法一样禁止通过实现类来调用。[/quote] 因为接口本来的定义都是抽象类的集合,需要子类重写的,但是加入了静态方法后,静态方法不能被重写。所以这里只是继承但是不能使用,如果要使用的话需要从父类调用,这里其实把静态方法看成了父类的私有方法。[/quote] 老哥,我问的不是静态方法,是静态变量!静态变量!静态变量! 问题是:静态变量为啥不是必须通过父类调用?你们回答问题不看题的吗。。。醉了
qingliang4321 2019-04-12
  • 打赏
  • 举报
回复
引用 7 楼 qq_39936465 的回复:
因为静态变量本身就可以直接调用无需实例化,当产生多接口变量名重复时,可以直接使用接口.变量名直接使用,没必要用实例变量名。
那你不觉得很奇怪吗,之所以静态方法不能通过实现类和实例来调用,就是怕实现多接口的时候有重复的问题。而静态变量也有这个问题,但是静态变量居然没有和静态方法一样禁止通过实现类来调用。
qingliang4321 2019-04-12
  • 打赏
  • 举报
回复
引用 6 楼 northwesternwind 的回复:
我觉得在实现接口的类或者实例中不能调用接口中的静态方法是合理的。原因是类实现接口后,覆盖的接口重中的抽象方法,那么在类的实现代码中就有这些方法的定义。编译时很容易确定这些方法签名,从而确定调用是否正确。运行时可以通过动态绑定去获取地址。 而静态方法因为是和类或者接口绑定的。如果允许实现接口的类访问接口中的静态方法,势必增加i编译处理的复杂性。因为通过类或者实例变量,无法识别这些静态方法的签名。
是合理的啊,但是可能你没太明白我的意思,你可以仔细看我的Demo和描述。接口的实现类和实现类的实例可以直接调用接口的静态变量而不能直调用静态方法...有点蹊跷,所以有此问。2楼老哥写的比较明白了,估计是遗留问题了。
qq_39936465 2019-04-12
  • 打赏
  • 举报
回复
因为静态变量本身就可以直接调用无需实例化,当产生多接口变量名重复时,可以直接使用接口.变量名直接使用,没必要用实例变量名。
northwesternwind 2019-04-11
  • 打赏
  • 举报
回复
我觉得在实现接口的类或者实例中不能调用接口中的静态方法是合理的。原因是类实现接口后,覆盖的接口重中的抽象方法,那么在类的实现代码中就有这些方法的定义。编译时很容易确定这些方法签名,从而确定调用是否正确。运行时可以通过动态绑定去获取地址。
而静态方法因为是和类或者接口绑定的。如果允许实现接口的类访问接口中的静态方法,势必增加i编译处理的复杂性。因为通过类或者实例变量,无法识别这些静态方法的签名。
qingliang4321 2019-04-10
  • 打赏
  • 举报
回复
引用 2 楼 coderALEX 的回复:
很好的问题,但我没有找到关于这个问题官方资料。 以下是个人看法: 关于接口的静态变量在JDK1.0就进行了定义,一开始的设计考虑不了太多,我猜关于实现类对象可以直接调用接口静态变量就是那时候定义的。 但是关于接口静态方法在JDK1.8才有了定义,而这时如何调用静态方法和静态变量明确是在类型信息初始化阶段就和类本身绑定在一起,尽量应该使用它们两者所属类或者接口来调用,即接口I的静态方法和变量就应该用I.a和I.test()来调用,其它的方式都不建议。 你所考虑的问题确实是多实现可能导致的,这应该是禁止实现类对象和类本身去调用接口的静态方法的主要原因。 关于为什么可以调用接口静态变量,我猜应该是考虑到兼容性,避免使用老版本JDK的程序崩溃。 参考: https://coderanch.com/t/655798/java/Inheritance-static-fields https://stackoverflow.com/questions/49998880/re-inheritance-static-field-from-class-and-interface https://stackoverflow.com/questions/25169175/why-are-class-static-methods-inherited-but-not-interface-static-methods https://stackoverflow.com/questions/129267/why-no-static-methods-in-interfaces-but-static-fields-and-inner-classes-ok-pr
谢谢,说的很有道理,基本解决了我的困惑了。
qingliang4321 2019-04-10
  • 打赏
  • 举报
回复
引用 3 楼 吴昀杰 的回复:
interface里面还能写普通方法?
恩,JDK1.8新特性
吴昀杰 2019-04-09
  • 打赏
  • 举报
回复
interface里面还能写普通方法?
coderALEX 2019-04-09
  • 打赏
  • 举报
回复
很好的问题,但我没有找到关于这个问题官方资料。

以下是个人看法:

关于接口的静态变量在JDK1.0就进行了定义,一开始的设计考虑不了太多,我猜关于实现类对象可以直接调用接口静态变量就是那时候定义的。

但是关于接口静态方法在JDK1.8才有了定义,而这时如何调用静态方法和静态变量明确是在类型信息初始化阶段就和类本身绑定在一起,尽量应该使用它们两者所属类或者接口来调用,即接口I的静态方法和变量就应该用I.a和I.test()来调用,其它的方式都不建议。

你所考虑的问题确实是多实现可能导致的,这应该是禁止实现类对象和类本身去调用接口的静态方法的主要原因。
关于为什么可以调用接口静态变量,我猜应该是考虑到兼容性,避免使用老版本JDK的程序崩溃。

参考:
https://coderanch.com/t/655798/java/Inheritance-static-fields
https://stackoverflow.com/questions/49998880/re-inheritance-static-field-from-class-and-interface
https://stackoverflow.com/questions/25169175/why-are-class-static-methods-inherited-but-not-interface-static-methods
https://stackoverflow.com/questions/129267/why-no-static-methods-in-interfaces-but-static-fields-and-inner-classes-ok-pr
qq_39936465 2019-04-09
  • 打赏
  • 举报
回复
我是这样理解的,静态变量或静态方法可以看做一个原子程序,它相当于一个常数,在程序载入时已经实例化了,你不能破坏它的结构,不然静态方法就 不是自己了,你只能使用它。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧