转换为 Java - (Parent) 这是什么意思?

Casting in Java - what does (Parent) this mean?

class A {
    public int a = 100;
} 

class B extends A {
    public int a = 80;
} 

class C extends B {
    public int a = 10;

    public void show() {
        int a = 0;

        System.out.println(a);
        System.out.println(super.a);
        System.out.println(((A) this).a);
    }
}

System.out.println(((A) this).a); 中的 ((A) this).a 有什么作用? 是 upcasting/downcasting this 还是这里发生了其他事情?

我也尝试了 System.out.println(this);System.out.println((A)this);,它们都有相同的输出。这里到底发生了什么?

  • System.out.println(a);
    a 是来自 C class 的 show 方法的那个 → a = 0

  • System.out.println(super.a);
    aC的super-class中的那个,也就是B一=80

  • System.out.println(((A) this).a);
    首先,将 C 实例 (this) 转换为 A,然后调用 aA class 的成员 → a = 100

还有一些事情需要考虑:方法将始终采用更专业的方法(除非使用 super),其中字段将直接从引用的类型中获取(即使有扩展 class ).

例如,如果我在每个 classes 中添加 getA() :

class A {
    public int a = 100;

    public int getA(){
        return a;
    }
}

class B extends A {
    public int a = 80;

    public int getA(){
        return a;
    }
}

class C extends B {
    public int a = 10;


    public int getA(){
        return a;
    }
    public void show() {
        int a = 0;

        System.out.println(a);
        System.out.println(super.a);
        System.out.println(((A) this).a);
        System.out.println(getA());
        System.out.println(super.getA());
        System.out.println(((A) this).getA());
    }
}


class Scratch {

    public static void main(String[] args) {
        new C().show();
    }
}

我得到以下输出:

0
80
100
10
80
10

这意味着在方法的情况下,除了 super.getA() 明确转到超级 class 的情况外,将 C 转换为 A 对方法来说变化不大,因为它会影响领域。

在 java 编程语言中,我们有 classes。当我们编写 java 代码时,我们创建了那些 classes 的实例,例如:

Object o = new Object();

Object 是一个 class。写入 new Object() 会创建 class 的一个实例。上面的代码声明了一个变量 o 并将其 [引用] 分配给 class Object.

的一个实例

在java编程语言的术语中,我们说变量o具有类型Object.

在你问题的代码中,分配了 class C 实例的变量实际上具有三种类型。

  • 其类型为 C
  • 它的类型为 B,因为 BC 的超级 class。
  • 它的类型为 A 因为它也间接扩展了 class A

在您问题的代码上下文中,this 是一个类型为 C 的特殊变量。写作 (A) this 告诉 java 与变量 this 相关,就好像它的类型是 A.

Class A 无法访问其子classes。因此它只知道它的 class 成员 a。因此,当您编写这行代码时...

((A) this).a

您正在访问 class A 的成员。

System.out.println(this);

System.out.println((A)this)

这两个使用 toString() 方法打印对 class C 的对象引用。

System.out.println(((A)this).a);

这是向上转型,子对象到父对象。

如果你写类似 obj.aobj.getA()someMethod(obj) 的东西,Java 必须根据类型以某种方式找到要使用的实际字段或方法或 obj 中的 class。涉及两种不同的调度机制(加上特殊构造 super)。

  • Dynamic dispatch (polymorphism, overriding): 在对象上调用实例方法时使用,如obj.getA()。然后检查 obj 的运行时 class,如果这个 class 包含一个 getA() 方法,则使用它。否则,将检查直接父 class 是否有 getA() 方法,依此类推直到 Object class.

  • 静态调度:在 obj.asomeMethod(obj) 的情况下,obj 的运行时间 class 无关紧要。只涉及编译器,根据他对 obj 类型的了解,他决定使用哪个字段或方法。

  • super dispatch:如果你写 super.getA()super.a,你的 getA() 方法或 a 字段将被忽略,并且相反,使用层次结构中的 next-higher class 包含此类方法或字段。

在您的例子中,您有 3 个字段和一个局部变量,它们都具有相同的名称 a。 (顺便说一句,在专业代码中出现这样的名称冲突是一个非常糟糕的主意。)我们在 C class 中声明的方法 show() 中。让我们来看看一些不同的表达方式及其含义:

  • a引用局部变量a。不需要调度,只是局部定义优先于字段。

  • this.a 是一个 static-dispatch 表达式,因此编译器对 this 类型的看法很重要。这始终是编写此代码的 class。在您的情况下,它是 class C,因此使用 class C 中的字段 a,即 10.

  • super.a 是一个 super-dispatch 表达式,意味着 class C 中的 a 字段被忽略并且下一个更高的(在我们的例子中来自 B)。

  • ((A) this).a 是静态调度,但是 (A) 转换有显着效果。点之前的表达式最初来自 this,属于 C 类型,但 (A) 强制转换告诉编译器相信它属于 A 类型。这没关系,因为每个 C 通过继承也是一个 A。但是现在,static dispatch 在点前面看到类型 A 的东西,并从 A class 调度到 a 字段,而不是从 [=30] =].

  • getA()this.getA()((A) this).getA()都是dynamic-dispatch的例子,都给出了相同的结果。调用的方法将是基于此对象的运行时 class 的方法。这通常是 C class 中定义的一个。但是,如果 show() 是在 C 的子 class 的对象上调用的,例如DD 有自己的 getA() 方法,将使用该方法。

  • super.getA()super-dispatch 的一种情况,它将调用 class 层次结构中更高层的 getA() 方法当前 class,例如B.