USING JAVA.LANG.CLASS
These tips were developed using Java(tm) 2 SDK, Standard Edition,
v 1.2.2.
In object-oriented programming, a class is a user-defined type,
with a set of methods that operate on instances (objects) of the
class. For example, you might have a class Point in an application:
public class Point {
int x;
int y;
}
and the application operates on instances of Point, like (37,47)
and (153,89).
java.lang.Class is one of the standard classes in the Java
programming language, and instances of java.lang.Class represent
other classes and interfaces. This tip could use Class to refer
to java.lang.Class, but that terminology might be confusing.
So you'll see java.lang.Class throughout the discussion.
java.lang.Class gives you the ability to find out information
about classes that are currently loaded into the Java(tm) Virtual
Machine* (JVM). It also gives you a way to dynamically load
additional classes into your application. Here's an example,
it's a short application that uses java.lang.Class features:
public class ClassDemo1 {
public static void main(String args[]) {
Class cls = null;
// load a class by name (like java.util.ArrayList)
try {
cls = Class.forName(args[0]);
}
catch (ClassNotFoundException exc) {
System.err.println(exc);
}
// display the hierarchy back to java.lang.Object
do {
System.out.println(cls);
cls = cls.getSuperclass();
} while (cls != null);
}
}
This program uses Class.forName to load a class into the JVM; if the
class is already loaded, it finds the java.lang.Class instance that
represents the class. Then the program calls Class.getSuperclass
repeatedly to find the class's superclass. The result of this
process is the class hierarchy for a given class. For example, if
you invoke the program with an argument of "java.util.ArrayList",
the output is:
class java.util.ArrayList
class java.util.AbstractList
class java.util.AbstractCollection
class java.lang.Object
which is the class hierarchy of ArrayList up through
java.lang.Object. In other words, you can find out about the class
properties of ArrayList from within a running program.
java.lang.Class is a class whose instances represent other Java
classes and interfaces, such as ArrayList, String, and Cloneable.
java.lang.Class doesn't have a public constructor, so you can't say:
Class c = new Class(...);
Instead, you obtain java.lang.Class instance references using
Class.forName as illustrated above. Class.forName is used to load
a class at run time, based on a string containing the class name
(such as "java.util.ArrayList").
Another way you can obtain a java.lang.Class instance reference is
to use the ".class" notation, as in:
Class c = java.lang.String.class;
Because Java arrays fit into the class hierarchy rooted at
java.lang.Object, you can also say:
Class c = int[].class;
A final way to obtain a java.lang.Class reference is through an
object reference. In this case, you say:
Class c = obj.getClass();
or:
int vec[] = new int[10];
Class c = vec.getClass();
Once you have a java.lang.Class instance reference, you can create
new instances of the class that it represents. Here's an example:
public class ClassDemo2 {
public static void main(String args[]) {
Class cls = null;
Object obj = null;
// load a class by name
try {
cls = Class.forName(args[0]);
}
catch (ClassNotFoundException exc) {
System.err.println(exc);
}
// create a new instance of that class
try {
obj = cls.newInstance();
}
catch (IllegalAccessException exc1) {
System.err.println(exc1);
}
catch (InstantiationException exc2) {
System.err.println(exc2);
}
}
}
Class.newInstance is used to create new instances of the class
represented by the java.lang.Class instance. It assumes the
existence of a default (no parameter) constructor for the class.
You could ask why you can't simply use "new" to create a new
class instance, and not go to all the trouble of using
java.lang.Class and newInstance. The key point about the above
approach is that it's dynamic; you can load classes by name into
a program and create new instances of these classes.
If you load classes using a string name, like "pkg.classname", then
you might wonder how the loaded classes are manipulated. One way is
to program in terms of interfaces. Suppose that you have an
interface A, and two classes B and C that implement that interface.
Class B uses an implementation that is the most space efficient,
while class C uses more space but runs faster than B. You can
dynamically load B or C, but then program in terms of the
interface A. So the line above that reads:
obj = cls.newInstance();
might better read:
A aref = null;
... load B or C by name ...
aref = (A)cls.newIntance();
A complete example looks like this:
// file A.java
public interface A {
void f();
}
// file B.java
public class B implements A {
public void f() {
System.out.println("B.f");
}
}
// file C.java
public class C implements A {
public void f() {
System.out.println("C.f");
}
}
// file ClassDemo3.java
public class ClassDemo3 {
public static void main(String args[]) {
A aref = null;
Class cls = null;
// load a class (B or C)
try {
cls = Class.forName(args[0]);
}
catch (ClassNotFoundException exc) {
System.err.println(exc);
}
// create a new instance of that class
try {
aref = (A)cls.newInstance();
}
catch (IllegalAccessException exc1) {
System.err.println(exc1);
}
catch (InstantiationException exc2) {
System.err.println(exc2);
}
// call f() in the loaded class
aref.f();
}
}
If you say:
$ java ClassDemo3 C
then the output is:
C.f
that is, the f method in the loaded class C is called through
the interface reference.
In ClassDemo1 above, getSuperclass finds the superclass of
a class represented by a java.lang.Class instance. There are
other query methods that you can use with java.lang.Class. For
example, a common one is illustrated by this program:
public class ClassDemo4 {
public static void classify(Object obj) {
if (obj == null) {
System.out.println("null");
}
else if (obj.getClass().isArray()) {
System.out.println("array");
}
else {
System.out.println("non-array");
}
}
public static void main(String args[]) {
classify(null);
classify(new int[10]);
classify(new String());
}
}
In this example there's an object reference passed to the classify
method, and you'd like to know whether it represents an array.
A final area worth mentioning is reflection. The Java system
defines a separate package for reflection (java.lang.reflect), but
it relies on methods found in java.lang.Class. One way to
distinguish java.lang.reflect facilities from those in
java.lang.Class is to note that the java.lang.reflect operates
on individual fields and methods in a class instance.
java.lang.Class is concerned with a class as a whole unit.
For example, this program displays a list of all the public methods
found in String:
import java.lang.reflect.*;
public class ClassDemo5 {
public static void main(String args[]) {
Class cls = java.lang.String.class;
Method methlist[] = cls.getMethods();
for (int i = 0; i < methlist.length; i++)
System.out.println(methlist[i]);
}
}
java.lang.reflect.Method is a class found in the reflection package.
Class.getMethods gets a list of all the methods in the
class. You could go deeper into the internals of a method, for
example, you could obtain a list of all the method's parameters in
a form that could be manipulated within an application. To do that,
you would use facilities such as Method.getParameterTypes.
In other words, in this simple demo program, the names of all
methods and their parameters are displayed. However, to find out
which of the methods has a third parameter of type "int", use
reflection facilities within java.lang.reflect.Method.
java.lang.Class is a powerful mechanism for examining the properties
of classes, and for dynamically loading and manipulating those
classes.
|