Bruce Eckel’s Thinking in Java | Contents | Prev | Next |
performs its RTTI
using the
Class
object, even if you’re doing something like a cast. The class
Class
also has a number of other ways you can use RTTI.
you must get a handle to the appropriate
Class
object. One way to do this, as shown in the previous example, is to use a
string and the
Class.forName( )
method. This is convenient because you don’t need an object of that type
in order to get the
Class
handle. However, if you do already have an object of the type you’re
interested in, you can fetch the
Class
handle by calling a method that’s part of the
Object
root class:
getClass( ).
This returns the
Class
handle representing the actual type of the object.
Class
has several interesting and sometimes useful methods, demonstrated in the
following example:
//: ToyTest.java // Testing class Class interface HasBatteries {} interface Waterproof {} interface ShootsThings {} class Toy { // Comment out the following default // constructor to see // NoSuchMethodError from (*1*) Toy() {} Toy(int i) {} } class FancyToy extends Toy implements HasBatteries, Waterproof, ShootsThings { FancyToy() { super(1); } } public class ToyTest { public static void main(String[] args) { Class c = null; try { c = Class.forName("FancyToy"); } catch(ClassNotFoundException e) {} printInfo(c); Class[] faces = c.getInterfaces(); for(int i = 0; i < faces.length; i++) printInfo(faces[i]); Class cy = c.getSuperclass(); Object o = null; try { // Requires default constructor: o = cy.newInstance(); // (*1*) } catch(InstantiationException e) {} catch(IllegalAccessException e) {} printInfo(o.getClass()); } static void printInfo(Class cc) { System.out.println( "Class name: " + cc.getName() + " is interface? [" + cc.isInterface() + "]"); } } ///:~
can see that
class
FancyToy
is quite complicated, since it inherits from
Toy
and
implements
the
interfaces
of
HasBatteries,
Waterproof,
and
ShootsThings.
In
main( ),
a
Class
handle is created and initialized to the
FancyToy
Class
using
forName( )
inside an appropriate
try
block.
Class.getInterfaces( )
method
returns an array of
Class
objects representing the interfaces that are contained in the
Class
object of interest.
you have a
Class
object you can also ask it for its direct base class using getSuperclass( ).
This, of course, returns a
Class
handle that you can further query. This means that, at run time, you can
discover an object’s entire class hierarchy.
newInstance( )
method of
Class
can, at first, seem like just another way to
clone( )
an object. However, you can create a new object with
newInstance( )
without
an existing object, as seen here, because there is no
Toy
object, only
cy,
which is a handle to
y’s
Class
object. This is a way to implement a “virtual constructor,” which
allows you to say “I don’t know exactly what type you are, but
create yourself properly anyway.” In the example above,
cy
is just a
Class
handle with no further type information known at compile time. And when you
create a new instance, you get back an
Object
handle. But that handle is pointing to a
Toy
object. Of course, before you can send any messages other than those accepted by
Object,
you have to investigate it a bit and do some casting. In addition, the class
that’s being created with
newInstance( )
must have a default constructor. There’s no way to use
newInstance( )
to
create objects that have non-default constructors, so this can be a bit
limiting in Java 1. However, the
reflection
API in Java 1.1
(discussed in the next section) allows you to dynamically use any constructor
in a class.
final method in the listing is printInfo( ),
which takes a
Class
handle and gets its name with getName( ),
and finds out whether it’s an interface with isInterface( ).
output from this program is:
Class name: FancyToy is interface? [false] Class name: HasBatteries is interface? [true] Class name: Waterproof is interface? [true] Class name: ShootsThings is interface? [true] Class name: Toy is interface? [false]