首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Febers
V2EX  ›  Java

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

  •  
  •   Febers · 117 天前 · 2590 次点击
    这是一个创建于 117 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在一个类的实例方法中,可以直接通过 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;
        }
    }
    
    17 条回复    2019-12-24 17:09:28 +08:00
    anakinsky
        1
    anakinsky   117 天前
    我理解的是 super 本质是关键字 而非某对象的某成员变量 /函数 所以你无法使用对象调用关键字
    Febers
        2
    Febers   117 天前
    @anakinsky #1 有这种可能,我的疑惑是,既然方法引用有这种形式,把父类的方法引用限定在子类内部,其他地方无法调用,会不会没什么必要

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

    4. 个人推断, 不保证正确, 并没有找到官方说明.
    Febers
        6
    Febers   117 天前
    @guxingke #4 反编译之后,super 确实是被替换成 animal 的实例
    Febers
        7
    Febers   117 天前
    @chendy #5 里面好像也没有更多的信息~
    guyeu
        8
    guyeu   117 天前
    因为不存在父类的实例这么个东西,你实例化一个类的时候,实例化出的就是一个对象,并不是父类有个对象子类有个对象。
    但是在类内部有需求访问这个类继承自父类的方法、属性,所以有了 super 这么个关键字,用来区分当前类和它的父类,不会引起混淆的情况下你省略这个关键字也没关系。
    但是在类外面不能使用这个关键字,这会破坏对象的封装和继承。
    KentY
        9
    KentY   117 天前
    可能是我见的代码太少了, 好像我没见过 object.super.method()这种 super 夹在俩点儿中间的情况.
    "object.super"是什么呢, super 应该是没有这个用法吧? 通常"super"只在子类自身里用
    janus77
        10
    janus77   117 天前
    好像是在类的内部才能正常使用 super,直接用点去调用是不行的
    mxalbert1996
        11
    mxalbert1996   117 天前 via Android
    这样做有什么意义?允许在类外访问超类成员完全违反了 OOP 的原则,并且不经过子类直接调用父类方法会导致子类无法正常工作。
    Febers
        12
    Febers   117 天前 via Android
    @guyeu #8 @guyeu #8 确实是这样的,其实问题在于 Function Reference 有一种形式是 TypeName.super::function,然后我又是在 Main 类中引用,想写出这种形式发现没法做到。
    Febers
        13
    Febers   117 天前 via Android
    @KentY #9 确实是没有这种用法的,不过可以在类的实例方法中调用 SubClass.super.function。
    而我又想在外部 Main 类中进行方法引用,方法引用又有一一种父类方法引用的方式,所以才有这个问题
    Febers
        14
    Febers   117 天前 via Android
    @janus77 #10 对的,还得是实例方法
    KentY
        15
    KentY   116 天前
    @Febers 没太懂你说的"在类的实例方法中"SubClass.super.function...
    你是说你的例子 //报错 那行可以写 Bird.super.action() ?
    Febers
        16
    Febers   116 天前
    @KentY #15 意思是 在 Bird 的非静态方法中可以调用 Bird.super.action() 实现调用父类方法的目的,但是在其他地方,想调用就不行
    比如在 Main 中,第一种调用形式,Bird.super.action 明显不行,因为 Bird 没有实例,无法调用它自身或者它父类(如果有的话)的 action 这一个实例方法;第二种调用形式,Bird bird = new Bird(); bird.super.action(),报错,才有了我的疑惑
    hitsmaxft
        17
    hitsmaxft   104 天前
    写上 super 的地方, 会被 jvm 编译成 invokespecial 指令,
    如果用字节码 INVOKESPECIAL 可以对一个 object 调用任意合法方法, 用反射是能做到的,我没验证,只是搜了一下有现成例子。
    至于为什么 java 不允许, 继承时存在方法 override,不想被从外界胡乱使用。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2512 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 15:39 · PVG 23:39 · LAX 08:39 · JFK 11:39
    ♥ Do have faith in what you're doing.