认识Java反射机制
认识Java反射机制
???? 在正常情况下,必须知道一个类才可以实例化对象,但是在Java中也通过一个对象来找到其所在的类的信息,那么这实际上是Class类的功能。
package zyz.demo;class X{ };public class GetClassDemo01{public static void main(String args[]){X x = new X() ;// 实例化X类的对象System.out.println(x.getClass().getName()) ;// 得到对象所在的类的完整名字}}; 结果:zyz.demo.X
?
?
?
?
?
实例化Class类型对象
实例化Class类型对象的方法有三种:
第一种:通过forName()方法
第二种:类.class
第三种:对象.getClass()
?
package zyz.demo;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());// 得到类的名称}};
?
一旦可以实例化Class类之后,就可以进行反射的进一步操作。
?
1、实例化对象
?class Person{private String name ;// name属性private int age ;// 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 Demo01{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对象try{per = (Person)c.newInstance() ;// 实例化对象}catch(Exception e){e.printStackTrace() ;}per.setName("李兴华") ;// 设置姓名per.setAge(30) ;// 设置年龄System.out.println(per) ;// 内容输出,调用toString()}};
?
?
?
???? 通过以上的代码,可以发现,即使不使用关键字new对象也可以进行实例化操作,反射的作用。但是,在使用以上操作的时候有一点必须注意,在操作中类中必须存在无参构造方法。否则无法实例化。
?
???? 所以说,使用以上的方法实际上还是需要类中构造方法的支持,符合于对象的实例化需求。
如果要想调用有参,由必须按照以下的步骤进行:
1、通过Class类中的getConstructors()取得本类中的全部构造方法。
2、向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。
3、之后通过Constructor实例化对象
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()}};
?
?
?
???? 但是,从实际角度看,如果要使用反射进行对象的实例化操作,最好在类中存在无参构造。
?
2、取得类所实现的全部接口
?
package org.lxh.demo15.classinfodemo ;public class GetInterfaceDemo{public static void main(String args[]){Class<?> c1 = null ;// 声明Class对象try{c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化对象}catch(ClassNotFoundException e){e.printStackTrace() ;}Class<?> c[] = c1.getInterfaces() ;// 以数组形式返回实现的全部接口for(int i=0;i<c.length;i++){System.out.println("实现的接口名称:" + c[i].getName()) ;// 输出接口名称}} };结果:实现的接口名称:org.lxh.demo15.China
?
3、取得父类
?package org.lxh.demo15.classinfodemo ;public class GetSuperClassDemo{public static void main(String args[]){Class<?> c1 = null ;// 声明Class对象try{c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化对象}catch(ClassNotFoundException e){e.printStackTrace() ;}Class<?> c2 = c1.getSuperclass() ;// 取得父类System.out.println("父类名称:" + c2.getName()) ;}}; 结果:父类名称:java.lang.Object
?
?
4、取得类中的全部构造方法
?
package org.lxh.demo15.classinfodemo ;import java.lang.reflect.Constructor ;// 导入构造方法的包public class GetConstructorDemo01{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++){System.out.println("构造方法:" + con[i]) ; // 输出构造,直接打印} } }; 结果:构造方法:public org.lxh.demo15.Person()构造方法:public org.lxh.demo15.Person(java.lang.String)构造方法:public org.lxh.demo15.Person(java.lang.String,int)
??
?
????? 以上的操作确实取得了类中的构造方法,但是此时是通过对象直接打印取得的,肯定会调用Constructor类中的toString()方法。
???? Constructor类中存在了以下的几个方法:
??? 取得修饰符:public int getModifiers()
??? 取得方法名称:public String getName()
??? 取得参数的类型:public Class<?>[] getParameterTypes()
package org.lxh.demo15.classinfodemo ;import java.lang.reflect.Constructor ;// 导入构造方法的包public class GetConstructorDemo02{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("构造方法:" ) ; // 输出构造,直接打印System.out.print(con[i].getModifiers() + " ") ;// 得到修饰符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("){}") ;}}};
?
?
?
运行结果:
构造方法:1 org.lxh.demo15.Person(){}
构造方法:1 org.lxh.demo15.Person(java.lang.String arg1){}
构造方法:1 org.lxh.demo15.Person(java.lang.String arg2,int arg2){}
此时,在操作之后,发现,所有的修饰符变成了数字。需要还原修饰符,改写上面的代码
package 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("){}") ;}}};
?
?
?
?运行结果:
构造方法:public org.lxh.demo15.Person(){}
构造方法:public org.lxh.demo15.Person(java.lang.String arg1){}
构造方法:public org.lxh.demo15.Person(java.lang.String arg2,int arg2){}
?
5、取得类中的全部方法
package org.lxh.demo15.classinfodemo ;import java.lang.reflect.Method ;// 导入构造方法的包import java.lang.reflect.Modifier ;// 导入构造方法的包public class GetMethodDemo{public static void main(String args[]){Class<?> c1 = null ;// 声明Class对象try{c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化对象}catch(ClassNotFoundException e){e.printStackTrace() ;}Method m[] = c1.getMethods() ;// 取得全部方法for(int i=0;i<m.length;i++){Class<?> r = m[i].getReturnType() ;// 得到返回值类型Class<?> p[] = m[i].getParameterTypes() ;// 取得全部参数的类型int xx = m[i].getModifiers() ;// 得到修饰符System.out.print(Modifier.toString(xx) + " ") ;// 输出修饰符System.out.print(r + " ") ;System.out.print(m[i].getName()) ;System.out.print("(") ;for(int j=0;j<p.length;j++){System.out.print(p[j].getName() + " " + "arg" + j) ;if(j<p.length-1){System.out.print(",") ;}}Class<?> ex[] = m[i].getExceptionTypes() ;// 取出异常if(ex.length>0){ // 判断是否产生异常System.out.print(") throws ") ;}else{System.out.print(")") ;}for(int j=0;j<ex.length;j++){System.out.print(ex[j].getName()) ;if(j<p.length-1){System.out.print(",") ;}}System.out.println() ;}}};
?
?
运行结果:
public void sayChina()
public class java.lang.String sayHello(java.lang.String arg0,int arg1)
public void setAge(int arg0)
public int getAge()
public class java.lang.String getName()
public void setName(java.lang.String arg0)
public final void wait() throws java.lang.InterruptedException
public final void wait(long arg0,int arg1) throws java.lang.InterruptedException,
public final native void wait(long arg0) throws java.lang.InterruptedException
public native int hashCode()
public final native class java.lang.Class getClass()
public boolean equals(java.lang.Object arg0)
public class java.lang.String toString()
public final native void notify()
public final native void notifyAll()
?
???? 在一般的开发工具中经常看见随笔提示功能,实际上此功能就是利用以上的程序完成的。
?
6、取得类中的属性
package org.lxh.demo15.classinfodemo ;import java.lang.reflect.Field ;// 导入构造方法的包import java.lang.reflect.Modifier ;// 导入构造方法的包public class GetFieldDemo{public static void main(String args[]){Class<?> c1 = null ;// 声明Class对象try{c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化对象}catch(ClassNotFoundException e){e.printStackTrace() ;}{// 本类属性Field f[] = c1.getDeclaredFields() ;// 取得本类中的属性for(int i=0;i<f.length;i++){Class<?> r = f[i].getType() ;// 得到属性类型int mo = f[i].getModifiers() ;// 得到修饰符的数字String priv = Modifier.toString(mo) ; // 还原修饰符System.out.print("本类属性:") ;System.out.print(priv + " ") ;System.out.print(r.getName() + " ") ;// 得到属性类型System.out.print(f[i].getName()) ;// 输出属性名称System.out.println(" ;") ;}}{// 公共属性Field f[] = c1.getFields() ;// 取得本类中的公共属性for(int i=0;i<f.length;i++){Class<?> r = f[i].getType() ;// 得到属性类型int mo = f[i].getModifiers() ;// 得到修饰符的数字String priv = Modifier.toString(mo) ; // 还原修饰符System.out.print("公共属性:") ;System.out.print(priv + " ") ;System.out.print(r.getName() + " ") ;// 得到属性类型System.out.print(f[i].getName()) ;// 输出属性名称System.out.println(" ;") ;}}}};
?
?
运行结果:
本类属性:private java.lang.String name ;
本类属性:private int age ;
公共属性:public static final java.lang.String NATIONAL ;
公共属性:public static final java.lang.String AUTHOR ;
?
7、通过反射调用类中的方法
????
package org.lxh.demo15.invokedemo ;import java.lang.reflect.Method ;public class InvokeSayChinaDemo{public static void main(String args[]){Class<?> c1 = null ;try{c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化Class对象}catch(Exception e){}try{Method met = c1.getMethod("sayChina") ;// 找到sayChina()方法met.invoke(c1.newInstance()) ;// 调用方法}catch(Exception e){e.printStackTrace() ;}}};
?
?
?
???? 如果现在要调用的方法中存在了参数,则必须设置参数的类型及内容。
package org.lxh.demo15.invokedemo ;import java.lang.reflect.Method ;public class InvokeSayHelloDemo{public static void main(String args[]){Class<?> c1 = null ;try{c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化Class对象}catch(Exception e){}try{Method met = c1.getMethod("sayHello",String.class,int.class) ;// 找到sayHello(String name,int age)方法String rv = null ;rv = (String)met.invoke(c1.newInstance(),"李兴华",30) ;// 调用方法System.out.println(rv) ;}catch(Exception e){e.printStackTrace() ;}}};
?
?
?
8、通过反射调用类setter及getter
???? Setter及Getter方法是一个标准的属性的访问方法,如果一个类的属性被封闭,则必须通过setter及getter方法设置和取得,实际上此方法的操作之所以要这样规定,主要原因是由于反射机制可以给予支持的。
package org.lxh.demo15.invokedemo ;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","李兴华",String.class) ;// 调用setter方法setter(obj,"age",30,int.class) ;// 调用setter方法System.out.print("姓名:") ;getter(obj,"name") ;System.out.print("年龄:") ;getter(obj,"age");}/**Object obj:要操作的对象String att:要操作的属性Object value:要设置的属性内容Class<?> type:要设置的属性类型*/
?
?
?
9、通过反射调用属性
???? 观察,以上的操作中是否需要类的setter及getter方法支持呢?证明以上的操作调用与setter及getter无关,但是为了保证程序的安全性,最好还是通过setter及getter方法完成调用。
package org.lxh.demo15.invokedemo ;import java.lang.reflect.Field ;public class InvokeFieldDemo{public static void main(String args[]) throws Exception{Class<?> c1 = null ;Object obj = null ;c1 = Class.forName("org.lxh.demo15.Person") ;// 实例化Class对象obj = c1.newInstance() ;Field nameField = null ;Field ageField = null ;nameField = c1.getDeclaredField("name") ;// 取得name属性ageField = c1.getDeclaredField("age") ;// 取得name属性nameField.setAccessible(true) ;// 此属性对外部可见ageField.setAccessible(true) ;// 此属性对外部可见nameField.set(obj,"李兴华") ;// 设置name属性内容ageField.set(obj,30) ;// 设置age属性内容System.out.println("姓名:" + nameField.get(obj)) ;System.out.println("年龄:" + ageField.get(obj)) ;}};
?
?
?
10、通过反射操作数组
???? 反射机制不光只能用在类中,也可以应用在任意的引用数据类型上,当然,这就包含了数组,数组使用Array类完成。
???? Class类中存在以下一个方法:
public Class<?> getComponentType()
?