一、Class类
在java中,允许通过一个对象找到其所在的类的所有信息,这便是Class类的作用。
1. Objcet类对反射的支持
在Object类中定义了以下方法,该方法将被所有子类继承:public final Class getClass() 以上方法的返回值是一个Class对象,该类是java反射机制的源头。
2. Class类
Class本身表示一个类的自身,可以通过Class类得到一个类的完整结构,包括此类中的方法定义,属性定义等。
获取Class类的实例有三种方法:
(1) 通过forName()方法
(2)通过类.class
(3)对象.getClass()
例:
package org.lxh.demo15.getclassdemo ;
class X{
};
public class GetClassDemo02{
public static void main(String args[]){
Class<?> c1 = null ; // 指定泛型
Class<?> c2 = null ; // 指定泛型
Class<?> c3 = null ; // 指定泛型
try{
// 以下的操作形式是在开发中最常用的一种形式
c1 = Class.forName("org.lxh.demo15.getclassdemo.X") ;
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
c2 = new X().getClass() ; // 通过Object类中的方法实例化
c3 = X.class ; // 通过类.class实例化
System.out.println("类名称:" + c1.getName()) ; // 得到类的名称
System.out.println("类名称:" + c2.getName()) ; // 得到类的名称
System.out.println("类名称:" + c3.getName()) ; // 得到类的名称
}
};
3. 利用Class类实例化对象
如果现在已经实例化了Class对象,则可以通过Class类中提供的
public T newInstance() throws InstantiationException,IllegalAccessException 函数实例化对象。
但是使用该函数实例化对象需要注意一点,该类必须存在无参构造函数。
要想解决这样的问题,必须明确指定要调用的构造方法,并传递参数,但是从实际的角度来看,一般使用反射实例化对象的时候,都最好存在一个无参构造方法,这样比较合理。要调用带有参数的构造方法,则必须使用Constructor类。
4. Constructor类
可以利用Constructor类获取Class中的有参构造方法,并产生实例。
操作过程:(1) 通过Class类的getConstructors()方法获得该类的所有构造方法。
(2) 向构造方法中传递一个对象数组进去,里面包含了构造方法所需的各个参数。
(3) 之后通过Constructor实例化对象。
public T newInstance(Object... initargs)
throws InstantiationException, IllegalAccessException,IllegalArgumentException,InvocationTargetException例:
package org.lxh.demo15.instancedemo ;
import java.lang.reflect.Constructor ; // 导入反射机制包
class Person{
private String name ; // name属性
private int age ; // age属性
public Person(String name,int age){
this.setName(name) ;
this.setAge(age);
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String toString(){ // 覆写toString()方法
return "姓名:" + this.name + ",年龄:" + this.age ;
}
};
public class InstanceDemo03{
public static void main(String args[]){
Class<?> c = null ; // 声明Class对象
try{
c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
Person per = null ; // 声明Person对象
Constructor<?> cons[] = null ;
cons = c.getConstructors() ;
try{
per = (Person)cons[0].newInstance("李兴华",30) ; // 实例化对象
}catch(Exception e){
e.printStackTrace() ;
}
System.out.println(per) ; // 内容输出,调用toString()
}
};
二、反射应用 - 取得类的结构
可以利用Class取得一个类所实现的全部接口、继承的所有父类、全部构造方法、全部方法、及全部属性。
1. 取得所实现的全部接口
public Class<?>[] getInterfaces()
2. 取得父类
public Class<? super T> getSuperClass()
3. 取得构造方法
public Constructors<?>[] getConstructors()
在Constructors中存在几个常用方法:
(1) 取得修饰符 : public int getModifiers()
(2) 取得方法名称: public String getName()
(3) 取得参数的类型: public Class<?>[] getParameterTypes()
但是发现修饰符变成了数字,必须使用Modifier类进行还原。
public static String toString(int mod)
例:
ackage org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Constructor ; // 导入构造方法的包
import java.lang.reflect.Modifier ; // 导入构造方法的包
public class GetConstructorDemo03{
public static void main(String args[]){
Class<?> c1 = null ; // 声明Class对象
try{
c1 = Class.forName("org.lxh.demo15.Person") ; // 实例化对象
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
Constructor<?> con[] = c1.getConstructors() ; // 取得一个类中的全部构造
for(int i=0;i<con.length;i++){
Class<?> p[] = con[i].getParameterTypes() ; // 得到构造方法中的全部参数
System.out.print("构造方法:" ) ; // 输出构造,直接打印
int mo = con[i].getModifiers() ; // 得到所要的访问权限
System.out.print(Modifier.toString(mo) + " ") ; // 得到修饰符
System.out.print(con[i].getName()) ; // 取得构造方法的名字
System.out.print("(") ;
for(int j=0;j<p.length;j++){
System.out.print(p[j].getName() + " arg" + i) ;
if(j<p.length-1){
// 判断此是否是最后一个参数
System.out.print(","); // 输出“,”
}
}
System.out.println("){}") ;
}
}
};
4. 取得全部方法public Method[] getDeclaredMethods()
throws SecurityException //输出本类中声明的全部方法
public Method[] getMethods()
方法操作:throws SecurityException //输出具有的所有方法
取得返回值类型: public Class<?> getReturnType()
取得全部的参数类型:public Class<?>[] getParameterTypes()
取得修饰符: public int getModifiers()
取得异常类型: public Class<?>[] getExceptionTypes()
取得方法名称: public String getName()
5. 取得全部属性
public Field[] getDeclaredFields()
throws SecurityException //取得本类中声明的全部属性
public Field[] getFields()
throws SecurityException //取得本类具有的所有属性(即包括从父类继承下来的)
Field类使用方法与Method方法类似,不再赘述。
三、深入反射
1. 通过反射调用类中的方法。
public Method getMethod(String name,
Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
通过此方法可以获得一个method对象。然后通过此method对象调用该方法:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
第一个参数为调用该方法的对象,后面的可变参数为传入该函数的参数
2. 通过反射调用类的setter和getter方法。
可以采用一种通用的方式来处理setter和getter方法的调用,例如:
import java.lang.reflect.Method ;
public class InvokeSetGetDemo{
public static void main(String args[]){
Class<?> c1 = null ;
Object obj = null ;
try{
c1 = Class.forName("org.lxh.demo15.Person") ; // 实例化Class对象
}catch(Exception e){}
try{
obj = c1.newInstance() ;
}catch(Exception e){}
setter(obj,"name","Troy",String.class) ; // 调用setter方法
setter(obj,"age",22,int.class) ; // 调用setter方法
System.out.print("姓名:") ;
getter(obj,"name") ;
System.out.print("年龄:") ;
getter(obj,"age");
}
/**
Object obj:要操作的对象
String att:要操作的属性
Object value:要设置的属性内容
Class<?> type:要设置的属性类型
*/
public static void setter(Object obj,String att,Object value,Class<?> type){
try{
Method met = obj.getClass().getMethod("set"+initStr(att),type) ; // 得到setter方法
met.invoke(obj,value) ; // 设置setter的内容
}catch(Exception e){
e.printStackTrace() ;
}
}
public static void getter(Object obj,String att){
try{
Method met = obj.getClass().getMethod("get"+initStr(att)) ; // 得到setter方法
System.out.println(met.invoke(obj)) ; // 调用getter取得内容
}catch(Exception e){
e.printStackTrace() ;
}
}
public static String initStr(String old){ // 将单词的首字母大写
String str = old.substring(0,1).toUpperCase() + old.substring(1) ;
return str ;
}
};
3. 通过反射调用类的属性
public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException //取得本类声明的属性
public Field getField(String name) throws NoSuchFieldException,SecurityException //取得公共属性
设置值:public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException
取得值: public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException
在访问私有属性时,必须让该属性可见: public void setAccessible(boolean flag) throws SecurityException
建议:虽然可以这样直接这样操作对象的属性,但是还是建议通过setter和getter方法来调用属性,因为这样更安全。
4. 通过反射操作数组
获得数组得类型信息,Class中存在以下方法:public Class<?> getComponentType()
Array类中存在以下方法:public static Object newInstance(Class<?> componentType, int... dimensions) throws IllegalArgumentException,
NegativeArraySizeException
则以上两个方法可以搭配使用,能以仅知道一个数组对象的时候,就能创建与该对象同样类型的数组。