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

原文地址:https://www.cnblogs.com/gnivor/p/4246720.html