4

I'm trying to figure out why it is allowed to downcast a Graphics instance to a Graphics2D instance.

It's usually against the rules to downcast a reference type that isn't inheriting the target type.

In the graphic-oriented classes the hierarchy is like the following:

  1. Graphics is the superclass
  2. Graphics2D is the subclass of the superclass Graphics

When drawing something in Swing you override the paint() method - And if you're in need of 2D-drawing you downcast the automatically supplied Graphics instance from the paint() method to a Graphics2D instance:

public void paint(Graphics g)
{
    super.paint(g);

    Graphics2D g2d = (Graphics2D)g;
}

But this is reverse? A Graphics instance is NOT inheriting a graphics2D instance - It's the Graphics2D instance that IS inheriting a Graphics instance when looking at the class-hierarchy!

Why is this allowed?

4

7 回答 7

3

It's allowed if you know that g will indeed be an instance of Graphics2D at runtime. If it is not, you will get a ClassCastException at runtime.

If you check the documentation for Graphics, you will note that there are only two known subclasses of Graphics, Graphics2D and DebugGraphics. So, barring a custom implementation of a Graphics subclass, you can be fairly certain you're dealing with a Graphics2D instance.

于 2013-07-11T19:41:59.960 回答
3

Graphics2D is a class which inherits from Graphics - the same way that "human" is a class of "biped", and it is true that all humans are bipeds but it is not true that all bipeds are humans.

java.awt.Graphics dates to the earliest days of Java and was not very sophisticated. Waphen Swing and Java2D were created, Graphics2D was created as a subclass of Graphics so that old code would work - backwards compatibility was a religion at Sun (and not a bad one).

JComponent and other Swing classes inherit from java.awt.Component, which used the old API. To make it easy for people to migrate from AWT to Swing without making any changes except the superclass, Swing kept the signature of taking a Graphics rather than a Graphics2D.

It is well documented that in Swing, the Graphics passed to paint(Graphics) will always be a Graphics2D, so you do not need an alternate code-path to handle the case that it is not.

于 2013-07-12T00:56:18.340 回答
1

Graphics is a super class of Graphics2D. As for why this cast is necessary, I am not sure. Its something that bothers me too.

Edit:

Check this out:

Graphics2D was introduced after JDK 1.1. I think we need to downcast Graphics to Graphics2D to maintain backwards compatibility with legacy programs.

If you want access to the more advanced functions you cast to Graphics2D. This breaks best practices but was probably deemed worth it to maintain backwards compatibility.

于 2013-07-11T19:40:39.083 回答
1

The object that is passed to the paint method is of the type Graphics2D. You, as a programmer, know this, even though it is not explicit in the method signature (because it need not be true in general). So, it is allowed to cast the object.

于 2013-07-11T19:43:12.267 回答
1

You are confused Graphics is the super class from Graphics2D . You can downcast, but downcasting is dangereous better use instanceof to avoid runtime exception ClassCastException.

Also don't override paint if is not necesary override paintComponent instead.

于 2013-07-11T19:54:07.730 回答
1

Sometimes downcasting is useful because data is coming from code that cannot possibly know its actual type. Consider this example from the Hibernate Interceptor interface

public void onDelete(Object entity,
                     Serializable id,
                     Object[] state,
                     String[] propertyNames,
                     Type[] types) {
    // do nothing
}

Note that entity is typed as Object even though it is surely a more specific type. Hibernate cannot possibly have a compile-time reference to the types of the entities it is persisting, but this can still be a useful method:

if (entity instanceof Auditable) {
    Auditable data = (Auditable)entity; // downcast
    logger.warn("{current user} is deleting " data.GetDescriptionForAudit());
}

In this example, a cast is unavoidable - the Hibernate API can't be improved, Object is the best type that can be used.

In the case of swing's paint method, it seems that the method signature should have used Graphics2D, or else the methods that you need should have been defined on the Graphics class. Perhaps the designers of swing are trying to say "don't depend on the Graphics2D methods unless you really need to."

To answer the question

Downcasting is allowed because sometimes the programmer has to do it. In the Hibernate example, the API is typed as well as it can be. In the swing example, one might argue that the API has a flaw. But in either case, it is useful that Java allows downcasting.

于 2013-07-11T20:39:05.017 回答
0

Actually Graphics2D is subclass of Graphics. When we pass an instance of graphics as an argument say(Graphics g) then internally g is declared like this: g = new Graphics2D. Since Graphics2D is subclass of graphics. Therefore g is now an instance of Graphics 2D with datatype of graphics.Therefore we can downcast g to graphics 2d.

于 2014-03-29T12:32:00.807 回答