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();
    		}
    	}
    }
    

      

     

  • 相关阅读:
    UVA1349 Optimal Bus Route Design 最优巴士路线设计
    POJ3565 Ants 蚂蚁(NEERC 2008)
    UVA1663 Purifying Machine 净化器
    UVa11996 Jewel Magic 魔法珠宝
    NEERC2003 Jurassic Remains 侏罗纪
    UVA11895 Honorary Tickets
    gdb调试coredump(使用篇)
    使用 MegaCLI 检测磁盘状态并更换磁盘
    员工直接坦诚直来直去 真性情
    山东浪潮超越3B4000申泰RM5120-L
  • 原文地址:https://www.cnblogs.com/liuwei6/p/6575119.html
Copyright © 2011-2022 走看看