• java反射机制(转载)


    转载地址:https://www.cnblogs.com/Eason-S/p/5851078.html

    一. 反射机制概念

         主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

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

      类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。

      通俗的说,大家都知道java编译完成后会生成.class文件,java的反射机制就相当于用程序直接调用以前生成的.class的功能,说一个很现实的例子,我们用java开发好的程序,我们给用户的是包含.class的安装包,里边没有.java文件,如果我们程序版本更新了,用户通过网络更新程序,那需要重新下载一次所有文件吗?当然不是,通过java的反射机制,我们添加的新版本功能只需要通过反射就可以调用.class文件中函数的功能,所以,就只需要更新新添加的.class文件和修改的.class文件即可。

    二. 反射机制的作用

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

    三. 反射机制的优点与缺点

    首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。 
    静态编译:在编译时确定类型,绑定对象,即通过。 
    动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。 

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

      比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 

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

    四. 反射机制的示例

    1.通过一个对象获得完整的包名和类名

    添加一句:所有类的对象其实都是Class的实例。

    package Reflect;
    
    class Demo{
        //other codes...
    }
    
    class hello{
        public static void main(String[] args) {
            Demo demo=new Demo();
            System.out.println(demo.getClass().getName());
        }
    }
    //【运行结果】:Reflect.Demo
    

    2.实例化Class类对象

    package Reflect;
    
    class Demo{
        //other codes...
    }
    
    class hello{
        public static void main(String[] args) {
            Class<?> demo1=null;
            Class<?> demo2=null;
            Class<?> demo3=null;
            try{
                //一般尽量采用这种形式
                demo1=Class.forName("Reflect.Demo");
            }catch(Exception e){
                e.printStackTrace();
            }
            demo2=new Demo().getClass();
            demo3=Demo.class;
    
            System.out.println("类名称   "+demo1.getName());
            System.out.println("类名称   "+demo2.getName());
            System.out.println("类名称   "+demo3.getName());
        }
    }
    //【运行结果】:
    //类名称   Reflect.Demo
    //类名称   Reflect.Demo
    //类名称   Reflect.Demo
    

    3.通过Class实例化其他类的对象

    Person类

    package reflect;
    
    public class Person {
        private String name;
        private int age;
        
        public Person(){
        	
        }
        public Person(String name){
            this.name=name;
        }
        public Person(int age){
            this.age = age;
        }
        public Person(String name, int age) {
            this.age = age;
            this.name = name;
        }
        
    	public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString(){
            return "["+this.name+"  "+this.age+"]";
        }
    }
    

    通过class实例化Person类

    package reflect;
    //通过class实例化其他类对象
    public class test2 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person");
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		Person per = null;
    		try {
    			per = (Person) demo.newInstance();
    		} catch (InstantiationException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    		per.setName("Artorias");
    		per.setAge(20);
    		System.out.println(per.toString());
    	}
    }
    

    !!!注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误。

    4.通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    //通过class调用其他类中的构造函数或者创建其他类的对象
    public class test3 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person");
    		} catch (ClassNotFoundException e) {
    			System.err.println("there is a error");
    			e.printStackTrace();
    		}
    		Person per1 = null;
    		Person per2 = null;
    		Person per3 = null;
    		Person per4 = null;
    		Constructor<?> cons[] = demo.getConstructors();
    		for(Constructor<?> con:cons){
    			System.out.println("构造函数:" + con);
    		}
    		try {
    			//要注意这里的cons得到的cons中构造函数的顺序,下边的代码也要按照顺序来写,不然就会报错
    			per1 = (Person) cons[3].newInstance();
    			per2 = (Person) cons[2].newInstance("Arotrias");
    			per3 = (Person) cons[1].newInstance(18);
    			per4 = (Person) cons[0].newInstance("Arotrias", 18);
    		} catch (InstantiationException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    		System.out.println(per1.toString());
    		System.out.println(per2.toString());
    		System.out.println(per3.toString());
    		System.out.println(per4.toString());
    	}
    }
    

    5.返回一个类实现的接口

    China接口

    package reflect;
    
    public interface China {
    	public static final String name = "Artorias";
    	public static int age = 18;
    	public void sayChina();
    	public void sayHello(String name, int age);
    }
    

    Person1实现了China这个接口

    package reflect;
    
    
    public class Person1 implements China{
    	private String sex;
    	public Person1(){}
    	public Person1(String sex){
    		this.sex = sex;
    	}
    	
    	public String getSex() {
    		return sex;
    	}
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    	@Override
    	public void sayChina() {
    		System.out.println("Hello China");
    	}
    
    	@Override
    	public void sayHello(String name, int age) {
    		System.out.println(name + "    " + age);
    	}
    
    }
    

    获得Person1类的实现的所有接口

    package reflect;
    //获得其他类实现的所有接口
    public class test4 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person1");
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    		Class<?> intes[] = demo.getInterfaces();
    		for(int i=0; i<intes.length; i++){
    			System.out.println(intes[i].getName());
    		}
    	}
    }
    

    6.取得其他类中的父类

    package reflect;
    //取得其他类的父类
    public class test6 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person1");
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		Class<?> temp = demo.getSuperclass();
    		System.out.println(temp.getName());
    	}
    }
    

    7.获得其他类中的全部构造函数

    package reflect;
    
    import java.lang.reflect.Constructor;
    //获得其他类的所有构造方法
    public class test5 {
    	
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person");
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		Constructor<?>[] cons = demo.getConstructors();
    		for(Constructor<?> con:cons){
    			System.out.println(con);
    		}
    	}
    }
    

    8.取得其他类的全部属性,将这些整理在一起,也就是通过class取得一个类的全部框架

    package reflect;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    
    //取得其他类的全部属性,将这些整理到一起,也就是通过class取得一个类的全部框架
    public class test7 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person1");
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		System.out.println("------本类属性------");
    		//取得本类全部属性
    		Field[] fields = demo.getDeclaredFields();
    		for(Field field : fields){
    			//权限修饰符
    			int mo = field.getModifiers();
    			String priv = Modifier.toString(mo);
    			//属性类型
    			Class<?> type = field.getType();
    			System.out.println("权限:" + priv + ",属性类型:" + type.toString() + ",属性名:" + field.getName());
    		}
    		System.out.println("------实现的接口或父类属性------");
    		Field[] field1s = demo.getFields();
    		for(Field field1 : field1s){
    			//权限修饰符
    			int mo = field1.getModifiers();
    			String priv = Modifier.toString(mo);
    			//属性类型
    			Class<?> type = field1.getType();
    			System.out.println("权限:" + priv + ",属性类型:" + type.toString() + ",属性名:" + field1.getName());
    		}
    	}
    }
    

    9.通过反射调用其他类中的方法

    package reflect;
    
    import java.lang.reflect.Method;
    
    //通过反射获得其他类中的方法
    public class test8 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		try {
    			demo = Class.forName("reflect.Person1");
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		try {
    			//调用Person1类中的sayChina方法
    			Method method = demo.getMethod("sayChina");
    			method.invoke(demo.newInstance());
    			//调用Person1类中的sayHello方法
    			method = demo.getMethod("sayHello", String.class, int.class);
    			method.invoke(demo.newInstance(), "Artorias", 18);
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    }
    

    10.调用其他类的set和get方法

    package reflect;
    
    import java.lang.reflect.Method;
    
    //调用其他类的set和get方法
    public class test9 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
            Object obj=null;
            try {
                demo = Class.forName("reflect.Person1");
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
    			obj = demo.newInstance();
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
            setter(obj, "Sex", "男", String.class);
            getter(obj, "Sex");
    	}
    	
    	 /**
         * @param obj   操作的对象
         * @param att   操作的属性
         * */
    	public static void getter(Object obj, String att){
    		try {
    			Method method = obj.getClass().getMethod("get" + att);
    			System.out.println(method.invoke(obj));
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    	
    	 /**
         * @param obj   操作的对象    
         * @param att   操作的属性
         * @param value 设置的值
         * @param type  参数的属性
         * */
    	public static void setter(Object obj, String att, Object value, Class<?> type){
    		try {
    			Method method = obj.getClass().getMethod("set" + att, type);
    			method.invoke(obj, value);
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    }
    

    11.通过反射操作属性

    package reflect;
    
    import java.lang.reflect.Field;
    
    //通过反射操作属性
    public class test10 {
    	public static void main(String[] args) {
    		Class<?> demo = null;
    		Object obj = null;
    		
    		try {
    			demo = Class.forName("reflect.Person1");
    			obj = demo.newInstance();
    			Field field = demo.getDeclaredField("sex");
    			field.setAccessible(true);
    			field.set(obj, "男");
    			System.out.println(field.get(obj));
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }
    

    12.通过反射取得并修改数组的信息

    package reflect;
    
    import java.lang.reflect.Array;
    
    //通过反射取得并修改数组的信息
    public class test11 {
    	public static void main(String[] args) {
    		int[] temp={1,2,3,4,5};
    		Class<?> demo = temp.getClass().getComponentType();
    		System.out.println("数组类型:" + demo.getName());
    		System.out.println("数组长度:" + Array.getLength(temp));
    		System.out.println("数组第一个元素:" + Array.get(temp, 0));
    		Array.set(temp, 0, 100);
    		System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
    	}
    }
    

    13.通过反射修改数组大小

    package reflect;
    
    import java.lang.reflect.Array;
    
    //通过反射修改数组大小
    public class test12 {
    	public static void main(String[] args) {
    		int[] temp={1,2,3,4,5,6,7,8,9};
    		 int[] newTemp=(int[])arrayInc(temp,15);
    	     print(newTemp);
    	     System.out.println("
    =====================");
    	     String[] atr={"a","b","c"};
    	     String[] str1=(String[])arrayInc(atr,8);
    	     print(str1);
    	}
    	
    	/**
         * 修改数组大小
         * */
        public static Object arrayInc(Object obj,int len){
            Class<?> arr = obj.getClass().getComponentType();
            Object newArr = Array.newInstance(arr, len);
            int co = Array.getLength(obj);
            System.arraycopy(obj, 0, newArr, 0, co);
            return newArr;
        }
        /**
         * 打印
         * */
        public static void print(Object obj){
            Class<?>c=obj.getClass();
            if(!c.isArray()){
                return;
            }
            System.out.println("数组长度为: " + Array.getLength(obj));
            for (int i = 0; i < Array.getLength(obj); i++) {
                System.out.print(Array.get(obj, i)+" ");
            }
        }
    }
    

    14.动态代理

    首先来看看如何获得类加载器:

    package reflect;
    //动态代理
    public class test13 {
    	public static void main(String[] args) {
    		//首先看看如何获得类加载器
    		Person1 p1 = new Person1();
    		System.out.println("类加载器:" + p1.getClass().getClassLoader().getClass().getName());
    	}
    }
    

    其实在java中有三种类类加载器。

    1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

    2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jrelibext目录中的类

    3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

    如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。

    package reflect;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    //定义项目接口
    interface Subject {
      public String say(String name, int age);
    }
    
    //定义真实项目
    class RealSubject implements Subject {
      @Override
      public String say(String name, int age) {
          return name + "  " + age;
      }
    }
    
    class MyInvocationHandler implements InvocationHandler {
      private Object obj = null;
    
      public Object bind(Object obj) {
          this.obj = obj;
          return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                  .getClass().getInterfaces(), this);
      }
    
      public Object invoke(Object proxy, Method method, Object[] args)
              throws Throwable {
          Object temp = method.invoke(this.obj, args);
          return temp;
      }
    }
    
    public class test14 {
    	public static void main(String[] args) {
            MyInvocationHandler demo = new MyInvocationHandler();
            Subject sub = (Subject) demo.bind(new RealSubject());
            String info = sub.say("Rollen", 20);
            System.out.println(info);
        }
    }
    

      

    类的生命周期

      在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

      类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载以前

    链接就是把二进制数据组装为可以运行的状态。

    链接分为校验,准备,解析这3个阶段:

    校验一般用来确认此二进制文件是否适合当前的JVM(版本),

    准备就是为静态成员分配内存空间,并设置默认值。

    解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)。

      完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期。

  • 相关阅读:
    对网页图片的增删改管理
    还没搞完的排序(后期更新)
    web实现图片动态
    C++11 笔记
    如何解决刷新系统桌面响应速度很慢的问题
    CGrowableArray解析 _ DXUT容器
    测试...外部指针访问private
    CustomUI Direct3D9_Sample
    缺少.lib文件导致的Link2019 解决方案汇总
    在DirectX9中使用DXUT定制按钮来控制模型旋转的问题
  • 原文地址:https://www.cnblogs.com/K-artorias/p/8033808.html
Copyright © 2020-2023  润新知