反射

java的反射机制是在运行状态中,对于任意一个类,都能获得这个类得所以属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。而这种在运行阶段动态的获取信息及动态的调用对象的方法称为java的反射机制。
Class 类与java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field,Method,Constructor类(每个类都实现了Member 接口)。这些类型的对象时由JVM 在运行时创建的,用以表示未知类里对应的成员。
这样你就可以使用Constructor 创建新的对象,用get() 和set() 方法读取和修改与Field 对象关联的字段,用invoke() 方法调用与Method 对象关联的方法。另外,还可以调用getFields() getMethods() 和 getConstructors() 等很便利的方法,以返回表示字段,方法,以及构造器的对象的数组。这样匿名对象的信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

反射机制的作用:
1.在运行时判断任意一个对象所属的类;
2.在运行时获取类的对象;
3.在运行时访问java对象的属性,方法,构造方法等。

获取字节码(class)对象的三种方式:
1.根据Object类中所有的.getClass()方法,想使用这种方法,则必须要有明确具体的类并且创建该类的对象。
2.所有的数据类型(对象?)都有对应的静态的属性.Class来获取对应的Class对象,还是必须要先明确到类,才能根据该类的Class对象获取到该类中的属性,方法,构造方法等…。
3.我们只有通过给定的类的字符串名称(需要的是全类目)才可以获取该类的字节码对象,这样的扩展性更强,具体则是通过Class.forName()方法完成,这种方法和前两种相比有一个缺点,由于前两种方法都是知道该类的情况下获取该类的字节码对象的,因此不会产生异常(也不一定但是很少概率),但是Class.forName()方法如果写错了该类的路径则会报ClassNotFoundException(类找不到异常)异常。
基类

package testDemo.demo.reflections;

public class Car {

	public String colour;
	public int age;
	private long length;

	public void say() {
		System.err.println("di~di~di~");
	}

	public void single(String num) {

		System.err.println("我只喜欢" + num);
	}

	private void eat(int num) {

		System.err.println("我只喜欢吃汽油和" + num);
	}

	public String getColour() {
		return colour;
	}

	public void setColour(String colour) {
		this.colour = colour;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public long getLength() {
		return length;
	}

	public void setLength(long length) {
		this.length = length;
	}

	public Car(String colour, int age, long length) {
		super();
		this.colour = colour;
		this.age = age;
		this.length = length;
		System.out.println("这是有参构造器");
	}

	public Car() {
		super();
		// TODO Auto-generated constructor stub
		System.err.println("这是无参构造器");
	}

	@Override
	public String toString() {
		return "Car [colour=" + colour + ", age=" + age + ", length=" + length + "]";
	}
}

获取Class对象的三种方式:

package testDemo.demo.reflections;

public class testreflections {
//通过反射获取类(Class)对象的三种方式
	public static void main(String[] args) throws ClassNotFoundException {

		Car car = new Car();

		Class<?> class1 = car.getClass();

		Class<?> class2 = Car.class;

		Class<?> class3 = Class.forName("testDemo.demo.reflections.Car");

		System.err.println(class1);
		System.out.println(class2);
		System.err.println(class3);
	}
}

通过反射机制获取类信息:
下面这段代码分别在运行期间创建了一个无参与有参的对象实例。由于getConstructor() 方法与newInstance() 方法抛出了很多异常(你可以通过源代码查看它们),这里就简写了直接抛出一个Exception,下同。

package testDemo.demo.reflections;

import java.lang.reflect.Constructor;

public class testreflections1 {

	public static void main(String[] args) throws Exception, Exception {
		Car car = new Car();
		Class<?> class1 = car.getClass();
		// 获取类加载器
		ClassLoader classLoader = class1.getClassLoader();
		// 获取这个类的无参构造器
		Constructor<?> constructor = class1.getConstructor();
		// 获取这个类的有参构造器()
		Constructor<?> constructor1 = class1.getConstructor(String.class, int.class, long.class);

		Object newInstance = constructor.newInstance();
		Object newInstance2 = constructor1.newInstance("apple", 12, 22);
		System.err.println(classLoader);
		System.out.println(constructor);
		System.err.println(constructor1);
		System.out.println(newInstance);
		System.out.println(newInstance2);
	}
}

小知识点:
********* getConstructor()和getDeclaredConstructor()区别:*********
getDeclaredConstructor(Class<?>… parameterTypes)
这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。
getDeclaredConstructors()的返回结果就没有参数类型的过滤了。

再来看getConstructor(Class<?>… parameterTypes)
这个方法返回的是上面那个方法返回结果的子集,只返回制定参数类型访问权限是public的构造器。
getConstructors()的返回结果同样也没有参数类型的过滤。

通过反射机制获取Class 中的属性:

package testDemo.demo.reflections;

import java.lang.reflect.Field;

public class testreflections2 {

	public static void main(String[] args) throws Exception {

		Class<?> class3 = Class.forName("testDemo.demo.reflections.Car");

		// 通过反射获取类中的属性
		Field field = class3.getField("colour");

		// 如果类中没有这个属性会报(java.lang.NoSuchFieldException)这个异常
		// 也不能使用这个方法去获取类中私有的属性
		// Field field = class3.getField("like");

		// 获取私有属性需要用getDeclaredField()这个方法
		Field declaredField = class3.getDeclaredField("length");
		// 当然这个方法可以获取不是私有属性(private)的属性
		Field declaredField1 = class3.getDeclaredField("colour");

		// 创建无参对象实例
		Object newInstance = class3.newInstance();
		// 为无参对象实例属性赋值 Car
		field.set(newInstance, "li");
		// 通过newInstance对象获取属性值
		Object object = field.get(newInstance);

		System.out.println(field);
		System.out.println(declaredField);
		System.out.println(declaredField1);
		System.out.println(newInstance);
		System.out.println(object);
	}
}

通过反射机制获取Class 中的方法并运行:
package testDemo.demo.reflections;

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

public class testreflections3 {

	public static void main(String[] args) throws Exception {

		Class<?> class3 = Class.forName("testDemo.demo.reflections.Car");
		// 通过反射获取及使用类中的方法的时候,首先要获得类的构造器(构造函数)(必须是有参构造器)(这里不太确定是否是必须的)
		Constructor<?> constructor1 = class3.getConstructor(String.class, int.class, long.class);
		// 然后创建有参对象实例(这里不太确定是否是必须的)
		Object newInstance = constructor1.newInstance("is", 1, 2);
		String string = newInstance.toString();

		// 获取空参数say方法
		Method m = class3.getMethod("say", null);
		// 执行无参方法
		m.invoke(newInstance, null);

		// 获取有参数say方法
		Method method = class3.getMethod("single", String.class);
		// 执行有参方法
		method.invoke(newInstance, "唱歌");

		// 如果想执行类中的私有方法需要使用这个 getDeclaredMethods()这个方法
		// 获取私有方法(有参数的)eat方法
		Method s = class3.getDeclaredMethod("eat", int.class);
		// 将检查取消(重点)
		s.setAccessible(true);
		// 执行有参方法
		s.invoke(newInstance, 10);

		System.err.println(m);
		System.err.println(string);
	}
}


反射的其他用法(比如通过创建一个工厂类)
参考文章:
https://blog.csdn.net/houguofei123/article/details/81454807
https://www.cnblogs.com/ktlshy/p/4716838.html
萌新一个有错误希望指正,一起探讨!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值