gpt4 book ai didi

Java 转换之谜 - Class.cast 与强制转换运算符

转载 作者:行者123 更新时间:2023-12-02 01:31:02 25 4
gpt4 key购买 nike

基于此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(…)clazzClass<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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com