Java反射快速入门

557 阅读4分钟

1. Java引入反射技术目的:

Java反射可以让我们在编译期(CompileTime)之外的运行期(Runtime)获得任何一个类的字节码对象,通过对该字节码对象的解剖,可以动态的获取对像信息和调用对象方法。在知乎看到一个形象的说法:

程序对象都是new出来的,程序相当于写死了给jvm去跑,假设服务器突然遇到某个请求要用到某个类,但没加载进jvm,这时便可用到反射。而不用停下来去重新new一个对象,然后再编译运行一遍。

2. Java反射主要提供的功能:

  • 在运行时构造任意一个类的对象
  • 在运行时调用任意一个对象的成员属性与方法(甚至是private修饰的)

3. Java反射的基本运用

  1. 通过反射获取class对象
  • 方式一: 通过Object类中的getClass()方法(基本不用)
    Person person = new Person();
    Class clazz = person.getClass();
    
  • 方式二: 使用“类.class”取得
    Class clazz = person.Class();
    
  • 方式三:(常用)使用Class内部的一个静态方法:Class.forName
    Class c = Class.forName("ReflectStudy.Person");  //注意路径
    
  1. 通过反射获取构造器与实例化对象

    简单了解一下相关的API,快速上手简单使用一下(Person类代码在最后)

  • public Constructor<?>[] getConstructors()
    获取所有的无参构造方法
  • public Constructor<T> getConstructor(Class<?>... parameterTypes)
    获取public修饰,指定参数类型的构造器,若不传参数则构造无参构造
  • public T newInstance(Object... initargs)
    使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

第一种实例化Class对象方式

public static void main(String[] args) throws Exception{
	//获取字节码对象
	Class p = Class.forName("ReflectStudy.Person");	
	//获取无参构造器 
	Constructor con = p.getConstructor();
	//实例化对象
	Object obj = con.newInstance();
	System.out.println(obj.toString());
	
}
public static void main(String[] args) throws Exception{
		Class p = Class.forName("ReflectStudy.Person");
		Constructor con = p.getConstructor(String.class,int.class);
		Object obj = con.newInstance("张三",12);
		System.out.println(obj.toString());
	}

第二种实例化Class对象方式
这种方式的前提是类有空参的公共构造方法。(如果是同包,默认权限也可以)

public static void main(String[] args) throws Exception{
		//获取字节码对象
		Class p = Class.forName("ReflectStudy.Person");
		//实例化
		Object obj = p.newInstance();
		System.out.println(obj.toString());
	}	

若想获取私有的构造器,有如下API:一般不建议使用,破坏了程序的封装性,安全性,暴力反射

  • public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
    获取指定参数类型所对应的构造方法(包含私有的)。
  • public Constructor<?>[] getDeclaredConstructors()
    获取所有的构造方法(包含私有的)。
public static void main(String[] args) throws Exception{
		Class p = Class.forName("ReflectStudy.Person");
		Constructor con = p.getDeclaredConstructor(int.class,String.class);
		//设置为true,允许访问私有构造方法
		con.setAccessible(true);
		Object obj =  con.newInstance(12,"李四");
		System.out.println(obj.toString());
	}

3. 通过反射获取成员方法与成员属性
日常中使用反射都是实例化类和调用成员方法,在这里先了解Java反射是如何调用方法的。

  • public Method getMethod(String name, Class<?>... parameterTypes)
    常用,返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
  • public Method[] getMethods()
    返回一个包含某些 Method 对象的数组,这些对象反映此 Class对象所表示的类或接口(包括从超类和超接口继承的那些的类或接口)的公共方法。
  • public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
  • public Method[] getDeclaredMethods()
    返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public static void main(String[] args) throws Exception{
		Class p = Class.forName("ReflectStudy.Person");
		Object obj = p.newInstance();
		
		/*Method[] methods = p.getMethods();
		for(Method m : methods){
			System.out.println(m);
		}*/
		
		//获取空参类型的方法eat
		Method method_1 = p.getMethod("eat");
		//获取有参类型的方法sleep
		Method method_2 = p.getMethod("sleep", String.class,int.class,double.class);
		//调用Method类的方法invoke运行
		method_1.invoke(obj);
		method_2.invoke(obj,"张三",12,123.12);
	}

获取成员属性的方式:与获取成员方法相似

  • public Field getField(String name)
  • public Field[] getFields()
  • public Field getDeclaredField(String name)
  • public Field[] getDeclaredFields()
public static void main(String[] args) throws Exception {

		Class p = Class.forName("ReflectStudy.Person");
		Object obj = p.newInstance();
		// 获取指定的成员变量public String name;
		Field field = p.getField("name");
		field.set(obj, "李四");
		//获取私有成员变量 private int age;
		field = p.getDeclaredField("age");
		field.setAccessible(true);
		field.set(obj, 12);
		
		System.out.println(obj);	//Person [name=李四, age=12]
	}

反射泛型擦除: 练习反射用的,实际上也不会这么干。例如有一个泛型为String的ArrayList集合,现在需要往里面添加Integer类型的数据

public static void main(String[] args) throws Exception {
		List<String> list = new ArrayList<>();
		list.add("张三");
		list.add("李四");

		Class c = list.getClass();
		Method method = c.getMethod("add", Object.class);
		method.invoke(list, 12);
		
		System.out.println(list);
	}

person类:

package ReflectStudy;

public class Person {
	public String name;
	private int age;
	
	public Person(){
	}
	
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	private Person(int age,String name){
		this.name = name;
		this.age = age;
	}
	
	public void eat(){
		System.out.println("人吃饭");
	}

	public void sleep(String s, int a,double d){
		System.out.println("人在睡觉"+s+"....."+a+"....."+d);
	}
	private void playGame(){
		System.out.println("人在打游戏");
	}

	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

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