Class类的使用
类是java.lang.Class类的对象
任何一个类都是Class的实例对象,可以通过三种方式得到其类型:
1. 类名.class
2. 该类对象.getClass()
3. Class.forName(“类的全称”) [动态加载类]
Class c1=Foo.class;//方法一
Class c2=foo.getClass();//方法二
try {
Class c3=Class.forName("entity.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}//方法三
可以通过类的类型创建类对象实例:newInstance()方法(该类必须要有无参构造方法)
public class Foo {
public Foo() {};// 使用newInstance方法必须要有无参构造函数
}
Foo _foo=(Foo) c1.newInstance();//使用Class的newInstance方法构造已知类对象
new:创建对象 是静态加载,在编译时刻就需要加载所有可能使用到的类
Class.forName():创建对象 是动态加载,在运行时刻加载,使用动态加载可以方便支持新类型的扩充,而已完成的类不受兄弟(继承自同一父类,或实现同一接口)类的影响
package entity;
public class Foo {
public String 我是变量;
public Foo() {
};// 使用newInstance方法必须要有无参构造函数
public void print(String parameter) {
System.out.println("我是" + this + "类");
System.out.println(parameter);
}
}
package entity;
/**
* 该类继承自Foo
* @author sunqi
*/
public class Foo1 extends Foo {
public Foo1() {
};// 使用newInstance方法必须要有无参构造函数
}
在main函数中用Class.forName()可以创建出Foo1类型的对象,由其父类型指针指向
try {
Class c=Class.forName("entity.Foo1");
Foo foo1=(Foo)c.newInstance();//Foo1的父类型Foo指向这个对象
foo1.print();
Class _c=Class.forName("entity.Foo2");//Foo2类型还不存在
Foo foo2=(Foo)_c.newInstance();
foo2.print();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
由于Foo2类型不存在,所以Class _c=Class.forName("entity.Foo2");
会出现ClassNotFound异常,但是不影响Foo1对象的执行
这样可以方便添加新的继承或者实现同一接口的class的编写
方法的反射
步骤:
- 获取类的类类型(三种方式),返回Class类型对象
- 通过Class类型对象的下列方法获取相关内容(中括号里是返回类型)
- getName():类的名称 [String]
- getSimpleName():类的名称缩写 [String]
- getMethods():类的方法 [Methods[]]
- getMethod(name, parameterTypes):类的指定名称和参数类型的方法 [Method]
- getDeclaredMethods():类自己声明的方法,不问访问权限 [Methods[]]
- 又获得的类的方法(即Method[])的每一个元素都是一个Class类型的对象,对这些对象调用相应的方法获得每一个”Method”的相关内容(可选)
- getName():方法的名称 [String]
- getReturnType():方法返回值类型 [Class]
- getParameterTypes():方法的参数类型 [Class[]]
- 对获取到的方法的参数类型遍历,调用其getName()方法,获得参数类型的名称(可选)
- 调用获得的Method对象的invoke(obj, args);
/**
* 获取类的方法
* @param object 类对象
*/
public static void getClassMethods(Object object){
Class c=object.getClass();
System.out.println("类的名称:"+c.getName());//获得类的名称
Method[] methods=c.getMethods();//获得类的方法
for (Method method : methods) {
System.out.print(method.getReturnType().getSimpleName()+" ");//获得返回值类型名称
System.out.print(method.getName()+"(");//获得方法的名称
Class[] paramsTypes=method.getParameterTypes();//获得参数类型
for (Class paramsType : paramsTypes) {
System.out.print(paramsType.getName()+",");//参数类型名称
}
System.out.println(")");
}
try {
Method method=c.getMethod("print", new Class[]{String.class});
//或者Method method=c.getMethod("print",String.class);
method.invoke(object, "我是参数");
} catch (Exception e) {
e.printStackTrace();
}
}
成员变量的反射
成员变量是java.lang.reflect.Field类的对象,Field类封装了关于成员变量的操作
步骤:
- 获取类的类类型(三种方式),返回Class类型对象
- 通过Class类型对象的getFields()(或getField(name))获得成员变量,返回Field
- 对Field对象有下列方法
- getName():成员变量的名称 [String]
- getType():成员变量的类型 [Class]
/**
* 获得类的成员变量
* @param object 类对象
*/
public static void getClassVariable(Object object){
Class c=object.getClass();
Field[] fields=c.getFields();
for (Field field : fields) {
System.out.print(field.getType().getSimpleName()+" ");//成员变量的类型名称
System.out.println(field.getName());//成员变量的名称
}
}
构造函数的反射
构造函数是java.lang.Constructor类的对象,Constructor类封装了关于构造函数的操作
步骤:
- 获取类的类类型(三种方式),返回Class类型对象
- 通过Class类型对象的getConstructors()(或getConstructor(parameterTypes))获得成员变量,返回Constructor
- 对Constructor对象有下列方法
- getName():构造函数的名称 [String]
- getParameterTypes():构造函数的参数类型 [Class[]]
/**
* 获得类的构造函数
* @param object
*/
public static void getClassConstructor(Object object){
Class c=object.getClass();
Constructor[] constructors=c.getConstructors();//获得构造函数数组
for (Constructor constructor : constructors) {
System.out.print(constructor.getName()+" ");//构造函数名称
Class[] parameterTypes=constructor.getParameterTypes();//构造函数参数类型
for (Class parameterType : parameterTypes) {
System.out.println(parameterType.getSimpleName());
}
}
}
Java的反射可以绕过编译时报错,编译之后的集合不具有泛型,由此可以将不满足泛型的元素加到集合中去
public class Test {
public static void main(String[] args) throws Exception {
ArrayList a=new ArrayList();
ArrayList<String> b=new ArrayList<String>();
//b.add(10);编译不通过
Class _b=b.getClass();
Method method=_b.getMethod("add", Object.class);
method.invoke(b, 10);
System.out.println(b);
System.out.println(a.getClass()==b.getClass());//a,b类型相同
}
}
由运行结果可以看出a,b两个集合在运行中认为类型是相同的,并且通过反射的方式将整型数’10’加入到了泛型为String类型的集合中