繁体   English   中英

为什么我可以投射一个对象? 可以用其他对象完成吗?

[英]Why can I cast an object? Can it be done with other objects?

所以我正在编写一个paintComponent(Graphics g)方法,一开始我意识到我将它转换为Graphics2D g2 = (Graphics2D) g; . 不久前我写了这段代码,刚刚意识到我不知道这是什么。 我用谷歌搜索了一下,但对象转换对我来说有点陌生。

一个对象引用可以被类型转换为另一个对象引用。 这称为铸造对象。

^^ 逐字逐句来自 Y. Daniel Liang 的教科书

我不明白为什么这有效。 GraphicsGraphics2D是两个不同的对象,它们如何相互继承实例变量和方法? 显然我知道原始铸造即加宽和变窄。 这是有道理的,因为它们只是 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 提供的方法的原因。

Graphics2DGraphics都是抽象类,这意味着您不能拥有它们的实例,但您可以拥有扩展其中之一的对象。

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");
    }
}

在上面的例子中, g1g2都是Graphics ,但只有g2Graphics2D

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的直接已知子类是DebugGraphicsGraphics2D ,所以当你有一个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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM