zoukankan      html  css  js  c++  java
  • 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);
    	}
    	
    }
    

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

  • 相关阅读:
    URL 编码通用引用
    [转]Asp.Net 301重定向的实现(SEO友好,有利于PR值)
    js重载图片
    Asp.net MVC学习
    SEO分析的七个切入角度
    [C#] 注入DLL
    [C] 伽马函数计算(可求小数)
    [C++] DLL远程注入实例
    [JS] 玩转微软Bing地图
    [C#(WebForm)] (开源)仿VS.NET的在线网页编辑器(Lesktop开源控件库)
  • 原文地址:https://www.cnblogs.com/Actexpler-S/p/7450238.html
Copyright © 2011-2022 走看看