簡體   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