1. Java引入反射技术目的:
Java反射可以让我们在编译期(CompileTime)之外的运行期(Runtime)获得任何一个类的字节码对象,通过对该字节码对象的解剖,可以动态的获取对像信息和调用对象方法。在知乎看到一个形象的说法:
程序对象都是new出来的,程序相当于写死了给jvm去跑,假设服务器突然遇到某个请求要用到某个类,但没加载进jvm,这时便可用到反射。而不用停下来去重新new一个对象,然后再编译运行一遍。
2. Java反射主要提供的功能:
- 在运行时构造任意一个类的对象
- 在运行时调用任意一个对象的成员属性与方法(甚至是private修饰的)
3. Java反射的基本运用
- 通过反射获取class对象
- 方式一: 通过Object类中的getClass()方法(基本不用)
Person person = new Person(); Class clazz = person.getClass(); - 方式二: 使用“类.class”取得
Class clazz = person.Class(); - 方式三:(常用)使用Class内部的一个静态方法:Class.forName
Class c = Class.forName("ReflectStudy.Person"); //注意路径
-
通过反射获取构造器与实例化对象
简单了解一下相关的API,快速上手简单使用一下(Person类代码在最后)
public Constructor<?>[] getConstructors()
获取所有的无参构造方法public Constructor<T> getConstructor(Class<?>... parameterTypes)
获取public修饰,指定参数类型的构造器,若不传参数则构造无参构造public T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
第一种实例化Class对象方式
public static void main(String[] args) throws Exception{
//获取字节码对象
Class p = Class.forName("ReflectStudy.Person");
//获取无参构造器
Constructor con = p.getConstructor();
//实例化对象
Object obj = con.newInstance();
System.out.println(obj.toString());
}
public static void main(String[] args) throws Exception{
Class p = Class.forName("ReflectStudy.Person");
Constructor con = p.getConstructor(String.class,int.class);
Object obj = con.newInstance("张三",12);
System.out.println(obj.toString());
}
第二种实例化Class对象方式
这种方式的前提是类有空参的公共构造方法。(如果是同包,默认权限也可以)
public static void main(String[] args) throws Exception{
//获取字节码对象
Class p = Class.forName("ReflectStudy.Person");
//实例化
Object obj = p.newInstance();
System.out.println(obj.toString());
}
若想获取私有的构造器,有如下API:一般不建议使用,破坏了程序的封装性,安全性,暴力反射
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
获取指定参数类型所对应的构造方法(包含私有的)。public Constructor<?>[] getDeclaredConstructors()
获取所有的构造方法(包含私有的)。
public static void main(String[] args) throws Exception{
Class p = Class.forName("ReflectStudy.Person");
Constructor con = p.getDeclaredConstructor(int.class,String.class);
//设置为true,允许访问私有构造方法
con.setAccessible(true);
Object obj = con.newInstance(12,"李四");
System.out.println(obj.toString());
}
3. 通过反射获取成员方法与成员属性
日常中使用反射都是实例化类和调用成员方法,在这里先了解Java反射是如何调用方法的。
public Method getMethod(String name, Class<?>... parameterTypes)
常用,返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。public Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class对象所表示的类或接口(包括从超类和超接口继承的那些的类或接口)的公共方法。public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。public Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public static void main(String[] args) throws Exception{
Class p = Class.forName("ReflectStudy.Person");
Object obj = p.newInstance();
/*Method[] methods = p.getMethods();
for(Method m : methods){
System.out.println(m);
}*/
//获取空参类型的方法eat
Method method_1 = p.getMethod("eat");
//获取有参类型的方法sleep
Method method_2 = p.getMethod("sleep", String.class,int.class,double.class);
//调用Method类的方法invoke运行
method_1.invoke(obj);
method_2.invoke(obj,"张三",12,123.12);
}
获取成员属性的方式:与获取成员方法相似
public Field getField(String name)public Field[] getFields()public Field getDeclaredField(String name)public Field[] getDeclaredFields()
public static void main(String[] args) throws Exception {
Class p = Class.forName("ReflectStudy.Person");
Object obj = p.newInstance();
// 获取指定的成员变量public String name;
Field field = p.getField("name");
field.set(obj, "李四");
//获取私有成员变量 private int age;
field = p.getDeclaredField("age");
field.setAccessible(true);
field.set(obj, 12);
System.out.println(obj); //Person [name=李四, age=12]
}
反射泛型擦除: 练习反射用的,实际上也不会这么干。例如有一个泛型为String的ArrayList集合,现在需要往里面添加Integer类型的数据
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
Class c = list.getClass();
Method method = c.getMethod("add", Object.class);
method.invoke(list, 12);
System.out.println(list);
}
person类:
package ReflectStudy;
public class Person {
public String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
private Person(int age,String name){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("人吃饭");
}
public void sleep(String s, int a,double d){
System.out.println("人在睡觉"+s+"....."+a+"....."+d);
}
private void playGame(){
System.out.println("人在打游戏");
}
public String toString() {
return "Person [name=" + name + ", 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;
}
}