- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
基于此oracle doc example我尝试创建自己的示例来测试它。当然,按照建议引用了示例工作。但是当我尝试基于 Class.cast 方法时,我遇到了问题:
我的代码是
CL3 扩展 CL2 扩展 CL1 扩展 CL0 扩展 Base。
public class CL3 extends CL2 {
int x = 3;
public int getX() { return x; }
}
public class CL2 extends CL1 {
int x = 2;
public int getX() { return x; }
}
public class CL1 extends CL0 {
int x = 1;
public int getX() { return x; }
}
public class CL0 extends Base {
int x = 0;
public int getX() { return x; }
public String getPath() {
System.out.println("before obj : " + getClass().cast(this));
System.out.println("before class : " + getClass());
System.out.println("before x : " + getClass().cast(this).x);
System.out.println("before getX() : " + getClass().cast(this).getX());
System.out.println();
return getClazzPath(getClass());
}
}
public abstract class Base {
int x = -1;
abstract int getX();
@SuppressWarnings("unchecked")
public <T extends CL0> String getClazzPath(Class<T> clazz) {
System.out.println("clazz : " + clazz);
System.out.println("cast : " + clazz.cast(this));
System.out.println("cast.x : " + clazz.cast(this).x);
System.out.println("cast.getX() : " + clazz.cast(this).getX());
System.out.println("#");
return clazz.cast(this).x + (clazz == CL0.class ? "" : "/" + getClazzPath((Class<T>) clazz.getSuperclass()));
}
}
主要功能代码为:
public static void main(String[] args) {
CL3 cl3 = new CL3();
System.out.println("cl3.getX()=" + cl3.getX());
System.out.println("((CL2)cl3).getX()=" + ((CL2) cl3).getX());
System.out.println("((CL1)cl3).getX()=" + ((CL1) cl3).getX());
System.out.println("((CL0)cl3).getX()=" + ((CL0) cl3).getX());
System.out.println("((IdentyfiedScope)cl3).getX()=" + ((Base) cl3).getX());
System.out.println();
System.out.println("cl3.x=" + cl3.x);
System.out.println("((CL2)cl3).x=" + ((CL2) cl3).x);
System.out.println("((CL1)cl3).x=" + ((CL1) cl3).x);
System.out.println("((CL0)cl3).x=" + ((CL0) cl3).x);
System.out.println("((IdentyfiedScope)cl3).x=" + ((Base) cl3).x);
System.out.println();
System.out.println(cl3.getPath());
}
输出是:
cl3.getX()=3
((CL2)cl3).getX()=3
((CL1)cl3).getX()=3
((CL0)cl3).getX()=3
((IdentyfiedScope)cl3).getX()=3
cl3.x=3
((CL2)cl3).x=2
((CL1)cl3).x=1
((CL0)cl3).x=0
((IdentyfiedScope)cl3).x=-1
before obj : test.code.hierarchy.read.CL3@70dea4e
before class : class test.code.hierarchy.read.CL3
before x : 0
before getX() : 3
clazz : class test.code.hierarchy.read.CL3
cast : test.code.hierarchy.read.CL3@70dea4e
cast.x : 0
cast.getX() : 3
#
clazz : class test.code.hierarchy.read.CL2
cast : test.code.hierarchy.read.CL3@70dea4e
cast.x : 0
cast.getX() : 3
#
clazz : class test.code.hierarchy.read.CL1
cast : test.code.hierarchy.read.CL3@70dea4e
cast.x : 0
cast.getX() : 3
#
clazz : class test.code.hierarchy.read.CL0
cast : test.code.hierarchy.read.CL3@70dea4e
cast.x : 0
cast.getX() : 3
#
0/0/0/0
问题是 - 为什么当我们使用 Class.cast(由 getPath().getClazzPath() 调用)方法时,我们得到的结果与直接访问 x 字段时由强制转换运算符产生的结果不同?正如我们看到 getClazzPath 方法 ('clazz : ') 的输出返回正确的类型 CL3 -> CL2 -> CL1 -> CL0 但 x 始终引用 0。
我发现这与 getClazzPath 方法中的 T 类型有关 - 但我不知道如何正确解释它。
是否有任何专家可以解释为什么在我的情况下强制转换运算符和 Class.cast 之间的行为不同?
最佳答案
类型转换不会改变对象的类型。它仅更改对其引用的编译时类型,并在需要时进行有效性检查。
由于强制转换不会更改对象的类型,因此它永远不会更改调用可重写方法(如 getX()
)的结果。 ,它将始终调用最具体的方法。同样,将对象附加到 String
时,强制转换没有效果,因为结果将是调用可重写方法 toString()
.
当涉及到字段或private
时方法中,引用的编译时类型可能会影响访问哪个字段或方法,但是,由于有关类型的知识仅限于泛型方法的类型参数,因此您不能期望对类型产生影响只有调用者知道。
所以当你更换时
@SuppressWarnings("unchecked")
public <T extends CL0> String getClazzPath(Class<T> clazz) {
System.out.println("clazz : " + clazz);
System.out.println("cast : " + clazz.cast(this));
System.out.println("cast.x : " + clazz.cast(this).x);
System.out.println("cast.getX() : " + clazz.cast(this).getX());
System.out.println("#");
return clazz.cast(this).x + (clazz == CL0.class ? "" : "/" + getClazzPath((Class<T>) clazz.getSuperclass()));
}
与
@SuppressWarnings("unchecked")
public <T extends CL0> String getClazzPath(Class<T> clazz) {
System.out.println("clazz : " + clazz);
System.out.println("cast : " + (T)this);
System.out.println("cast.x : " + ((T)this).x);
System.out.println("cast.getX() : " + ((T)this).getX());
System.out.println("#");
return clazz.cast(this).x + (clazz == CL0.class ? "" : "/" + getClazzPath((Class<T>) clazz.getSuperclass()));
}
结果不会改变。与普通类型转换没有区别(T)…
和clazz.cast(…)
当clazz
是 Class<T>
,两者都具有更改对 T
的引用的编译时类型的效果。 1。
但是 T
是什么? ?该方法不知道,它只知道它可以分配给 CL0
,由于声明<T extends CL0>
,因此允许访问 CL0
的成员,包括字段 CL0.x
.
您可能会认为允许访问不可重写的成员(例如 CL0
的字段)是一个语言设计错误。通过类型 T
的引用,尽管T
可以是一个子类,声明自己的同名字段。事实上,对于private
成员,编译器在通过 T
类型的引用访问它们时会生成错误,即使 private
CL0
的成员可以访问。
进一步证明普通类型转换和 Clazz.cast
之间没有区别,你可以改变
System.out.println("cl3.getX()=" + cl3.getX());
System.out.println("((CL2)cl3).getX()=" + ((CL2) cl3).getX());
System.out.println("((CL1)cl3).getX()=" + ((CL1) cl3).getX());
System.out.println("((CL0)cl3).getX()=" + ((CL0) cl3).getX());
System.out.println("((IdentyfiedScope)cl3).getX()=" + ((Base) cl3).getX());
System.out.println();
System.out.println("cl3.x=" + cl3.x);
System.out.println("((CL2)cl3).x=" + ((CL2) cl3).x);
System.out.println("((CL1)cl3).x=" + ((CL1) cl3).x);
System.out.println("((CL0)cl3).x=" + ((CL0) cl3).x);
System.out.println("((IdentyfiedScope)cl3).x=" + ((Base) cl3).x);
你的main
方法
System.out.println("cl3.getX()=" + cl3.getX());
System.out.println("((CL2)cl3).getX()=" + CL2.class.cast(cl3).getX());
System.out.println("((CL1)cl3).getX()=" + CL1.class.cast(cl3).getX());
System.out.println("((CL0)cl3).getX()=" + CL0.class.cast(cl3).getX());
System.out.println("((IdentyfiedScope)cl3).getX()=" + Base.class.cast(cl3).getX());
System.out.println();
System.out.println("cl3.x=" + cl3.x);
System.out.println("((CL2)cl3).x=" + CL2.class.cast(cl3).x);
System.out.println("((CL1)cl3).x=" + CL1.class.cast(cl3).x);
System.out.println("((CL0)cl3).x=" + CL0.class.cast(cl3).x);
System.out.println("((IdentyfiedScope)cl3).x=" + Base.class.cast(cl3).x);
结果也是一样的。这些方法之间没有区别,重要的是在一个地方,您要转换为具体类型 CL3
, CL2
, CL1
, CL0
,或Base
,另一方面,您正在转换为类型参数 T
.
1 区别在于 Class.cast
将在运行时检查有效性,与未经检查的强制转换不同,但由于它们在本例中都是有效的,因此结果不会改变,我们可以关注对成员选择的影响。
关于Java 转换之谜 - Class.cast 与强制转换运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56059363/
Or 运算符 对两个表达式进行逻辑“或”运算。 result = expression1 Or expression2 参数 result 任意数值变量。 expression1 任意
Not 运算符 对表达式执行逻辑非运算。 result = Not expression 参数 result 任意数值变量。 expression 任意表达式。 说明 下表显示如何
Is 运算符 比较两个对象引用变量。 result = object1 Is object2 参数 result 任意数值变量。 object1 任意对象名。 object2 任意
\ 运算符 两个数相除并返回以整数形式表示的结果。 result = number1\number2 参数 result 任意数值变量。 number1 任意数值表达式。 numbe
And 运算符 对两个表达式进行逻辑“与”运算。 result = expression1 And expression2 参数 result 任意数值变量。 expression1
运算符(+) 计算两个数之和。 result = expression1 + expression2 参数 result 任意数值变量。 expression1 任意表达式。 exp
我对此感到困惑snippet : var n1 = 5-"4"; var n2 = 5+"4"; alert(n1); alert(n2); 我知道 n1 是 1。那是因为减号运算符会将字符串“4”转
我想我会得到 12,而不是 7。 w++,那么w就是4,也就是100,而w++, w 将是 8,1000;所以 w++|z++ 将是 100|1000 = 1100 将是 12。 我怎么了? int
Xor 运算符 对两个表达式进行逻辑“异或”运算。 result = expression1 Xor expression2 参数 result 任意数值变量。 expression1
Mod 运算符 两个数值相除并返回其余数。 result = number1 Mod number2 参数 result 任意数值变量。 number1 任意数值表达式。 numbe
Imp 运算符 对两个表达式进行逻辑蕴涵运算。 result = expression1 Imp expression2 参数 result 任意数值变量。 expression1 任
Eqv 运算符 执行两个表达式的逻辑等价运算。 result = expression1 Eqv expression2 参数 result 任意数值变量。 expression1 任
我有一个运算符重载的简单数学 vector 类。我想为我的运算符(operator)获取一些计时结果。我可以通过计时以下代码轻松计时我的 +=、-=、*= 和/=: Vector sum; for(s
我是用户定义比较运算符的新手。我正在读一本书,其中提到了以下示例: struct P { int x, y; bool operator、运算符<等),我们
在 SQL 的维基百科页面上,有一些关于 SQL 中 bool 逻辑的真值表。 [1] 维基百科页面似乎来源于 SQL:2003 标准。 等号运算符 (=) 的真值表与 SQL:2003 草案中的 I
我遇到了一个奇怪的 C++ 运算符。 http://www.terralib.org/html/v410/classoracle_1_1occi_1_1_number.html#a0f2780081f
我正在阅读关于 SO 和 answers 中的一个问题,它被提到为: If no unambiguous matching deallocation function can be found, pr
我偶然发现了这个解决方案,但我无法理解其中到底发生了什么。谁能解释一下! 据我了解,它试图通过计算一半的单元格然后将其加倍来计算 a*b 网格中的单元格数量。但是我无法理解递归调用。 请不要建议其他解
Go的基本类型 布尔类型bool 长度:1字节 取值:布尔类型的取值只能是true或者false,不能用数字来表示 整型 通用整型 int / uint(有符号 / 无符号,下面也类似) 长度:根据运
在本教程中,您将学习JavaScript中可用的不同运算符,以及在示例的帮助下如何使用它们。 什么是运算符? 在JavaScript中,运算符是一种特殊符号,用于对运算数(值和变量)执行操作。例如,
我是一名优秀的程序员,十分优秀!