Java:反射

反射到底是什么呢?我们先来看一段代码:

package 日常练习;
class Person{
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.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;
	}
	public void run() {
		System.out.println("你好,我是" + this.name + ",我今年" + this.age + "岁!");
	}
}
public class Test{
	public static void main(String[] args) {
		Person person = new Person("张三", 18);
		person.run();
	}
}

这段代码很简单,就是我们平时经常创建对象,并调用对象方法的方式,也就是正向的操作。那我们能不能反着来?就是不知道Person类的内部构成的情况下,我们如何来实例化一个Person类的对象、给对象赋值、调用Person类的普通方法?这就用到了反射。

一、Class对象的三种实例化方式

Class类是描述整个类的概念,也就是整个类的操作源头(刚开始看,可能不明白Class类到底是干嘛的,不要紧,后面还会继续说)。Class是一个类,要使用它,必然要实例化Class类的对象。Class类有三种实例化方式:

①、任何类的实例化对象,都可以通过Object类的getClass()方法来取得Class类对象。

public class Test{
	public static void main(String[] args) {
		Person person = new Person("张三", 18);
        Class<?> cls = person.getClass();
		System.out.println(cls);
	}
}

程序输出结果如下:

class 日常练习.Person

可以看到,通过此方式,可以得到person对象是“日常练习”包下的“Person”类的实例化对象。

②、“类名.class”:直接根据具体类的类名来取得Class类的对象。

public class Test{
	public static void main(String[] args) {
        Class<?> cls = Person.class;
		System.out.println(cls);
	}
}

程序输出结果依旧是:

class 日常练习.Person

③、使用Class类提供的方法:public static Class<?> forName(String className)  throws ClassNotFoundException

public class Test{
	public static void main(String[] args) throws ClassNotFoundException {
        Class<?> cls = Class.forName("日常练习.Person");
		System.out.println(cls);
	}
}

程序输出结果依旧是:

class 日常练习.Person

二、反射的基本操作:

1、取得父类信息:

①:取得类的所在包名称:public Package getPackage()

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        System.out.println(cls.getPackage().getName());
	}
}

②:取得父类的Class对象:public native Class<? super T> getSuperclass()

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        System.out.println(cls.getSuperclass());
	}
}

输出结果:

class java.lang.Object

取得实现的接口:public Class<?>[] getInterfaces()

package 日常练习;
interface A{	
}
class Person implements A{
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.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;
	}
	public void run() {
		System.out.println("你好,我是" + this.name + ",我今年" + this.age + "岁!");
	}
}
public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Class<?>[] iClasses = cls.getInterfaces();
        for (Class<?> class1 : iClasses) {
			System.out.println(class1.getName());
		}
	}
}

输出结果:

日常练习.A

总结:通过反射可以得到类结构上的所有关键信息。

2、反射调用构造方法:

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Constructor<?>[] iClasses = cls.getConstructors();
        for (Constructor<?> constructor : iClasses) {
			System.out.println(constructor);
		}
	}
}

输出结果:

public 日常练习.Person(java.lang.String,int)

因为我们Person类这里只给了一个构造方法,所以得到一个权限为public,参数为两个(一个String类型,一个整型)的构造方法。

那么如何来通过所得到的构造方法来实例化对象呢?

package 日常练习;

import java.lang.reflect.Constructor;

interface A{	
}
class Person implements A{
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.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;
	}
	public void run() {
		System.out.println("你好,我是" + this.name + ",我今年" + this.age + "岁!");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}
public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Constructor<?> constructor = cls.getConstructor(String.class,int.class);
		System.out.println(constructor.newInstance("张三",18));
	}
}

输出结果如下:

Person [name=张三, age=18]

3、反射调用普通方法:

①public Method[] getDeclaredMethods() throws SecurityException:取得本类所有的普通方法。

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
			System.out.println(method);
		}
	}
}

输出结果:

private void 日常练习.Person.run()
public java.lang.String 日常练习.Person.toString()
public java.lang.String 日常练习.Person.getName()
public void 日常练习.Person.setName(java.lang.String)
public int 日常练习.Person.getAge()
public void 日常练习.Person.setAge(int)

②public Method[] getMethods() throws SecurityException:取得父类及本类所有权限为public的普通方法。

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
			System.out.println(method);
		}
	}
}

输出结果:

public java.lang.String 日常练习.Person.toString()
public java.lang.String 日常练习.Person.getName()
public void 日常练习.Person.setName(java.lang.String)
public int 日常练习.Person.getAge()
public void 日常练习.Person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

那么,在通过这些方法将普通方法拿到之后,应该如何去调用它呢?

Method类提供类调用普通方法的方法:public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,InvocationTargetException

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Constructor<?> constructor = cls.getConstructor(String.class,int.class);
        Object object = constructor.newInstance("张三",18);
        System.out.println(object);
        System.out.println("*************************");
        Method setMethod = cls.getMethod("setName", String.class);
        setMethod.invoke(object, "李四");
        System.out.println(object);
	}
}

运行结果:

Person [name=张三, age=18]
*************************
Person [name=李四, age=18]

4、反射调用属性:

①:public Field[] getFields() throws SecurityException:取得本类包括父类的所有属性。

②:public Field[] getDeclaredFields() throws SecurityException:取得本类所有的属性。

为了方便演示,我们把上面的age属性的权限变为public,请看代码:

public class Test{
	public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("日常练习.Person");
        Constructor<?> constructor = cls.getConstructor(String.class,int.class);
        Object object = constructor.newInstance("张三",18);
        System.out.println(object);
        System.out.println("************************");
        Field fields = cls.getDeclaredField("age");
        fields.set(object , 40);
        System.out.println(object);
	}
}

输出结果:

Person [name=张三, age=18]
************************
Person [name=张三, age=40]

完!

猜你喜欢

转载自blog.csdn.net/weixin_41890097/article/details/81560396