如果内部类扩展外部类,则内部类的不同成员行为?

2022-09-01 20:24:01

今天,我偶然发现了一些奇怪的内部(非静态)阶级行为。

如果我有以下课程...

class B {
    String val = "old";

    void run(){
        val = "new";
        System.out.println(val);        // outputs: new
        new InnerB().printVal();        // outputs: new
    }

    private class InnerB {
        void printVal(){ System.out.println(val); }
    }
}

new B().run();

...一切似乎都很清楚。InnerB 的实例属于 B 的实例,因此,如果它应该输出 val,它将打印已替换的值“new”。

但是,如果内部类扩展了外部类,则这不起作用。

class B {
    String val = "old";

    void run(){
        val = "new";
        System.out.println(val);        // outputs: new
        new InnerB().printVal();        // outputs: new
        new InheritedB().printVal();    // outputs: old new
    }

    private class InnerB {
        void printVal(){ System.out.println(val); }
    }

    private class InheritedB extends B{
        void printVal(){ System.out.println(val + " "+ B.this.val); }
    }
}

new B().run(); // outputs: new new old!

如果我看一下构造函数,我还看到,如果创建了 InheritedB 的实例,则会创建一个新的 B 实例。

我觉得这很奇怪...有人能解释为什么会有这种差异吗?


答案 1

此行:

new InheritedB().printVal();   

创建 一个新实例,其包含的实例是 的现有实例(其中 val 为 )。但此时有个变量:InheritedBB"new"val

  • 现有实例中的那个B
  • 实例中的那个,它有一个单独的字段InheritedBval

第二个变量的值是因为它实际上是字段的默认值。"old"

此语句位于 :InheritedB

System.out.println(val + " "+ B.this.val);

打印出 继承自 的值,后跟 “包含实例” 中的 值 。valBval

考虑将其重构为:

public class B
{
    String val = "old";
}

public class InheritedB extends B {
    B other;

    public InheritedB(B other)
    {
        this.other = other;
    }

    void printVal() {
        System.out.println(val + " "+ other.val);
    }
}

然后你基本上在运行:

B original = new B();
original.val = "new":
InheritedB inherited = new InheritedB(original);
inherited.printVal();

希望你能准确地了解那里发生了什么。编译器粗略地将原始代码执行到该代码中。


答案 2

valin 指的是 from 其基类 (),因为这是 的一部分。InheritedBvalsuper.valthis

如果不从外部类继承,则引用外部类 () 的作用域。但是,由于继承,因此范围更近,因此隐藏了外部范围。valB.this.scopethis

既然你从来不叫这个内在,所以还是.run()this.valold


如果我看一下构造函数,我还看到,如果创建了 InheritedB 的实例,则会创建一个新的 B 实例。

是的;创建派生类将始终创建其基类的实例。无法从现有实例继承。


推荐