向下转换图形实例 - 为什么允许它?

时间:2013-07-11 19:38:46

标签: java swing awt graphics2d downcast

我正在试图弄清楚为什么允许将Graphics实例向下转换为Graphics2D实例。

通常违反规则,转发不继承目标类型的引用类型

在面向图形的类中,层次结构如下所示:

  1. 图形是超类
  2. Graphics2D是超类Graphics
  3. 的子类

    在Swing中绘制内容时,您将覆盖paint()方法 - 如果您需要2D绘图,则将自动提供的Graphics实例从paint()方法向下转换为Graphics2D实例:

    public void paint(Graphics g)
    {
        super.paint(g);
    
        Graphics2D g2d = (Graphics2D)g;
    }
    

    但这是相反的吗? Graphics实例 NOT 继承了graphics2D实例 - 在查看类层次结构时, IS 继承Graphics实例的Graphics2D实例!

    为什么允许这样做?

7 个答案:

答案 0 :(得分:3)

如果你知道g在运行时确实是Graphics2D的一个实例,那是允许的。如果不是,您将在运行时获得ClassCastException

如果您检查Graphics的{​​{3}},则会注意到GraphicsGraphics2DDebugGraphics只有两个已知的子类。因此,除非自定义实现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的超级类。至于为什么这个演员是必要的,我不确定。这也困扰着我。

编辑:

Check this out:

在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