Java学习笔记--反射
参考资料:
Rollen Holt的博客: http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html
C'est la vie的博客: http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html
coolszy的博客: http://coolszy.iteye.com/blog/569846
leeon的博客: http://www.cnblogs.com/octobershiner/archive/2012/03/18/2404751.html
感谢上面4位博主
一、什么是反射机制
简单的来说,反射机制指的是程序在运行时能够获取自身的信息。
在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
二、哪里用到反射机制
有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,jdbc用过一行码,Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成 驱动对象实例,并不知道它的具体含义。听了反射机制这节课后,才知道,原来这就是反射,现在很多开框架都用到反射机制,hibernate、struts都是用反射机制实现的。
三、反射机制的优点与缺点
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多 态的应用,有以降低类之间的耦合性。一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
四、利用反射机制能获得什么信息
类中有什么信息,它就可以获得什么信息,不过前提是得知道类的名字,要不就没有后文了
首先得根据传入的类的全名来创建Class对象。
Class c=Class.forName("className"); 注:className必须为全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo;
Object obj=c.newInstance(); //创建对象的实例
OK,有了对象就什么都好办了,想要什么信息就有什么信息了。
获取类型信息
在没有对象实例的时候,主要有三种办法。
//获得类类型的三种方式
Class classtype1 = Class.forName("com.evor.test.Person"); Class classtype2 = new Person().getClass(); Class classtype2 = Person.class;
第一种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。
4.1 获得构造器的方法
首先介绍一下Constructor类,这个类用来封装反射得到的构造器,Class有四个方法来获得Constructor对象
Constructor getConstructor(Class[] params) | 根据指定参数获得public构造器 |
Constructor[] getConstructors() | 获得public的所有构造器,类中第一个构造器下标为0 |
Constructor getDeclaredConstructor(Class[] params) | 根据指定参数获得public和非public的构造器 |
Constructor[] getDeclaredConstructors() | 获得public的所有构造器 |
从名字来看,还是很好懂的,带上Declared的都是获得所有的构造方法,包括私有。
列举上面几种方法如何使用
1.
//指定参数列表获取特定方法,此处没参数,为默认构造方法 Constructor<?> constr1 =classtype1.getDeclaredConstructor();
Object obj1 = constr1.newInstance(new Object[]{});//使用构造器创建实例
2.
//指定参数列表获取特定方法 Constructor<?> constr2 = classtype2.getDeclaredConstructor(new Class[]{String.class,String.class,String.class,int.class}); //输出构造器名 System.out.println(constr2); //使用构造器创建实例 Object obj2 = constr2.newInstance(new Object[]{"20000001","李明","男",19}); //创建一个实例
3.
//获取所有的构造方法集合 Constructor<?> constr3[] =classtype1.getDeclaredConstructors(); //使用构造器创建实例 Object obj3 = constr3[1].newInstance(new Object[]{"30000001","张三","男",27});
4.2 获得类方法的方法
Method getMethod(String name, Class[] params) | 根据方法名,参数类型获得方法 |
Method[] getMethods() | 获得所有的public方法 |
Method getDeclaredMethod(String name, Class[] params) | 根据方法名和参数类型,获得public和非public的方法 |
Method[] getDeclaredMethods() | 获得所以的public和非public方法 |
Method method = classtype1.getMethod("getInfo");//获取getInfo()方法 Object infoobj1 = method.invoke(obj1); //使用方法,获取人的信息 System.out.println((String)infoobj1); //输出返回值
4.3 获得类中属性的方法
Field getField(String name) | 根据变量名得到相应的public变量 |
Field[] getFields() | 获得类中所以public的方法 |
Field getDeclaredField(String name) | 根据方法名获得public和非public变量 |
Field[] getDeclaredFields() | 获得类中所有的public和非public方法 |
Field fields[] = classtype1.getDeclaredFields(); //part1 获取类的所有属性 for(int i = 0 ; i <3 ; i ++){ fields[i].setAccessible(true); System.out.print((String)fields[i].get(obj2)+" "); } Field fieldsno = classtype1.getDeclaredField("age");//part2 获取年龄属性 fieldsno.setAccessible(true);//不设置可能发生异常 int s1_age =(int)fieldsno.get(obj2); System.out.println(s1_age);
输出结果:20000001 李明 男 19
实例:
public class Test1{ public static void main(String args[]){ Class<?> classtype1 = null; //类类型 Class<?> classtype2=null; Class<?> classtype3=null; try{ classtype1=Class.forName("com.evor.test.Person"); //获得类类型 }catch(Exception e){ } classtype2 = new Person().getClass(); //另一种获得类类型的方式 classtype3 = Person.class; //另一种获得类类型的方式 System.out.println("类名称"+classtype1.getName()); System.out.println("类名称"+classtype2.getName()); System.out.println("类名称"+classtype3.getName()); System.out.println("三种类实质上类型是一样的,只是获得类型方式不同"); try { //获取构造器 Constructor<?> constr1 =classtype1.getDeclaredConstructor(); Constructor<?> constr2 = classtype2.getDeclaredConstructor(new Class[]{String.class,String.class,String.class,int.class}); //输出构造器名 Constructor<?> constr3[] =classtype1.getDeclaredConstructors(); constr3[1].newInstance(new Object[]{"30000001","张三","男",27}); constr1.setAccessible(true);//设置可访问的权限 System.out.println("构造器1:"+constr1); System.out.println("构造器2:"+constr2); System.out.println("构造器组:"+constr3); //使用构造器创建实例 Object obj1 = constr1.newInstance(new Object[]{}); Object obj2 = constr2.newInstance(new Object[]{"20000001","李明","男",19}); //创建一个实例 System.out.println("对象1:"+obj1); System.out.println("对象2:"+obj2); //获取类的方法,并使用 System.out.println("========获取方法并使用========"); Method method = classtype1.getMethod("getInfo");//获取getInfo()方法 Object infoobj1 = method.invoke(obj1); //使用方法,获取人的信息 Object infoobj2 = method.invoke(obj2); //使用方法 System.out.println((String)infoobj1); //输出返回值 System.out.println((String)infoobj2); //获取类的属性,并使用 System.out.println("========获取属性========"); Field fields[] = classtype1.getDeclaredFields();//获取类的所有属性 for(int i = 0 ; i <3 ; i ++){ fields[i].setAccessible(true); System.out.print((String)fields[i].get(obj2)+" "); } Field fieldsno = classtype1.getDeclaredField("age");//获取年龄属性 fieldsno.setAccessible(true);//不设置可能发生异常 int s1_age =(int)fieldsno.get(obj2); System.out.println(s1_age); } catch (Exception e) { e.printStackTrace(); } /* System.out.println("================"); Method[] method = classtype1.getMethods(); //获取类的方法 for(int i=0;i<method.length;++i){ Class<?> returnType = method[i].getReturnType(); //获取方法的返回值类型 Class<?> para[] = method[i].getParameterTypes(); //获取方法的参数类型表 int temp = method[i].getModifiers(); System.out.print(Modifier.toString(temp)+" "); System.out.print(returnType.getName()+ " "); System.out.print(method[i].getName()+" "); System.out.print("("); for(int j = 0 ; j <para.length ; j++){ System.out.print(para[j].getName()+" "+"arg"+j); if(j<para.length-1){ System.out.print(","); } } Class<?> exce[]=method[i].getExceptionTypes(); if(exce.length>0){ System.out.print(") throws "); for(int k=0;k<exce.length;++k){ System.out.print(exce[k].getName()+" "); if(k<exce.length-1){ System.out.print(","); } } }else{ System.out.print(")"); } System.out.println(); }*/ } } class Person{ private String sno ; private String sname ; private String sex ; private int age; public Person(){ this.sno = "unknow"; this.sname = "unknow"; this.sex = "unknow"; this.age = 0; } public Person(String sno, String sname , String sex , int age){ this.sno = sno; this.sname = sname; this.sex = sex; this.age = age; } public void setSno(String sno){ this.sno = sno; } public void setSname(String sname){ this.sname = sname; } public void setSex(String sex){ this.sex = sex; } public void setAge(int age){ this.age = age; } public String getSno() { return sno; } public String getSname() { return sname; } public String getSex() { return sex; } public int getAge() { return age; } public String getInfo(){ return "学号:"+sno+",姓名:"+sname+",性别:"+sex+",年龄:"+String.valueOf(age); } }
输出
类名称com.evor.test.Person
类名称com.evor.test.Person
类名称com.evor.test.Person
三种类实质上类型是一样的,只是获得类型方式不同
构造器1:public com.evor.test.Person()
构造器2:public com.evor.test.Person(java.lang.String,java.lang.String,java.lang.String,int)
构造器组:[Ljava.lang.reflect.Constructor;@1db9742
对象1:com.evor.test.Person@106d69c
对象2:com.evor.test.Person@52e922
========获取方法并使用========
学号:unknow,姓名:unknow,性别:unknow,年龄:0
学号:20000001,姓名:李明,性别:男,年龄:19
========获取属性========
20000001 李明 男 19