转换为 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);
a
是C
的super-class中的那个,也就是B
→ 一=80
System.out.println(((A) this).a);
首先,将 C
实例 (this
) 转换为 A
,然后调用 a
是 A
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
,因为 B
是 C
的超级 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.a
、obj.getA()
或 someMethod(obj)
的东西,Java 必须根据类型以某种方式找到要使用的实际字段或方法或 obj
中的 class。涉及两种不同的调度机制(加上特殊构造 super
)。
Dynamic dispatch (polymorphism, overriding): 在对象上调用实例方法时使用,如obj.getA()
。然后检查 obj
的运行时 class,如果这个 class 包含一个 getA()
方法,则使用它。否则,将检查直接父 class 是否有 getA()
方法,依此类推直到 Object
class.
静态调度:在 obj.a
或 someMethod(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 的对象上调用的,例如D
和 D
有自己的 getA()
方法,将使用该方法。
super.getA()
是 super
-dispatch 的一种情况,它将调用 class 层次结构中更高层的 getA()
方法当前 class,例如B
.
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 = 0System.out.println(super.a);
a
是C
的super-class中的那个,也就是B
→ 一=80System.out.println(((A) this).a);
首先,将C
实例 (this
) 转换为A
,然后调用a
是A
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
,因为B
是C
的超级 class。 - 它的类型为
A
因为它也间接扩展了 classA
。
在您问题的代码上下文中,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.a
、obj.getA()
或 someMethod(obj)
的东西,Java 必须根据类型以某种方式找到要使用的实际字段或方法或 obj
中的 class。涉及两种不同的调度机制(加上特殊构造 super
)。
Dynamic dispatch (polymorphism, overriding): 在对象上调用实例方法时使用,如
obj.getA()
。然后检查obj
的运行时 class,如果这个 class 包含一个getA()
方法,则使用它。否则,将检查直接父 class 是否有getA()
方法,依此类推直到Object
class.静态调度:在
obj.a
或someMethod(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。在您的情况下,它是 classC
,因此使用 classC
中的字段a
,即 10.super.a
是一个super
-dispatch 表达式,意味着 classC
中的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 的对象上调用的,例如D
和D
有自己的getA()
方法,将使用该方法。super.getA()
是super
-dispatch 的一种情况,它将调用 class 层次结构中更高层的getA()
方法当前 class,例如B
.