Java反射机制

Posted Actexpler

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java反射机制相关的知识,希望对你有一定的参考价值。

     最近学习中遇到反射机制,可是老师只是轻描淡写的解释了一通,还是自己查资料补充一下。

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

一、Class类

     1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性
    2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
    3、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。
        一个 Class 对象包含了特定某个类的有关信息。换句话说:任何类都是Class类的实例对象
    4、Class 对象只能由系统建立对象
    5、一个类在 JVM 中只会有一个Class实例

 

二、反射机制

 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。

   作用:

  1. 在运行时判断任意一个对象所属的类;
  2. 在运行时获取类的对象;
  3. 在运行时访问java对象的属性,方法,构造方法等。

  

 

  反射的特点:

             为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。

静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性

反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

举例:一个大型的软件,当程序编译后,发布了,都会在后期不断的更新以完善整个程序,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 想一下,王者荣耀每次出新英雄或者出新皮肤的时候都会有更新,用户在更新的时候知只是下载一个小的程序包进行安装,而不用重新安装整个王者荣耀游戏,这就是采用动态编译的例子。

反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。

 

三、Class中实现反射机制的类

java.lang.Class;                

java.lang.reflect.Constructor; 

java.lang.reflect.Field;        

java.lang.reflect.Method;

java.lang.reflect.Modifier;

四、反射机制获取类有三种方法

在利用反射获取类的对象,对象的属性,方法,构造方法等的时候都需要创建类的类类型

 

 

package com.neuedu.reflect;
/* 
* 项目名称:Java-Reflect 
* @author:wzc
* @date 创建时间:2017年8月28日 下午8:41:29
* @Description:获取类的类类型
* @parameter  
*   */
public class JavaDemo1 {
    public static void main(String[] args) {
		//Food的实例对象如何表示
    	Food food1=new Food();
    	
    	/*
    	 * Food这个类也是一个实例对象,Class类的实例对象
    	 * 任何一个类都是Class的实例对象,三种表示方式
    	 * 第一种表达方式--->实际上在告诉我们任何一个类都有一个隐含的静态成员class
        */    	
    	Class class1=Food.class;
    	//第二种表示方式,已知该类的对象getClass
    	Class class2=food1.getClass();
    	/*
    	 * c1,c2表示了Food类的类类型(class type)
    	 * 任何类都是class类的实例对象
    	 * c1 c2都代表了Food的类类型,一个类只可能是Class类的一个实例对象
    	 */
    	System.out.println(class1==class2);
    	//第三种表达方式
    	Class class3=null;
    	try {
		class3=Class.forName("com.neuedu.reflect.Food");
	} catch (ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
    	System.out.println(class2==class3);
    	
}
//创建一个Food类
class Food{
	public void print(){
		System.out.println("hello Food");
	}
}

 

 五、创建对象

  获取类的类类型以后我们就可以利用类类型创建该类的对象

 

package com.neuedu.reflect;
/* 
* 项目名称:Java-Reflect 
* @author:wzc
* @date 创建时间:2017年8月28日 下午8:41:29
* @Description:获取类的类类型
* @parameter  
*   */
public class JavaDemo1 {
    public static void main(String[] args) {
		//Food的实例对象如何表示
    	Food food1=new Food();
    	
    	/*
    	 * Food这个类也是一个实例对象,Class类的实例对象
    	 * 任何一个类都是Class的实例对象,三种表示方式
    	 * 第一种表达方式--->实际上在告诉我们任何一个类都有一个隐含的静态成员class
        */    	
    	Class class1=Food.class;
    	//第二种表示方式,已知该类的对象getClass
    	Class class2=food1.getClass();
    	/*
    	 * c1,c2表示了Food类的类类型(class type)
    	 * 任何类都是class类的实例对象
    	 * c1 c2都代表了Food的类类型,一个类只可能是Class类的一个实例对象
    	 */
    	System.out.println(class1==class2);
    	//第三种表达方式
    	Class class3=null;
    	try {
			class3=Class.forName("com.neuedu.reflect.Food");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	System.out.println(class2==class3);
    	//我们可以通过类的类类型创建类的对象实例
    	try {
		Food food2 = (Food) class1.newInstance();
		food2.print();
    	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	}
}
//创建一个Food类
class Food{
	public void print(){
		System.out.println("hello Food");
	}
}

 

 六、获取类的相关信息:    类名,方法名,方法的返回值类型,方法的参数列表

package com.neuedu.Uttil;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/* 
* 项目名称:Java-Reflect 
* @author:wzc
* @date 创建时间:2017年8月29日 下午1:22:15
* @Description: 1.利用反射打印类的信息
*               2.利用反射打印类的成员变量
*               3.利用反射打印类的构造方法
* @parameter  
*   */
public class Uttil {
	/*
	 * 打印类的信息,打印类的返回值类型,类类名,参数列表
	 * 
	 * */
	public static void PrintClass(Object obj){
		Class  cInt=obj.getClass();
		System.out.println("类的名称:"+cInt.getName());
		/*
		 * Method类,方法对象
		 * 一个成员方法就是一个Method对象
		 * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
		 * getDeclaredMethods()获取的是所有该类自己声明的方法,
		 * 
		 * */
		Method[] ms=cInt.getMethods();
		System.out.println("[类的返回值类型],[类的名称],[类的参数列表]");
		for (int i = 0; i < ms.length; i++) {
			//得到方法的返回值类型的类类型
			Class returnType=ms[i].getReturnType();
			System.out.print(returnType.getName()+" ");
			//得到方法的名称
			System.out.print(ms[i].getName()+"(");
			//获取参数类型
			Class [] paramTypes=ms[i].getParameterTypes();
			for (Class class1 : paramTypes) {
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}
	}

}

 测试一下:

public class JunitTest {

	@Test
	public void test() {
		String string="hello";
		//Uttil.PrintClass(string);
		
	}

}

 执行结果:

 

七、获取类的属性

/*
	 * 成员变量也是对象
	 * java.lang.reflect.Field;
	 * Filed类封装了关于成员变量的操作
	 * getFields()方法获取的是所有的public的成员变量的信息
	 * getDeclaredFields获取的是该类自己声明的成员变量的信息
	 * 
	 * 
	 * */
	public static void printFieldInfo(Object obj) {
		//获取类的成员变量
		Class class1=obj.getClass();
		Field[] fields=class1.getDeclaredFields();
		for (Field field : fields) {
			//得到成员变量的类型的类类型
			//得到成员变量的类型名
			Class fieldType=field.getType();
			String   typeName=fieldType.getName();
			//得到成员变量的名称
			String   fieldName=field.getName();
			System.out.println(typeName+" "+fieldName);
		}
	}

 测试一下:

        @Test
	public void test() {
		Uttil.printFieldInfo(new Integer(1));
	}

 结果:

八、获取类的构造方法

  /*
     * 打印对象的构造函数
     * */
	public static void  printConMessage(Object obj){
	    Class class1=obj.getClass();
	    /*
	     * 构造函数也是对象
	     * java.lang.Contructor中封装了构造函数的信息
	     * getConstructors获取所有的public的构造函数
	     * getDeclaredContructors得到所有的构造函数
	     * 
	     * 
	     */
	    Constructor[] ct=class1.getConstructors();
	    for (Constructor constructor : ct) {
			System.out.print(constructor.getName()+"(");
			//获取构造函数的参数列表--->得到的是参数列表的类类型
			Class[] paramTypes=constructor.getParameterTypes();
			for (Class class2 : paramTypes) {
				System.out.print(class2.getName());
			}
			System.out.println(")");
		}
	}

 测试一下:

	@Test
	public void test() {
		String string="hello";
		Uttil.printConMessage(string);
	}

 结果:

九、通过反射来执行对象的方法

package com.neuedu.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/* 
* 项目名称:Java-Reflect 
* @author:wzc
* @date 创建时间:2017年8月29日 下午6:45:21
* @Description:通过反射执行类的方法
* 
* @parameter  
*   */
public class RunMethod {
   public static void main(String[] args) {
	   Student student=new Student("张三", 25);
	   //1.要获取方法,首先要获取该方法的类类型,
	   Class stuClass = student.getClass();
	   /*
	    * 2.获取方法、名称和参数列表
	    * getMethod获取的是public方法
	    * getDelcaredMethod自己声明的方法
	    */
	   try {
		//stuClass.getMethod("getName",new Class[]{})
		//stuClass.getMethod("getName");
		 Method m1=stuClass.getMethod("getName", null);
		//3.方法的反射操作-----以前:student.getName();
		 //m1.invoke(obj,args..);  //方法的反射操作是用m1对象来进行方法的调用
		 //方法如果没有返回值返回null,有返回值返回具体的返回值,并转换成Object
		 m1.invoke(student); 
		 System.out.println("==============");
		 m1=stuClass.getMethod("getAge", null);
		 Object object=m1.invoke(student, null);
		 System.out.println("==============");
		 //m1=stuClass.getMethod("getAge", int.class);
		 m1=stuClass.getMethod("getAge", new Class[]{int.class});
		 m1.invoke(student, 2);
		 
	
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
}
}
//student类
class Student{
	private String name;
	private int age;
	
	public Student(){
	}
	public Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	//无参数方法
	public void getName(){
	   System.out.println("name:"+name);
	}
	//无参数方法
	public void getAge(){
		System.out.println("age:"+age);	
	}
	//有参数的方法
	public void getAge(int num){
		System.out.println(num+"年前age:"+(age-num));
	}
	public void studentIn(){
		System.out.println("name:"+name+",age:"+age);
	}
	
}

 今天只是记录一些反射最基础的理论,之后会在写一些反射的应用,只有应用了才能更好的理解反射的概念。

 

以上是关于Java反射机制的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

java 反射代码片段

深入理解java的反射机制

Java反射机制

Java核心技术梳理-类加载机制与反射