java反射原来这么简单

反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。也就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。

获取class文件对象的方式:

 Reflect01.java

public class Reflect01 {
	public static void main(String[] args) throws Exception {
		// 方式一
		Person p1 = new Person();
		Class c1 = p1.getClass();

		Person p2 = new Person();
		Class c2 = p2.getClass();

		System.out.println(p1 == p2); // false
		System.out.println(c1 == c2); // true

		// 方式二
		Class c3 = Person.class;
		System.out.println(c1 == c3); // true
		
		// 方式三
		Class c4 = Class.forName("bean.Person");
		System.out.println(c1 == c4); // true
	}
}

person.java

public class Person {

	private String name;
	int age;
	public String address;

	public Person() {
	}

	private Person(String name) {
		this.name = name;
	}

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

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

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

	public void method(String s) {
		System.out.println("method " + s);
	}

	public String getString(String s, int i) {
		return s + "---" + i;
	}

	private void function() {
		System.out.println("function");
	}

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

}

 三种方法中,最常用第三种。因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

通过反射获取构造方法

public class Reflect02 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件
		Class<?> c = Class.forName("bean.Person");

		// 获取多个构造方法
		// Constructor[] cons = c.getConstructors(); 获取公共的构造方法
		// Constructor[] cons = c.getDeclaredConstructors(); 获取所有的构造方法
		
		// 获取单个无参构造方法
		Constructor<?> con = c.getConstructor();
		Object obj = con.newInstance();
		System.out.println(obj);
		
	}
}

通过反射获取带参构造方法

 第一种情况

public class Reflect03 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.itcast_01.Person");

		// 获取带参构造方法对象
		// public Constructor<T> getConstructor(Class<?>... parameterTypes)
		Constructor con = c.getConstructor(String.class, int.class,	String.class);

		// 通过带参构造方法对象创建对象
		// public T newInstance(Object... initargs)
		Object obj = con.newInstance("林青霞", 27, "北京");
		
		System.out.println(obj);
	}
}

 这种情况运行顺利通过

但是下面就报错

public class Reflect03 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件
		Class<?> c = Class.forName("bean.Person");
		// 获取单个带参构造方法
		Constructor<?> con = c.getDeclaredConstructor(String.class, int.class);
		Object obj = con.newInstance("susu",12);
		System.out.println(obj);

	}
}

错误信息

Exception in thread "main" java.lang.IllegalAccessException: Class 反射使用.Reflect03 can not access a member of class bean.Person with modifiers ""
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
	at 反射使用.Reflect03.main(Reflect03.java:16)

 此时我们需要加上一句话

con.setAccessible(true);  // 值为true则指示反射的对象在使用时应该取消Java语言访问检查。此时运行就通过了。

 通过反射获取成员变量

public class Reflect04 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件
		Class<?> c = Class.forName("bean.Person");
		// 通过无参构造获取对象
		Constructor<?> con = c.getConstructor();
		Object obj = con.newInstance();
		
		// 获取单个成员变量
		// 获取address并赋值
		Field addressField = c.getDeclaredField("address");
		// 给obj对象的addressField字段设置为北京,实际就是给address赋值
		addressField.set(obj, "西安"); 
		
		// 获取name并赋值
		Field nameField = c.getDeclaredField("name");
		// 由于name是私有属性,因此取消Java语言访问检查。
		nameField.setAccessible(true);
		nameField.set(obj, "susu");
		
		// 获取age并赋值
		Field ageField = c.getDeclaredField("age");
		ageField.setAccessible(true);
		ageField.set(obj, 22);
		
		System.out.println(obj);
	}
}

 通过反射获取成员方法

public class Reflect05 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件
		Class<?> c = Class.forName("bean.Person");

		// 获取所有方法
		// Method[] methods = c.getMethods(); // 获取自己的和父类的方法
		// Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法
		// for (Method method : methods) {
		// System.out.println(method);
		// }

		Constructor<?> con = c.getConstructor();
		Object obj = con.newInstance();

		// 获取单个方法使用,不带返回值
		// public Method getMethod(String name,Class<?>... parameterTypes)
		// 第一个参数表示方法名,第二个参数表示的是方法的参数的class类型
		Method m1 = c.getMethod("show");
		// public Object invoke(Object obj,Object... args)
		// 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
		m1.invoke(obj);

		Method m2 = c.getMethod("method", String.class);
		m2.invoke(obj, "hello");

		// 获取单个方法使用,带返回值
		Method m3 = c.getMethod("getString", String.class, int.class);
		Object object = m3.invoke(obj, "su", 22);
		System.out.println(object);

		// 获取单个私有方法使用
		Method m4 = c.getDeclaredMethod("function");
		m4.setAccessible(true);
		m4.invoke(obj);

	}
}

猜你喜欢

转载自blog.csdn.net/loli_kong/article/details/87898194