java_反射基础

65 阅读4分钟

1、反射

Java的反射机制是在运行的状态中,对于任意的一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,能够调用它的任意一个属性和方法,这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。

简单一句话,反射技术可以对类进行解剖。

为什么要对类进行解剖?应用场景是什么。

我们能随便对已经发布的一个类的代码做出改动吗?如果没有源码怎么办?

wpsoNQTYb.jpg

被反射的类一般都需要具备特定的规则,反射才有意义。反射技术的出现大大提高了程序的可扩展性。

image-20210520081723122.png

通过Class类的forName()方法获取

package com.aishang.day14;

public class Demo {
	public static void main(String[] args) throws ClassNotFoundException {
//		只要知道类名即可,不需使用该类和对象,有利于扩展
//		需要传入一个字符串,就是全限定类名(全限定类名:包名+类名)
//		你写的类名不一定对,所以抛异常
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		System.out.println(clazz);
	}
}

2、对象实例的获取

传统创建对象的方式new

如果不知道这个类,那么就需要用反射

通过class类中的newInstance()创建

package com.aishang.day14;

public class Demo {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//		只要知道类名即可,不需使用该类和对象,有利于扩展
//		需要传入一个字符串,就是全限定类名(全限定类名:包名+类名)
//		你写的类名不一定对,所以抛异常
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Object obj = clazz.newInstance(); //相当于创建对象,默认调用了构造方法
//		以上过程相当于: Person p =new Person();
		System.out.println(obj);//Person [name=null, age=0]
	}
}

获取所有构造方法

package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Constructor<?>[] constructors = clazz.getConstructors();
		for (Constructor<?> c : constructors) {
			System.out.println(c);
		}
	}
}

调用非默认的构造器

之前我们是通过new的方式,创建对象时进行调用构造方法

Person person = new Person("tom",18);

现在使用反射方式,通过构造方法创建对象

  • 调用的无参构造
package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Constructor<?> constructor = clazz.getConstructor();
		Object obj = constructor.newInstance();
		System.out.println(obj);
	}
}

  • 调用有参构造
package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
//		指定参数
		Constructor<?> constructor = clazz.getConstructor(String.class,int.class);
		Object obj = constructor.newInstance("tom",18);
		System.out.println(obj);
	}
}

只能获取公有构造方法,把一个构造方法改成私有

package com.aishang.day14;

public class Person {
	private String name;
	private int age;

	private Person() {
		System.out.println("Person 构造方法运行");
	}

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

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

	public static void show() {
		System.out.println("static show run");
	}

	public String eate(String a, int b) {
		String res = a + b;
		System.out.println("function param:" + a + "." + b);
		return res;
	}

	private void privateShow() {
		System.out.println("private show run...");
	}
}

Class<?> clazz = Class.forName("com.aishang.day12.Person");
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println(constructor);
}

这时只能获取公有的构造方法

获取所有构造方法

package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        //这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。
		for (Constructor<?> c : constructors) {
			System.out.println(c);
		}
	}
}

把构造方法全部私有,接着通过有参构造创建对象

package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo {
	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Constructor<?> c = clazz.getDeclaredConstructor(String.class,int.class);
		Object obj = c.newInstance("tom",18);
		System.out.println(obj);
	}
}

报错:无效访问异常,因为构造方法私有。

通过私有构造方法创建对象,需要取消访问权限

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("com.aishang.day14.Person");
    Constructor<?> c = clazz.getDeclaredConstructor(String.class,int.class);
    c.setAccessible(true);
    Object obj = c.newInstance("tom",18);
    System.out.println(obj);
}

3、字段获取

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("com.aishang.day14.Person");
    //		Field[] fields = clazz.getFields();获取的是公有的
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        System.out.println(field);
    }
}

获取指定字段

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("com.aishang.day14.Person");
    Field age = clazz.getDeclaredField("age");
    System.out.println(age);
}

成员变量赋值:通过反射,使成员变量映射到对象上

package com.aishang.day16;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Demo1 {
	public static void main(String[] args) throws Exception {
			Class<?> clazz = Class.forName("com.aishang.day16.Person");
			Object obj = clazz.newInstance();
			Field name = clazz.getDeclaredField("name");
			name.setAccessible(true);
			Field age = clazz.getDeclaredField("age");
			age.setAccessible(true);
			name.set(obj, "jerry");
			age.set(obj, 18);
			System.out.println(obj);
			System.out.println(name.get(obj));
	}
}

4、获取方法

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("com.aishang.day14.Person");
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (Method method : declaredMethods) {
        System.out.println(method);
    }
}

获取指定方法

	public static void main(String[] args) throws Exception {
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Method m = clazz.getDeclaredMethod("eate", String.class,int.class);
		System.out.println(m);
	}

调用方法

package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo {
	public static void main(String[] args) throws Exception {
		/*
		 * Person p = new Person(); p.eate("tom",18);
		 */
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Constructor<?> c = clazz.getDeclaredConstructor();
		c.setAccessible(true);
		Object obj = c.newInstance();
		Method m = clazz.getDeclaredMethod("eate", String.class, int.class);
		//调用方法,反射到对象上
		m.invoke(obj, "tom", 18);

	}
}

调用无参方法

package com.aishang.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo {
	public static void main(String[] args) throws Exception {
		/*
		 * Person p = new Person(); p.eate("tom",18);
		 */
		Class<?> clazz = Class.forName("com.aishang.day14.Person");
		Constructor<?> c = clazz.getDeclaredConstructor();
		c.setAccessible(true);
		Object obj = c.newInstance();
		Method m = clazz.getDeclaredMethod("eate", String.class, int.class);
		//调用方法,反射到对象上
		Object invoke = m.invoke(obj, "tom", 18);
		Method m1 = clazz.getDeclaredMethod("privateShow");
		m1.setAccessible(true);
		m1.invoke(obj);
	}
}

调用静态方法:静态没有对象,但是参数要求必须映射上,所以可以用null代替

public static void main(String[] args) throws Exception {
		/*
		 * Person p = new Person(); p.eate("tom",18);
		 */
		Class<?> clazz = Class.forName("com.aishang.day15.Person");
		Method m = clazz.getMethod("show");
		m.invoke(null);
//		没有参数可以用null代替 m.invoke(null, null);
	}