如果一个抽象class不能被实例化,为什么下面的可能呢?
If an abstract class can't be instantiated, why is the following possible?
在下面的代码中,一个 Graphics 对象被传递到下面的 paintComponent 方法中,然后它被转换成一个 Graphics2D 对象。 Graphics 不是抽象的 class 那为什么下面的可能呢?
public void paintComponent(Graphics comp) {
Graphics2D comp2D = (Graphics2D) comp;
Font font = new Font("Comic Sans", Font.BOLD, 15);
comp2D.setFont(font);
comp2D.drawString("Potrzebie!", 5, 50);
}
A class 是抽象的只是意味着你不能直接创建这样的 class。一旦你有了这样一个 class,你就可以转换它使它看起来像它的任何子classes。换句话说,所有"abstract"意味着你不能做:
SomeAbstractClass obj = new SomeAbstractClass(...);
您可以引用 Graphics2D
对象,就像在您的示例中一样,但是如果您要求 Java 告诉您对象的真实类型,它实际上永远不会是 Graphics2D
对象。从这段代码中,您也不能确定所讨论对象的真实类型是 Graphics
对象。这可能又是对真实对象的子 class 的引用,例如 MyGraphicsObject
或类似的东西。
这就是多态性的全部意义和威力。一旦你创建了一个对象,它的行为就像它的任何子classes 一样,并且可以通过向上转换将它视为任何这些子classes 的纯实例。
这里有一些代码指出了向上转型的对象的标识会发生什么:
abstract class Abstract {
public void whatAmI() {
System.out.println("I'm Abstract");
}
}
class Concrete extends Abstract {
@Override
public void whatAmI() {
System.out.println("I'm Concrete");
}
}
public class X {
public static void main(String[] args) {
// This won't compile. That's what it means for "Abstract" to be abstract.
// Abstract abs = new Abstract();
// You can create a Concrete, and then upcast it to an Abstract reference...
Concrete concrete = new Concrete();
Abstract abs = (Abstract)concrete;
// But it's stll really a Concrete
System.out.println(abs.getClass().getName());
// And it will still act like a Concrete if Concrete has overridden one of Abstract's methods.
abs.whatAmI();
}
}
结果:
org.littleshoot.proxy.inlet.Concrete
I'm Concrete
请注意,如果您询问 Java 对象的类型,即使您已通过抽象引用询问对象的类型,它仍然是具体的。另请注意,如果您在抽象 class 上调用已在混凝土中覆盖的方法,则将调用混凝土的版本。
仅仅因为 class 无法实例化并不意味着您无法获得它的实例。
在您的示例中,您所做的只是将其转换为图形层次结构中的另一个 class。
这是一个例子。
public class AbstractDemo {
public static void main(String[] args) {
Concrete c = new Concrete();
AClass a = (AClass) c;
a.me();
}
}
abstract class AClass {
public void me() {
System.out.println("Abstract parent");
}
}
class Concrete extends AClass {
}
在下面的代码中,一个 Graphics 对象被传递到下面的 paintComponent 方法中,然后它被转换成一个 Graphics2D 对象。 Graphics 不是抽象的 class 那为什么下面的可能呢?
public void paintComponent(Graphics comp) {
Graphics2D comp2D = (Graphics2D) comp;
Font font = new Font("Comic Sans", Font.BOLD, 15);
comp2D.setFont(font);
comp2D.drawString("Potrzebie!", 5, 50);
}
A class 是抽象的只是意味着你不能直接创建这样的 class。一旦你有了这样一个 class,你就可以转换它使它看起来像它的任何子classes。换句话说,所有"abstract"意味着你不能做:
SomeAbstractClass obj = new SomeAbstractClass(...);
您可以引用 Graphics2D
对象,就像在您的示例中一样,但是如果您要求 Java 告诉您对象的真实类型,它实际上永远不会是 Graphics2D
对象。从这段代码中,您也不能确定所讨论对象的真实类型是 Graphics
对象。这可能又是对真实对象的子 class 的引用,例如 MyGraphicsObject
或类似的东西。
这就是多态性的全部意义和威力。一旦你创建了一个对象,它的行为就像它的任何子classes 一样,并且可以通过向上转换将它视为任何这些子classes 的纯实例。
这里有一些代码指出了向上转型的对象的标识会发生什么:
abstract class Abstract {
public void whatAmI() {
System.out.println("I'm Abstract");
}
}
class Concrete extends Abstract {
@Override
public void whatAmI() {
System.out.println("I'm Concrete");
}
}
public class X {
public static void main(String[] args) {
// This won't compile. That's what it means for "Abstract" to be abstract.
// Abstract abs = new Abstract();
// You can create a Concrete, and then upcast it to an Abstract reference...
Concrete concrete = new Concrete();
Abstract abs = (Abstract)concrete;
// But it's stll really a Concrete
System.out.println(abs.getClass().getName());
// And it will still act like a Concrete if Concrete has overridden one of Abstract's methods.
abs.whatAmI();
}
}
结果:
org.littleshoot.proxy.inlet.Concrete
I'm Concrete
请注意,如果您询问 Java 对象的类型,即使您已通过抽象引用询问对象的类型,它仍然是具体的。另请注意,如果您在抽象 class 上调用已在混凝土中覆盖的方法,则将调用混凝土的版本。
仅仅因为 class 无法实例化并不意味着您无法获得它的实例。
在您的示例中,您所做的只是将其转换为图形层次结构中的另一个 class。
这是一个例子。
public class AbstractDemo {
public static void main(String[] args) {
Concrete c = new Concrete();
AClass a = (AClass) c;
a.me();
}
}
abstract class AClass {
public void me() {
System.out.println("Abstract parent");
}
}
class Concrete extends AClass {
}