1、什么是反射?
Java的反射(reflection)机制是在运行状态中,对任意一个类,都能知道这个类的所有属性和方法。
2、反射的使用
反射的使用简单来说就是几个步骤:
1、获取字节码文件对象
2、获取构造器对象
3、通过构造器实例化对象
4、反射属性和方法
本文的代码都是反射笔者自己实现的Student类中的属性和方法:
public class Student {
private String name;
private String gender;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
public String getGender(){
return gender;
}
public Student(String name, String gender, int age){
this.name=name;
this.gender=gender;
this.age=age;
}
public Student(){}
private Student(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
private int getAge(){
return age;
}
}
2.1获取字节码文件对象
.java源文件在编译后形成.class的字节码文件,然后通过双亲委派模式被类加载器加载之后形成字节码文件对象
字节码文件对象(Class对象)是Java反射的基石,想要进行反射的相关操作,必须要先获得字节码文件对象
Class对象:在Java中,一切皆对象,当字节码文件加载到JVM后,会形成一个Class类对象
获取字节码文件对象的方法有三种:
1、使用.class方法
2、使用对象的getClass()方法
3、使用Class.forName(“类的全路径名”)静态方法
public static void test1() throws ClassNotFoundException {
//1、每个类中有一个class静态属性
Class<?> stuClass1=Student.class;
System.out.println(stuClass1);
//2、通过对象调用getClass()
Student stu=new Student("lwl","男",12);
Class<?> stuClass2=stu.getClass();
System.out.println(stuClass2);
//3、通过Class静态方法forName()
Class<?> stuClass3=Class.forName("Student");//如果找不到类会抛异常,我们直接往出抛
System.out.println(stuClass3);
//三个stuClass是相同的,即:一个类最多会加载一次
System.out.println(stuClass1==stuClass2);
System.out.println(stuClass2==stuClass3);
}
2.2获取构造器对象
注意:方法名中有s表示获取所有构造器对象,带Declared表示获取声明的构造器对象,未带Declared时只能获取公有的构造器对象
public static void test2(){
try {
Class<?> stuClass=Class.forName("Student");
//获取构造器对象
Constructor<?> con=stuClass.getConstructor();//获取公有无参构造
System.out.println(con);
获取公有含参构造
Constructor<?> con1=stuClass.getConstructor(String.class,String.class,int.class);
System.out.println(con1);
//获取所有构造
Constructor<?>[] con2=stuClass.getDeclaredConstructors();
System.out.println(con2.length);
} catch (Exception e) {
e.printStackTrace();
}
}
2.3通过构造器实例化对象
//3、通过构造器实例化对象
public static void test3(){
try {
Class<?> stu=Class.forName("Student");
Constructor<?> con=stu.getDeclaredConstructor(String.class);
//如果构造器是私有的,不能直接用来实例化对象
con.setAccessible(true);//将构造器访问权限设置为公有的
// 调用newInstance实例化对象
Student s=(Student)con.newInstance("jack");
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
2.4反射属性和方法
public static void test5(){
try {
Class<?> stu=Class.forName("Student");
Constructor<?> con=stu.getDeclaredConstructor(String.class);
//如果构造器是私有的,不能直接用来实例化对象
con.setAccessible(true);//将构造器访问权限设置为公有的
Student s=(Student)con.newInstance("jack");
Field gender=stu.getDeclaredField("gender");
System.out.println(gender);//私有属性
//反射属性
//修改gender属性-->修改哪个实例的属性:s
gender.setAccessible(true);
gender.set(s,"人妖");
System.out.println(s.getGender());
System.out.println(s);
Field age=stu.getDeclaredField("age");
age.setAccessible(true);
age.set(s,99);//set第一个参数是对象
System.out.println(s);
//反射方法
Method setAge=stu.getDeclaredMethod("setAge",int.class);
setAge.invoke(s,200);
Method getAge=stu.getDeclaredMethod("getAge");
getAge.setAccessible(true);
System.out.println(getAge.invoke(s));
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
3、反射的优缺点
优点:
1、对于任意一个类,都可以知道该类的所有属性和方法
2、增加了程序的灵活性和扩展性
缺点:
1、使用反射会使程序的效率降低
2、反射绕过了源代码,会带来维护问题