[英]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.