Question about casts

J

J Leonard

Here is a question about the use of casts. It isn't so much about the
syntax of casts but about their "under the hood" meaning.

For example, when an applet needs to be re-displayed the JVM calls the
applet "paint" method and passes to it a graphics object. Standard
practice is to cast this Graphics object to type Graphics2D and use
it.

I'm trying to understand how this can work. My concept of what is
happening goes like this: the JVM instantiates a Graphics object and
associates it with the drawing surface, a Container or some such.

When the applet needs to be redrawn the JVM calls the applets paint
method and the Graphics object is passed by reference to the method.

I'm coming to Java from C. My understanding of casts is that they
cause the compiler to interpret an object differently. They don't
change the object. Casting a Graphics object to type Graphics2D also
doesn't instantiate a Graphics2D object. If the object created by the
JVM isn't actually a Graphics2D object I don't see how this could
work.

Perhaps JVM 1.2 and later actually instantiate Graphics2D objects in
this case but the argument passed to paint is still considered to be a
Graphics object by default, for some reason?

Thanks for your help,
J Leonard
 
S

Stefan Ram

J Leonard said:
practice is to cast this Graphics object to type Graphics2D and [...]
I'm trying to understand how this can work. My concept of what is [...]

If answering to this post, please do not quote all of it,
but only short part you directly refer to.

This explanation of casts begins with some words about reference
types and references. It ends with the explanation of »downcasts«,
such as a cast from »Graphics« to »Graphics2D« is. Best read all
of it in the given sequence.

Reference Types
===============

Supertypes
----------

A reference type »S« here is called a »supertype« of a type »U« (S>=U)
iff »U« directly or indirectly extends or implements »S« or is »S«.

Examples:
»java.lang.String« is a supertype of »java.lang.String«.
»java.lang.Object« is a supertype of »java.lang.String«.
»java.lang.String« is not a supertype of »java.lang.Object«.

Exercises:
Is »java.lang.Integer« a supertype of »java.lang.String«?
Is »java.lang.String« a supertype of »java.lang.Integer«?

Proper Subtypes
---------------

If »U« is not »S«, then »U« is called a »proper subtype« of »S« (U<S).

Examples:
java.lang.String is a proper subertype of java.lang.Object.
java.lang.Object is not a proper subtype of java.lang.Object.

Exercises:
Is java.lang.Integer a proper subtype of java.lang.String?
Is java.lang.String a proper subtype of java.lang.Integer?

Types of Expressions and Objects
--------------------------------

In Java, both expression (entities of the source-code model) and
objects (entities of the run-time model) have a type.

Types of expressions are known at compile time, while
types of objects are known only at run time in the general case.

Example:
In Java SE 1.6, the type of the expression »java.lang.System.in« is
java.io.InputStream, the type of the object »java.lang.System.in« is
java.io.BufferedInputStream.

Exercise:
What is the type of the expression »"alpha"«?
What is the type of the object »"alpha"«?
What is the type of the expression »java.lang.System.out«?
What is the type of the object »java.lang.System.out«?

References
==========

.-----------------------------------------------------.
| |
| Fundamental requirement for any reference |
| |
| B1 The type »R« of a reference expression must |
| be a supertype of the type »O« of the |
| object it refers to (R>=O) |
| |
'-----------------------------------------------------'

Example:
In Java SE 1.6, the expression »java.lang.System.in« has the
type »java.io.InputStream« and it references an object of the
type »java.io.BufferedInputStream«. And indeed, »java.io.InputStream«
is a supertype of the type »java.io.BufferedInputStream«.

Casts of References
===================

Let r be a reference-valued expression (syntactically, a
»UnaryExpressionNotPlusMinus«).

Let T be a reference type (syntactically, a »ReferenceType«).

Then

(T)r

is an expression, called a »cast expression« (»CastExpression«).

.-----------------------------------------------------.
| |
| Fundamental properties of the reference cast |
| |
| A1 The type of the expression »(T)r« is »T«. |
| |
| A2 If the value of »r« is null, the value of |
| »(T)r« also is null. |
| |
| A3 If »r« refers to an object, the expression |
| »(T)r« refers to the same object »o« as |
| the expression »r« refers to. |
| |
'-----------------------------------------------------'

Example:
»( java.lang.Object )"alpha"« is an expression of type
»java.lang.Object« referencing an object of type »java.lang.String.

Upcasts
=======

Let »R« be the type of the expression »r«. If »r« refers to an object,
Let »O« be the type of the object »r« refers to. (»O« is a class.)

If »T« is a supertype of »R« (T>=R) the cast is always allowed and
is called an »upcast«. (Proof: T>=R, and by B1, R>=O, thus, T>=O (B1)
is fulfilled; or r is null.)

Example:
»( java.lang.Object )"alpha"« is an upcast, because java.lang.Object >=
java.lang.String.

Downcasts
=========

Now, assume that »T« is a proper subtype of »R« (T<R): Because
a possible type of »O« is only known at run time, it can only be known
at runtime, whether B1 is fulfilled (T<R and R>=O does not imply T>=O.)
Such a cast is called a »downcast«.

The Java Machine will check at runtime whether a downcast fullfils B1,
but it does not check anything for an upcast, which always fullfils B1.

Example:
»( java.lang.String )( java.lang.Object )"alpha"« is a downcast,
because java.lang.String < java.lang.Object.

Exercises:
Assuming that »String« is a proper subtype of »Object« (String<Object),
which of the following expressions (one expression per line) are upcasts,
which are downcast, which will create an error during compilation and
which will create an exception during evaluation?
( Object )new String()
( String )new String()
( Object )new Object()
( String )new Object()
 
D

Daniel Pitts

J said:
Here is a question about the use of casts. It isn't so much about the
syntax of casts but about their "under the hood" meaning.

For example, when an applet needs to be re-displayed the JVM calls the
applet "paint" method and passes to it a graphics object. Standard
practice is to cast this Graphics object to type Graphics2D and use
it.

I'm trying to understand how this can work. My concept of what is
happening goes like this: the JVM instantiates a Graphics object and
associates it with the drawing surface, a Container or some such.
Actually, in this case the AWT Framework instantiates a Graphics2D
Object, but passes it in as a Graphics reference.
When the applet needs to be redrawn the JVM calls the applets paint
method and the Graphics object is passed by reference to the method.

I'm coming to Java from C. My understanding of casts is that they
cause the compiler to interpret an object differently. They don't
change the object. Casting a Graphics object to type Graphics2D also
doesn't instantiate a Graphics2D object. If the object created by the
JVM isn't actually a Graphics2D object I don't see how this could
work.
It wouldn't. It would throw a Cast Cast Exception.
Perhaps JVM 1.2 and later actually instantiate Graphics2D objects in
this case but the argument passed to paint is still considered to be a
Graphics object by default, for some reason?
The reason is for backward compatibility, Old implementations that used
Graphics objects don't have to know about the new Graphics2D.

Hope this helps,
Daniel.
 
M

Mark Space

J said:
Perhaps JVM 1.2 and later actually instantiate Graphics2D objects in
this case but the argument passed to paint is still considered to be a
Graphics object by default, for some reason?

Bingo.

It's a Graphics object for historical reasons (or may just a surfeit of
good design on Sun's part) but the docs say it's basically always a
Graphics2D object. That's what actually gets instantiated in the first
place, and that's why the cast always works.

I'd point you at the documentation (from Sun) that says "it's always a
Graphics2D object" but you can use Google as easily as I can. It's a
good habit to be into. Check the API docs, I think that's where it is at.
 
P

Peter Duniho

[...]
I'd point you at the documentation (from Sun) that says "it's always a
Graphics2D object" but you can use Google as easily as I can. It's a
good habit to be into. Check the API docs, I think that's where it is
at.

For what it's worth, I had a very similar question a month or so ago, I
had already Googled to try to find the answer, and I am in fact fairly
familiar with the Java API docs. I wasn't able to find the documentation
that assured me that the instance is always a Graphics2D object, though I
was assured by others that it is.

It's possible that it is in fact trivial to find the answer and I'm just a
dope for not being able to find it. But if someone does find the specific
link, it would be nice if they'd post it here. Us dopes need help too. :)

Pete
 
L

Lew

Peter said:
For what it's worth, I had a very similar question a month or so ago, I
had already Googled to try to find the answer, and I am in fact fairly
familiar with the Java API docs. I wasn't able to find the
documentation that assured me that the instance is always a Graphics2D
object, though I was assured by others that it is.

It's possible that it is in fact trivial to find the answer and I'm just
a dope for not being able to find it. But if someone does find the
specific link, it would be nice if they'd post it here. Us dopes need
help too. :)

About the Graphics Object

As you might have noticed, all the Swing component paint methods are
called with a single parameter, an object of type java.awt.Graphics.
... An interesting point about the object passed to this method is that
(as of 1.2) it's actually an instance of java.awt.Graphics2D, an
extension of Graphics that provides a richer drawing API. To take
advantage of this API, you need only cast the object to type Graphics2D.


That turned up in about five minutes of Googling for "sun.com Java Swing
Graphics object is always a Graphics2D".

The Javadocs for the Graphics2D class do say:
This is the fundamental class for rendering 2-dimensional shapes,
text and images on the Java(tm) platform.

Components are still rendered by calling their paint() method, which takes a Graphics object.

In the current version of the language, though, the object is really a Graphics2D object.

There is a lot of information googlable, I just picked the top couple of links
I found in researching for this post.
 
P

Peter Duniho

[...]
There is a lot of information googlable, I just picked the top couple of
links I found in researching for this post.

Well, I do appreciate you sharing those links. They are all useful and
informative.

However, I am having the same problem with these that I have had with
other issues (see the previous EDT thread). That is, none of these are
what I'd consider authoritative (except the Graphics2D class
documentation, which fails to discuss the parameter passed to the paint()
method so doesn't address this specific question at all), nor do they
clearly state that this is behavior that can be relied upon not to change.

I mean, it's a very reasonable assumption that it won't change -- lots of
things would break if it did -- but an authoritative source would state
clearly, as part of the API documentation, that you can always rely on
being able to cast the Graphics instance to a Graphics2D instance. In
other words, it'd say "it's always a Graphics2D object" just as Mark's
post promises the relevant reference does.

In other words, with respect to Mark's statement to "Check the API docs",
where should we check in the API docs to find the statement that with
respect to what's passed to a component's paint() method, "it's always a
Graphics2D object".

In the context of my request, please note that it's not that I didn't find
any information about using Graphics2D in a paint() method for a Swing
component. I did, and have in fact relied on that information repeatedly
over the past month or so. What I was unable to find is something in the
_API documentation_ itself that clearly states that this is something that
can be relied upon.

I found lots of evidence that I can rely upon it, but I never did find a
clear statement in the API documentation to that effect. Since neither of
the references you've offered that actually say one can expect a
Graphics2D instance are part of the API documentation, they don't serve as
an example of such a statement. Offering them rather than something that
actually addresses what I asked for only reinforces my suspicion that the
Java API documentation does not in fact state this clearly anywhere.

Pete
 
L

Lew

Peter said:
[...]
There is a lot of information googlable, I just picked the top couple
of links I found in researching for this post.

Well, I do appreciate you sharing those links. They are all useful and
informative.

However, I am having the same problem with these that I have had with
other issues (see the previous EDT thread). That is, none of these are
what I'd consider authoritative (except the Graphics2D class
documentation, which fails to discuss the parameter passed to the
paint() method so doesn't address this specific question at all), nor do
they clearly state that this is behavior that can be relied upon not to
change.

The one from sun.com can safely be considered authoritative. After all, it is
part of their official documentation, under the heading "Reference".

You are right that they do not guarantee to keep it that way, but they haven't
changed it in the last ten years - it's been since version 1.2. Given the
care they took not to invalidate the original guarantee that those parameters
would be of type 'Graphic' I think we're safe. For a little while, at least.

With the Java 2 platform, you can do this by casting the Graphics class that is
passed in to your custom component's paint methods to a java.awt.Graphics2D object,
using it to render the appropriate shapes:

public paint(Graphics g) {

Graphics2D g2 = (Graphics2D)g;

To ensure backward compatibility, the functionality of existing JDK graphics and
imaging classes and interfaces was maintained. Existing features were not removed
and no package designations were changed for existing classes. The Java 2D API
enhances the functionality of the AWT by implementing new methods in existing
classes, extending existing classes, and adding new classes and interfaces that
don’t affect the legacy APIs. ....
To gain access to the new features implemented in Graphics2D, a Java 2D API–compatible applet
casts the graphics context to a Graphics2D object:

public void Paint (Graphics g) {

Graphics2D g2 = (Graphics2D) g;
...
...
g2.setTransform (t);
}

Boy, Sun just keeps repeating that information over and over in different
articles. They must really mean it. That one that says "spec" looks pretty
official, too, except for the misspelling of 'Paint'. I found it by a link on
Sun's Java 2D FAQ page.

What the heck, let's look for a tutorial:
To use Java 2D API features, you cast the Graphics object passed into a
component’s rendering method to a Graphics2D object. For example:

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

I admit, it took me about twenty minutes to find these references.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top