Java 中通过 ClassName.super 获取直接父类的引用范围的疑惑

2019-12-11 14:05:24 +08:00
 Febers

在一个类的实例方法中,可以直接通过 ClassName.super ( ClassName 可省略)获取其直接父类的实例,但是在其他类中,使用 classInstance.super 引用其父类却报错,IDE 报错信息为:Class name expected here,Java 这么做的考虑是什么呢?

学习 Java 的方法引用的时候遇到这个问题。方法引用有一种情况是,可以引用超类的方法,代码如下

public abstract class Animal {

    public void action() {
        System.out.println("The animal is running");
    }
}

public class Bird extends Animal {

    public void action() {
        
        System.out.println("The bird is flying");

        //引用父类方法
        Runnable r = super::action;
        r.run();
    }
}

方法调用

public class Main {

    public static void main(String[] args) {

        Bird bird = new Bird();

        //正常运行
        Runnable r = bird::action;
        r.run();

        //报错
        Runnable r1 = bird.super::action;
    }
}
4224 次点击
所在节点    Java
17 条回复
anakinsky
2019-12-11 14:55:44 +08:00
我理解的是 super 本质是关键字 而非某对象的某成员变量 /函数 所以你无法使用对象调用关键字
Febers
2019-12-11 15:17:37 +08:00
@anakinsky #1 有这种可能,我的疑惑是,既然方法引用有这种形式,把父类的方法引用限定在子类内部,其他地方无法调用,会不会没什么必要

无法使用对象调用关键字这件事还是存疑,实例化非静态内部类的时候,就会用到 OutClass.InnerClass innerClass = outClass.new OutClass.InnerClass() 这种形式,那么 outClass 后面的 .new 是不是调用关键字呢
gotonull
2019-12-11 16:08:26 +08:00
super 是当前类的一个私有成员
guxingke
2019-12-11 16:36:51 +08:00
1. super 是个关键字 , 用处就是标志当前类的父类, 此处可以 反编译 class 推断.
2. 外部为什么无法使用 xxx.super.yyy , 编译器约束.
3. 方法引用是个语法糖. 跟这个问题没有直接关系.

4. 个人推断, 不保证正确, 并没有找到官方说明.
chendy
2019-12-11 16:38:00 +08:00
Febers
2019-12-11 19:34:30 +08:00
@guxingke #4 反编译之后,super 确实是被替换成 animal 的实例
Febers
2019-12-11 19:38:35 +08:00
@chendy #5 里面好像也没有更多的信息~
guyeu
2019-12-11 21:00:37 +08:00
因为不存在父类的实例这么个东西,你实例化一个类的时候,实例化出的就是一个对象,并不是父类有个对象子类有个对象。
但是在类内部有需求访问这个类继承自父类的方法、属性,所以有了 super 这么个关键字,用来区分当前类和它的父类,不会引起混淆的情况下你省略这个关键字也没关系。
但是在类外面不能使用这个关键字,这会破坏对象的封装和继承。
KentY
2019-12-11 21:15:10 +08:00
可能是我见的代码太少了, 好像我没见过 object.super.method()这种 super 夹在俩点儿中间的情况.
"object.super"是什么呢, super 应该是没有这个用法吧? 通常"super"只在子类自身里用
janus77
2019-12-11 21:29:42 +08:00
好像是在类的内部才能正常使用 super,直接用点去调用是不行的
mxalbert1996
2019-12-11 22:05:16 +08:00
这样做有什么意义?允许在类外访问超类成员完全违反了 OOP 的原则,并且不经过子类直接调用父类方法会导致子类无法正常工作。
Febers
2019-12-11 23:33:07 +08:00
@guyeu #8 @guyeu #8 确实是这样的,其实问题在于 Function Reference 有一种形式是 TypeName.super::function,然后我又是在 Main 类中引用,想写出这种形式发现没法做到。
Febers
2019-12-11 23:36:12 +08:00
@KentY #9 确实是没有这种用法的,不过可以在类的实例方法中调用 SubClass.super.function。
而我又想在外部 Main 类中进行方法引用,方法引用又有一一种父类方法引用的方式,所以才有这个问题
Febers
2019-12-11 23:36:49 +08:00
@janus77 #10 对的,还得是实例方法
KentY
2019-12-12 00:08:07 +08:00
@Febers 没太懂你说的"在类的实例方法中"SubClass.super.function...
你是说你的例子 //报错 那行可以写 Bird.super.action() ?
Febers
2019-12-12 11:52:54 +08:00
@KentY #15 意思是 在 Bird 的非静态方法中可以调用 Bird.super.action() 实现调用父类方法的目的,但是在其他地方,想调用就不行
比如在 Main 中,第一种调用形式,Bird.super.action 明显不行,因为 Bird 没有实例,无法调用它自身或者它父类(如果有的话)的 action 这一个实例方法;第二种调用形式,Bird bird = new Bird(); bird.super.action(),报错,才有了我的疑惑
hitsmaxft
2019-12-24 17:09:28 +08:00
写上 super 的地方, 会被 jvm 编译成 invokespecial 指令,
如果用字节码 INVOKESPECIAL 可以对一个 object 调用任意合法方法, 用反射是能做到的,我没验证,只是搜了一下有现成例子。
至于为什么 java 不允许, 继承时存在方法 override,不想被从外界胡乱使用。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/627984

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX