反射

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

  

 

原文地址:https://www.cnblogs.com/liuwei6/p/6575119.html