[英]Why can I cast an object? Can it be done with other objects?
所以我正在编写一个paintComponent(Graphics g)
方法,一开始我意识到我将它转换为Graphics2D g2 = (Graphics2D) g;
. 不久前我写了这段代码,刚刚意识到我不知道这是什么。 我用谷歌搜索了一下,但对象转换对我来说有点陌生。
一个对象引用可以被类型转换为另一个对象引用。 这称为铸造对象。
^^ 逐字逐句来自 Y. Daniel Liang 的教科书
我不明白为什么这有效。 Graphics
和Graphics2D
是两个不同的对象,它们如何相互继承实例变量和方法? 显然我知道原始铸造即加宽和变窄。 这是有道理的,因为它们只是 Integer、Double、Byte 等的包装类......
使用强制转换不会发生任何类型的对象转换或转换。 想象一下你有以下类结构:
class Mammal { }
class Human extends Mammal { }
class Dog extends Mammal { }
现在,当您使用Human human = new Human();
创建一个新的 Human 实例时Human human = new Human();
那也会是哺乳动物,对吧? 所以你可以写一个方法,如:
public void doSoemthing(Mammal mammal) {
if (mammal instanceof Human) {
Human human = (Human) mammal;
human.doWork();
} else if (mammal instanceof Dog) {
Dog dog = (Dog) mammal;
dog.bark();
}
}
并调用如下方法:
doSomething(new Human());
所以你的方法可以将任何类型的哺乳动物作为输入参数,在你的方法中你可以检查它到底是哪种哺乳动物。 因此,当您将new Human()
作为输入传递时,对象的实际类型将是 Human。 之所以可以将 Human 传递给需要 Mammal 的方法是因为继承。 所以你的方法会知道输入参数肯定是哺乳动物。 但它可以是任何种类的哺乳动物。 如果你想知道对象的实际类型是什么,你可以使用instanceof
例如。 在这一行中:
Human human = (Human) mammal;
并不意味着您正在转换哺乳动物输入参数。 这只是意味着从现在开始您希望将输入参数用作人类。 你可以做到这一点,因为你可以检查它是否真的是一个人类。 你也可以做这样的事情:
public void doExample2(Object input) {
if (input instanceof Integer) {
System.out.println("I am a number");
} else if (input instanceof Graphics) {
System.out.println("I am a Graphics");
}
}
注意输入参数的类型。 对象是一切的基类。
所以回到你的场景。 您执行该转换,因为从您的应用程序的上下文来看,输入参数将始终是 Graphics2D,这就是您可以执行该转换以及使用 Graphics2D 提供的方法的原因。
Graphics2D
和Graphics
都是抽象类,这意味着您不能拥有它们的实例,但您可以拥有扩展其中之一的对象。
Graphics2D
扩展Graphics
,因此每个扩展Graphics2D
对象也将扩展Graphics
,但这并不意味着扩展Graphics
每个对象都可以转换为Graphics2D
。
abstract class Graphics {}
abstract class Graphics2D extends Graphics {}
class ClassGraphics extends Graphics {}
class ClassGraphics2D extends Graphics2D {}
class Main {
public static void main(String[] args) {
Graphics g1 = new ClassDebugGraphics();
Graphics g2 = new ClassDebugGraphics2D();
paintComponent(g1);
paintComponent(g2);
}
public static void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
System.out.print("Successful casting");
}
}
在上面的例子中, g1
和g2
都是Graphics
,但只有g2
是Graphics2D
。
paintComponent(g1);
会抛出java.lang.ClassCastException: ClassDebugGraphics cannot be cast to Graphics2D
,而paintComponent(g2);
将打印Successful casting
。
您没有在代码中提到发送到paintComponent()
,但它扩展了Graphics2D
因此您可以将其转换为它。
如果你看这里“ https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html ”
在顶部你会看到java.lang.Object -> java.awt.Graphics -> java.awt.Graphics2D
那么它是什么意思!?:java.lang.Object 是展位 Graphics 和 Graphics2D 的超类。 Graphics 是 Graphics2D 的超类。 因此 Graphics2D 扩展了 Graphics,因此它们并不是那么“不同”的对象。
如果你有一个看的Javadoc,你看,那java.awt.Graphics2D
是的一个子类java.awt.Graphics
。 https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Graphics2D.html
在 Java 11 中, Graphics
的直接已知子类是DebugGraphics
和Graphics2D
,所以当你有一个Graphics g
,它很可能也是一个Graphics2D
,因为Graphics
本身是一个抽象类,因此不能直接实例化。 因此,您可以将对象强制转换为特定类型。 可以肯定的是,您可以先检查一下,就像这样。
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g;
...
}
转换可能已经完成,以便您能够访问在Graphics2D
定义的方法,但不能在Graphics
。
再看一下 Javadoc 就会发现, Graphics2D
也是一个抽象类。 所以,你可以做的是,看看你真正处理的是什么类,像这样打印出类名:
System.out.println(g.getClass().getName());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.