简体   繁体   English

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

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

So I was writing a paintComponent(Graphics g) method and I realized at the beginning that I am casting it to Graphics2D g2 = (Graphics2D) g;所以我正在编写一个paintComponent(Graphics g)方法,一开始我意识到我将它转换为Graphics2D g2 = (Graphics2D) g; . . I wrote this code a while ago and just realized I have no clue what this is.不久前我写了这段代码,刚刚意识到我不知道这是什么。 I googled a bit but object casting is a bit foreign to me.我用谷歌搜索了一下,但对象转换对我来说有点陌生。

One object reference can be typecast into another object reference.一个对象引用可以被类型转换为另一个对象引用。 This is called casting object.这称为铸造对象。

^^Word for word from my textbook by Y. Daniel Liang ^^ 逐字逐句来自 Y. Daniel Liang 的教科书

I don't understand why this works.我不明白为什么这有效。 Graphics and Graphics2D are two different objects how could they inherit instance variables and methods from each-other? GraphicsGraphics2D是两个不同的对象,它们如何相互继承实例变量和方法? Obviously I am aware of primitive casting ie widening and narrowing.显然我知道原始铸造即加宽和变窄。 That makes sense since they are just wrapper classes of Integer, Double, Byte etc...这是有道理的,因为它们只是 Integer、Double、Byte 等的包装类......

With casting no object conversion or transformation of any kind is happening.使用强制转换不会发生任何类型的对象转换或转换。 Just imagine you have the following class structure:想象一下你有以下类结构:

class Mammal { }
class Human extends Mammal { }
class Dog extends Mammal { }

Now when you create a new instance of Human with Human human = new Human();现在,当您使用Human human = new Human();创建一个新的 Human 实例时Human human = new Human(); that will also be a Mammal, right?那也会是哺乳动物,对吧? So you could write a method like:所以你可以写一个方法,如:

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

and invoke the method like:并调用如下方法:

doSomething(new Human());

So your method can take any type of Mammal as an input parameter and in your method you can check what kind of Mammal it really is.所以你的方法可以将任何类型的哺乳动物作为输入参数,在你的方法中你可以检查它到底是哪种哺乳动物。 So when you pass a new Human() as the input, the object's actual type will be Human.因此,当您将new Human()作为输入传递时,对象的实际类型将是 Human。 The reason because you can pass a Human to a method expecting a Mammal is because inheritance.之所以可以将 Human 传递给需要 Mammal 的方法是因为继承。 So what your method will know is that the input parameter is definitely a Mammal.所以你的方法会知道输入参数肯定是哺乳动物。 But it can be any kind of Mammal.但它可以是任何种类的哺乳动物。 If you want to know what the Object's actual type is you can use instanceof for example.如果你想知道对象的实际类型是什么,你可以使用instanceof例如。 And in this line:在这一行中:

Human human = (Human) mammal;

doesn't mean you are converting the mammal input parameter.并不意味着您正在转换哺乳动物输入参数。 It just means that from now on you want to use the input parameter as a Human.这只是意味着从现在开始您希望将输入参数用作人类。 And you can do that, because with the isntanceof you check that it's really a Human.你可以做到这一点,因为你可以检查它是否真的是一个人类。 You could also do something like this:你也可以做这样的事情:

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

Notice the type of teh input parameter.注意输入参数的类型。 Object is the base class of everything.对象是一切的基类。

So getting back to your scenario.所以回到你的场景。 You do that casting, because from the context of your application the input parameter will always be a Graphics2D, and that's why you can do that casting, and also to use the methods provided by Graphics2D.您执行该转换,因为从您的应用程序的上下文来看,输入参数将始终是 Graphics2D,这就是您可以执行该转换以及使用 Graphics2D 提供的方法的原因。

Both Graphics2D and Graphics are abstract classes, which means you can't have an instance of them, but you can have an object which extends one of them. Graphics2DGraphics都是抽象类,这意味着您不能拥有它们的实例,但您可以拥有扩展其中之一的对象。

Graphics2D extends Graphics , so every object that extends Graphics2D will extend Graphics as well, but it doesn't mean every object that extends Graphics can be cast to Graphics2D . 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");
    }
}

In the above example both g1 and g2 are Graphics , but only g2 is Graphics2D .在上面的例子中, g1g2都是Graphics ,但只有g2Graphics2D

paintComponent(g1); will throw java.lang.ClassCastException: ClassDebugGraphics cannot be cast to Graphics2D , while paintComponent(g2);会抛出java.lang.ClassCastException: ClassDebugGraphics cannot be cast to Graphics2D ,而paintComponent(g2); will print Successful casting .将打印Successful casting

You didn't mention what is sent to paintComponent() in your code, but it extends Graphics2D so you can cast it to it.您没有在代码中提到发送到paintComponent() ,但它扩展了Graphics2D因此您可以将其转换为它。

If you look here " https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html "如果你看这里“ https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html

In the top you will see java.lang.Object -> java.awt.Graphics -> java.awt.Graphics2D在顶部你会看到java.lang.Object -> java.awt.Graphics -> java.awt.Graphics2D

So what does it mean!?: java.lang.Object is the super class for booth Graphics and Graphics2D.那么它是什么意思!?:java.lang.Object 是展位 Graphics 和 Graphics2D 的超类。 Graphics is super class for Graphics2D. Graphics 是 Graphics2D 的超类。 So Graphics2D extends Graphics, therefore they are not so "different" objects.因此 Graphics2D 扩展了 Graphics,因此它们并不是那么“不同”的对象。

If you have a look at the Javadoc, you see, that java.awt.Graphics2D is a subclass of java.awt.Graphics .如果你有一个看的Javadoc,你看,那java.awt.Graphics2D是的一个子类java.awt.Graphics https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Graphics2D.html https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Graphics2D.html

In Java 11 the direct known subclasses of Graphics are DebugGraphics and Graphics2D , so when you have a Graphics g , it is most probably also a Graphics2D , since Graphics itself is an abstract class and thus, cannot be instantiated directly.在 Java 11 中, Graphics的直接已知子类是DebugGraphicsGraphics2D ,所以当你有一个Graphics g ,它很可能也是一个Graphics2D ,因为Graphics本身是一个抽象类,因此不能直接实例化。 So you can cast the object to the specific type.因此,您可以将对象强制转换为特定类型。 To be sure, you could do check first, like so.可以肯定的是,您可以先检查一下,就像这样。

if (g instanceof Graphics2D) {
    Graphics2D g2 = (Graphics2D) g;
    ...
}

The cast is probably done, in order for you to be able to access methods, defined in Graphics2D , but not in Graphics .转换可能已经完成,以便您能够访问在Graphics2D定义的方法,但不能在Graphics

Another look at the Javadoc will reveals, that Graphics2D also is an abstract class.再看一下 Javadoc 就会发现, Graphics2D也是一个抽象类。 So, what you can do, to see, what class you are really dealing with is, print out the class name like this:所以,你可以做的是,看看你真正处理的是什么类,像这样打印出类名:

System.out.println(g.getClass().getName());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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