我正在试图弄清楚为什么允许将Graphics实例向下转换为Graphics2D实例。
通常违反规则,转发不继承目标类型的引用类型 。
在面向图形的类中,层次结构如下所示:
在Swing中绘制内容时,您将覆盖paint()方法 - 如果您需要2D绘图,则将自动提供的Graphics实例从paint()方法向下转换为Graphics2D实例:
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
}
但这是相反的吗? Graphics实例 NOT 继承了graphics2D实例 - 在查看类层次结构时, IS 继承Graphics实例的Graphics2D实例!
为什么允许这样做?
答案 0 :(得分:3)
如果你知道g
在运行时确实是Graphics2D的一个实例,那是允许的。如果不是,您将在运行时获得ClassCastException
。
如果您检查Graphics
的{{3}},则会注意到Graphics
,Graphics2D
和DebugGraphics
只有两个已知的子类。因此,除非自定义实现Graphics
子类,否则您可以确定您正在处理Graphics2D
实例。
答案 1 :(得分:3)
Graphics2D
是一个继承自Graphics
的类 - 就像“人类”是一类“两足动物”一样,所有人类都是两足动物,但事实并非如此。所有的两足动物都是人类。
java.awt.Graphics
可以追溯到Java的早期阶段,并不是很复杂。创建了Waphen Swing和Java2D,Graphics2D
被创建为Graphics
的子类,以便旧代码可以工作 - 向后兼容性是Sun的宗教信仰(而不是坏事)。
JComponent
和其他Swing类继承自使用旧API的java.awt.Component
。为了方便人们从AWT迁移到Swing而不进行除超类之外的任何更改,Swing保留了采用Graphics
而不是Graphics2D
的签名。
有充分证据表明,在Swing中,传递给paint(Graphics)
的图形将始终为Graphics2D
,因此您不需要备用代码路径来处理它不是的情况。< / p>
答案 2 :(得分:1)
Graphics是Graphics2D的超级类。至于为什么这个演员是必要的,我不确定。这也困扰着我。
编辑:
在JDK 1.1之后引入了Graphics2D。我认为我们需要将Graphics
转发给Graphics2D
以保持与旧版程序的向后兼容性。
如果您想要访问更高级的功能,请转换为Graphics2D。这打破了最佳做法,但可能认为值得保持向后兼容性。
答案 3 :(得分:1)
传递给paint方法的对象是Graphics2D类型。作为程序员,您知道这一点,即使它在方法签名中并不明确(因为它通常不一定是真的)。因此,允许转换对象。
答案 4 :(得分:1)
你很困惑Graphics
是Graphics2D的超类。你可以向下转换,但是向下转换是危险的,可以更好地使用instanceof
来避免运行时异常ClassCastException
。
如果不是必要的覆盖paint
,也不要覆盖paintComponent
。
答案 5 :(得分:1)
有时,向下转换非常有用,因为数据来自可能无法知道其实际类型的代码。请考虑the Hibernate Interceptor interface
中的此示例public void onDelete(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
// do nothing
}
请注意,entity
的输入方式为Object
,即使它确实是更具体的类型。 Hibernate不可能对它所持有的实体类型进行编译时引用,但这仍然是一个有用的方法:
if (entity instanceof Auditable) {
Auditable data = (Auditable)entity; // downcast
logger.warn("{current user} is deleting " data.GetDescriptionForAudit());
}
在此示例中,强制转换是不可避免的 - 无法改进Hibernate API,Object
是可以使用的最佳类型。
对于swing的paint
方法,似乎方法签名应该使用Graphics2D
,否则您应该在Graphics
类上定义所需的方法。也许摇摆的设计者试图说“不依赖于Graphics2D
方法,除非你真的需要。”
回答问题
允许向下转换,因为有时程序员必须这样做。在Hibernate示例中,API既可以输入,也可以输入。在swing示例中,有人可能认为API存在缺陷。但在任何一种情况下,Java允许向下转换都很有用。
答案 6 :(得分:0)
实际上Graphics2D
是Graphics的子类。当我们传递一个图形实例作为参数说(Graphics g
)时,内部g
就像这样声明:g = new Graphics2D
。由于Graphics2D
是图形的子类。因此,g
现在是Graphics 2D
datatype of graphics.Therefore
的实例,我们可以将g
转发给graphics 2d
。