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
萌新一个有错误希望指正,一起探讨!!!