zoukankan      html  css  js  c++  java
  • 反射

    1、反射机制

    Java中,反射指的是在运行时动态的获取一个类的信息,创 建该类的对象,或者访问该对象的成员(成员变量,方法等)。 

    2、运行的过程
    当我们通过java命令来运行某个类时,会经历如下的过程:
    类的加载 由类加载器将指定的class文件载入。载入仅执行一 次。类加载后,就会创建一个对应类的Class类的实例。
    链接 链接可以分为验证,准备,与解析。验证用于验证之前 所加载class文件结构上是否符合规范。准备阶段则准备为类 结构分配相应的空间。解析则是把class文件中的符号引用替 换为真实的实际引用。
    初始化 为类的静态成员进行相应的初始化赋值。(声明时初 始化与使用静态初始化块初始化)。 

    3、时间点
    以上只是基本的过程说明。但是, Java虚拟机规范( JVMS) 没有规定具体的执行时刻,例如,对于初始化而言,可以在 链接之后立即初始化,也可以直到使用类的相关成员时才进 行初始化。
    无论如何, JVMS都要求,在第一次使用类的静态成员时,该 成员一定是初始化完成的。也就是说,类的静态成员一定会 在第一次使用前得到初始化。 

    4、ClassLoader类加载器
    Java使用ClassLoader(子类)来实现类的加载。 ClassLoader  调用loadClass方法来加载参数指定的类型。该方法会返回一个 指定类型的Class对象。
    程序:通过ClassLoader获取系统类加载器。

    5、Class
    每个类在加载后都会由系统创建一个Class对象, Class对象存放 类的相关信息,如方法,变量,构造器等。
    通过Class类的静态方法forName方法可以获取指定类型的Class 对象。这与ClassLoader类的loadClass方法类似。不同的是, forName默认是初始化类的。
    说明:加载类不代表会初始化类。

    6、获取Class对象
    可以通过以下方式获取Class对象:
    通过ClassLoader对象的loadClass方法。 (Class<?>)
    通过Class类的静态方法forName方法。 (Class<?>)
    通过类名.class获取。 (Class<T>)
    通过对象.getClass方法获取。 (Class<? extends T>)

    7、创建对象
    可以通过Class对象的newInstance方法来创建对象。(类似于 调用无参的构造器)。
    如果要创建含有参数的构造器,需要通过Class对象的 getConstructor(只能获取public权限)或 getDeclaredConstructor来获取相应的构造器对象
    Constructor),然后通过构造器的newInstance方法创建对 象。
    说明:可以调用Constructor对象的setAccessible方法设置访问 权限。 

    8、调用方法
    通过Class对象的getMethodgetDeclaredMethod获取相关的 方法对象Method,然后通过Method对象的invoke方法调用。 

    /*
     * ClassLoader的loadClass方法与Class的forName方法:
     * 二者都可以加载参数的类型,不同的是:
     * loadClass方法仅加载类型,不会对类型进行初始化操作。
     * 而forName方法不仅加载类型,而且会对类型进行初始化。即类中
     * 声明的静态成员会得到初始化(执行)。
     */
    package day17;
    
    public class ClassTest {
    	public static void main(String[] args) {
    		try {
    			// 加载参数指定的类型。并且会对指定的类型进行
    			// 初始化。
    			// Class<?> c = Class.forName("day17.Value");
    			// 第二个参数可以指定是否在加载后对类进行初始化。
    			// 第三个参数类型加载器。
    			Class.forName("day17.Value", false, ClassLoader.getSystemClassLoader());
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      

    /*
     * 获取Class对象
     * 1 ClassLoader类的loadClass方法,返回Class<?>
     * 2 Class类的forName方法,返回Class<?>
     * 3 通过类型T.class,返回Class<T>
     * 4 通过Object类的getClass方法,返回Class<? extends T>
     */
    package day17;
    
    public class ClassObject {
    
    	public static void main(String[] args) {
    		ClassLoader cl = ClassLoader.getSystemClassLoader();
    		try {
    			Class<?> c = cl.loadClass("day17.Value");
    			Class<?> c2 = Class.forName("day17.Value");
    			Class<Value> c3 = Value.class;
    			Value v = new Value();
    			Class<? extends Value> c4 = v.getClass();
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    

      

    package day17;
    
    public class CreateObject {
    
    	public static void main(String[] args) {
    		CreateObject o = new CreateObject();
    		Object obj = o.createObject("day17.Value");
    		if (obj instanceof Value) {
    			Value v = (Value) obj;
    		}
    	}
    
    	// 通过反射动态去创建一个对象,并将该对象返回。
    	public Object createObject(String type) {
    		// Object o = new type();
    		Object o = null;
    		try {
    			Class<?> c = Class.forName(type);
    			// 通过无参的构造器创建对象。
    			o = c.newInstance();
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		}
    		return o;
    	}
    }
    

      

    /*
     * 通过Constructor类型创建
     * 相关类的对象。
     * 
     * Class类的getConstructor与getDeclaredConstructor:
     * getConstructor只能获得声明为public的构造器。
     * getDeclaredConstructor可以获得任意访问权限的构造器。
     */
    package day17;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class CreateObject2 {
    	public static void main(String[] args) {
    		/*
    		 * Value v = new Value(100); System.out.println(v.getX());
    		 */
    
    		Class<Value> c = Value.class;
    		// 获取声明为public访问权限的构造器
    		// c.getConstructor(parameterTypes)
    		try {
    			// 获得任意访问权限的构造器,参数为相应构造器参数对应的
    			// Class类型。
    			Constructor<Value> con = c.getDeclaredConstructor(int.class);
    			Value v = con.newInstance(100);
    			System.out.println(v.getX());
    
    			// 获得私有的构造器
    			con = c.getDeclaredConstructor(String.class);
    			// 设置为可访问的,这样可以访问私有成员(构造器)。
    			con.setAccessible(true);
    			v = con.newInstance("abcs");
    		} catch (NoSuchMethodException e) {
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      

    package day17;
    
    public class ClassLoaderTest {
    
    	public static void main(String[] args) {
    		// 获得系统类加载器
    		ClassLoader cl = ClassLoader.getSystemClassLoader();
    		// 主动加载一个类型,需要提供类型的全限定名。
    		try {
    			// 加载类型后,就会创建该类型的Class对象。
    			// 返回加载类型的Class对象。
    			// 加载一个类型,不会初始化该类型。(静态初始化不会
    			// 得到执行。
    			Class<?> c = cl.loadClass("day17.Value");
    			// 获得类型的加载器。
    			System.out.println(c.getClassLoader());
    			// 启动类加载器负责加载API(JAVA类库提供的)类型,启动类
    			// 加载时不是Java语言实现的,因此会输出null。
    			System.out.println(String.class.getClassLoader());
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    
    class Value {
    	static {
    		// System.out.println("静态初始化块执行");
    	}
    
    	public void f(int k) {
    		System.out.println(k);
    	}
    
    	public int g(int k) {
    		return k * k;
    	}
    
    	public static void staticF() {
    		System.out.println("静态方法");
    	}
    
    	private int x;
    
    	@Override
    	public String toString() {
    		return "Value [x=" + x + "]";
    	}
    
    	public int getX() {
    		return x;
    	}
    
    	public void setX(int x) {
    		this.x = x;
    	}
    
    	public Value() {
    
    	}
    
    	public Value(int x) {
    		this.x = x;
    	}
    
    	private Value(String s) {
    
    	}
    }
    

      

    /*
     * 通过反射动态调用一个方法。
     */
    package day17;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class MethodTest {
    	/*
    	 * Value v = new Value(); v.f(10);
    	 */
    	public static void main(String[] args) {
    		Class<Value> c = Value.class;
    		try {
    			Constructor<Value> con = c.getDeclaredConstructor();
    			Value v = con.newInstance();
    			// 获得相关方法的对象
    			Method m = c.getDeclaredMethod("f", int.class);
    			// 调用方法,第一个参数为调用该方法的对象,
    			// 第二个参数为方法的实际参数列表。
    			m.invoke(v, 10);
    			// 有返回值的方法。
    			Method m2 = c.getDeclaredMethod("g", int.class);
    			// 获得方法的返回值。
    			Object rtnValue = m2.invoke(v, 2);
    			System.out.println(rtnValue);
    			// 静态方法
    			Method m3 = c.getDeclaredMethod("staticF");
    			// 因为静态方法调用不需要对象的引用,因此,可以传递null值。
    			m3.invoke(null);
    
    		} catch (NoSuchMethodException e) {
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      9、访问成员变量
    通过Class对象的getFieldgetDeclaredField方法获取相关的成 员变量Field对象(域对象),然后通过Field对象的setget方 法设置与获取变量的值。
    说明: setget配有相关的setXXXgetXXXXXX为类型,可以 简化操作。 

         10、安全管理器
    我们可以设置安全管理器, 进而限制对私有成员的访问。

    /*
     * 通过反射动态获得成员变量。
     */
    package day17;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    
    public class FieldTest {
    
    	public static void main(String[] args) {
    		Class<Value> c = Value.class;
    		try {
    			Constructor<Value> con = c.getDeclaredConstructor();
    			Value v = con.newInstance();
    			Field f = c.getDeclaredField("x");
    			f.setAccessible(true);
    			// 设置Field对象所代表的成员变量的值。
    			f.set(v, 99);
    			// 获取Field对象所代表的成员变量的值。
    			// int k = f.get(v);
    			System.out.println(f.get(v));
    
    			// 如果成员变量是基本数据类型,我们可以使用
    			// 更加简便的getT或setT方法,T为相应的
    			// 基本数据类型。
    			f.setInt(v, 20);
    			int x = f.getInt(v);
    		} catch (NoSuchFieldException e) {
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		} catch (NoSuchMethodException e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    

      

    /*
     * 通过反射,我们可以访问到类的私有成员,这将
     * 打破类的封装性,我们可以设置安全管理器来
     * 解决这个问题。
     */
    package day17;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class Security {
    
    	public static void main(String[] args) {
    		// 设置安全管理器
    		System.setSecurityManager(new SecurityManager());
    		Class<Value> c = Value.class;
    		try {
    			Constructor<Value> con = c.getDeclaredConstructor(String.class);
    			con.setAccessible(true);
    			con.newInstance("ab");
    		} catch (NoSuchMethodException e) {
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      

     

  • 相关阅读:
    觉察——似非而是的隽语
    蔡志忠:带你看宇宙 颠覆你想象!
    宏图:肯恩·威尔伯眼中的法界|《野兽爱智慧》
    《平常禅》的启示:在平凡生活中活出真实的自己|心灵自由写作群·文选
    我们如何从高纬度世界吸取能量?
    刘希彦·到底该如何进补
    胡因梦|修道上的物化倾向
    【宗萨仁波切】精进,并不表示你要多念经、多念咒!
    Mysql:Authentication Plugins:插件式(权限)认证
    Mysql:通过SSH隧道方式实现安全通讯
  • 原文地址:https://www.cnblogs.com/liuwei6/p/6575119.html
Copyright © 2011-2022 走看看