前两天在编东西的时候遇到了这样一个问题,我在JFrame上放了一个JSplitPane,左右分开的,我想在左边放一个JTree,右边则放一个JPanel。我想达到这样一个效果,首先定义一些个JPanel,当点击树时我要得到被点击的结点的名称,然后根据这个名称去实例化与它名称相同的面板放在JSplitPane的右边。这样,在监听器里只写一个实例化面板的代码就行了,可是我得到的是一个String,这可犯难了,不可能用new关键字去直接实例化。经过在CSDN上的讨教,我终于还是用到了Java的反射。
其实这里需要用到Java里非常重要的一个概念——RTTI(Run-Time
Type
Identification,即运行时类型信息)。Java在运行时识别对象和类型的信息主要有两种方式:一种是“传统的”RTTI,它假定我们在编译时已经知道了所有的类型;另一种是“反射”机制,他允许我们在运行时发现和使用类的信息,RTTI的含义就是在运行时识别一个对象的类型。
首先是Class对象,它用来创建类的所有的“常规”的对象。Bruce
Eckel的《Thinking In
Java》中介绍说:“每当编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用被称为‘类加载器’的字系统。”类加载器字系统实际上可以包含一条类加载器链,但是只有一个原生类加载器,它是JVM实现的一部分。所有的类都是在对其第一次使用时,动态加载到JVM中的。Java程序在它开始运行之前并非被完全加载,其各个部分是在必需时才加载的。列加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件。一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
我们比较感兴趣的是这样一个方法:
Class.forName(String str)
这个方法是Class类的一个static成员。forName()是取得Class对象的引用的一种方法,它返回的是一个表示该对象的实际类型的Class引用,也就是一个这个引用的Class类型的对象。
Class的newInstance()方法是实现“虚拟构造器”的一种途径,Bruce说:“虚拟构造器允许你声明:我不知道你的确切类型,但是无论如何要正确的创建你自己。”如果使用newInstance()来创建的类必须带有默认的构造器。那么,如果构造器带参,我们又该怎么办呢?
不要怀疑大师们的努力,问题总是要解决的。
如果所要创建的类有无参构造器,那么我们可以直接应用:
Object obj =
Class.forName(包名+类名).newInstance();
注意,这个返回的是一个Class类型的对象,我们用Object类型的对象来接收,之后把它强制转换成要实例化的对象就可以了。
如果所要创建的类含有带参的构造器,那么我们应该这样来做:假设参数是两个String型的,那么
Class[] params = new
Class[]{String.class,String.class};
Object[]
newparams = new Object[]{"test","test"};
Class.forName(包名+类名).getConstructor(params).newInstance(Newparams);
这样我们就可以创建要使用的类了,用一个Object类型的对象来接收,之后再强制转换成要使用的类,就可以了。Class.forName()生成的结果在编译时是不可知的,反射机制的价值是很惊人的,但Bruce却说了,反射机制并没有什么神奇之处。当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类(就像RTTI那样)。RTTI与反射之间真正的区别只在于,对RTTI来说,编译器在编译时打开和检查.class文件;而对于反射机制来说,.class文件在编译时是不可获得的,所有是在运行时打开和检查.class。
一下是一些在网上的摘录,一些很不错的东东!!
检测类
1.Retrieving Class Objects
获取一个Class对象(metadata)
a,从对象的实例获取。
Class c = mystery.getClass();//(return Class)
b,从子类的实例获取
TextField t = new TextField();
Class c = t.getClass();
Class s = c.getSuperclass();
c,知道类名,则可以把.class加入到名字之后来获取。
Class c = java.awt.Button.class;
d,如果类名在编译时是未知的,则可以使用Class.forName()方法来获取.
Class c = Class.forName(classString);
2.Getting the Class Name
获取类名称
c.getName();
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleName {
public
static void main(String[] args) {
Button b = new Button();
printName(b);
}
static void
printName(Object o) {
Class c = o.getClass();
String s = c.getName();
System.out.println(s);
}
}
3.Discovering Class Modifiers
检索修改符
a.通过getModifiers()方法获取一个整型标识值。
b.通过java.reflect.Modifier对象的isPublic, isAbstract, 和
isFinal方法判断此值.
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleModifier {
public
static void main(String[] args) {
String s = new String();
printModifiers(s);
}
public
static void printModifiers(Object o) {
Class c = o.getClass();
int m = c.getModifiers();
if (Modifier.isPublic(m))
System.out.println("public");
if (Modifier.isAbstract(m))
System.out.println("abstract");
if (Modifier.isFinal(m))
System.out.println("final");
}
}
4.Finding Superclasses
检索父类
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleSuper {
public
static void main(String[] args) {
Button b = new Button();
printSuperclasses(b);
}
static void
printSuperclasses(Object o) {
Class subclass = o.getClass();
Class superclass = subclass.getSuperclass();
while (superclass != null) {
String className = superclass.getName();
System.out.println(className);
subclass = superclass;
superclass = subclass.getSuperclass();
}
}
}
5.Identifying the Interfaces
Implemented by a Class
检索指定类实现的接口
例如:
import java.lang.reflect.*;
import java.io.*;
class SampleInterface {
public
static void main(String[] args) {
try {
RandomAccessFile r = new RandomAccessFile("myfile", "r");
printInterfaceNames(r);
} catch (IOException e) {
System.out.println(e);
}
}
static void
printInterfaceNames(Object o) {
Class c = o.getClass();
Class[] theInterfaces = c.getInterfaces();
for (int i = 0; i < theInterfaces.length; i++)
{
String interfaceName = theInterfaces[i].getName();
System.out.println(interfaceName);
}
}
}
6.Examining Interfaces
判定一个类是不是接口
import java.lang.reflect.*;
import java.util.*;
class SampleCheckInterface {
public
static void main(String[] args) {
Class thread = Thread.class;
Class runnable = Runnable.class;
verifyInterface(thread);
verifyInterface(runnable);
}
static void
verifyInterface(Class c) {
String name = c.getName();
if (c.isInterface()) {
System.out.println(name + " is an interface.");
} else {
System.out.println(name + " is a class.");
}
}
}
如:c.isInterface()
7.Identifying Class Fields
找出指定类所有的域成员
每个数据成员可以用java.reflect.Field来封闭其名称,类型,修改符的集合。
也可以通过相应的方法获取或设置到该成员的值。
如:
import java.lang.reflect.*;
import java.awt.*;
class SampleField {
public
static void main(String[] args) {
GridBagConstraints g = new GridBagConstraints();
printFieldNames(g);
}
static void
printFieldNames(Object o) {
Class c = o.getClass();
Field[] publicFields = c.getFields();