反射的概述
- JAVA反射机制是在运行状态中,对于任意类,都能获取这个类的所有属性和方法;对于任意对象,都能够调用其方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。
通俗的讲:
- 编写的都是.java -->(jvm) 编译成 .class , 反射就是在 .class 文件里下手
- 任意类的所有信息在反射面前都是裸体,一般好的框架封装都用到了反射(spring mybatis)
如何用反射获取 .class 文件
- 获取 .class文件的三种方式
- getClass
- 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
- 通过Class类的静态方法:forName(String className)(超级常用)
/*------------第一种方式来获取 .class 文件------------*/
Student student = new Student();
Class c = student.getClass();
System.out.println(c);
/*------------第二种方式来获取 .class 文件------------*/
Class c2 = String.class;
System.out.println(c2);
/*------------第三种方式来获取 .class 文件------------*/
//这个参数传递的是你当前 .java 文件完整的包名加上类名
//第三种方式是最常用的,一定要掌握
try {
Class c3 = Class .forName("com.offcn.entity.Student");
System.out.println(c3);
} catch (Exception e) {
e.printStackTrace();
}
注意:
- 三种方式最常用的是第三种
a. 第一种 - 对象都有了还要反射干什么。
b. 第二种 - 需要导入类的包,依赖太强,不导包就抛编译错误。
c. 第三种 - 一个字符串可以传入也可写在配置文件中等多种方法。
反射获取Student类 有参、无参构造(公有、私有)
try {
Class c3 = Class .forName("com.offcn.entity.Student");
//得到这个对象,实例化对象肯定会走构造方法
/*------获取所有共有构造方法,返回的参数是构造的数组------*/
Constructor[] constructors = c3.getConstructors();
for (int i=0;i<constructors.length;i++){
System.out.println(i);
}
/*------获取所有的构造方法(包括共有与私有构造),返回的参数是构造的数组------*/
Constructor[] declaredConstructors = c3.getDeclaredConstructors();
for (int i=0;i<declaredConstructors.length;i++){
System.out.println(declaredConstructors[i]);
}
//实例化对象,如果当前构造是无参的构造,默认一般情况会给一个null
Constructor studentC = null;
Object obj = null;
studentC = c3.getConstructor(int.class); 有参
studentC = c3.getConstructor(null); 无参
//这一句话就相当于 Student stu = new Student();
obj = studentC.newInstance(1); 有参
obj = studentC.newInstance(null); 无参
/*-----------获取私有的构造方法-----------*/
Constructor constructor = c3.getDeclaredConstructor(String.class);
//通过暴力反射去除私有(通过反射获取所有的私有都要加上这句话)
constructor.setAccessible(true);
obj = constructor.newInstance("1");
Student student1 = (Student) obj;
student1.print();
} catch (Exception e) {
e.printStackTrace();
}
获取类中公有、私有属性以及怎么给私有属性赋值
/*---------获取student类里面公有的属性---------*/
Field[] f = c3.getFields();
for (int i=0;i<f.length;i++){
System.out.println(f[i]);
}
/*--------获取所有(包括公有与私有)的属性---------*/
Field[] f2 = c3.getDeclaredFields();
for (int i=0;i<f2.length;i++){
System.out.println(f2[i]);
}
/*---------给私有的属性赋值---------*/
Field f3 = c3.getDeclaredField("sname");
f3.setAccessible(true);
//给其赋值, 第一个参数代表的是你要赋值的对象,第二个参数是你要赋值的具体值
Object object = c3.getConstructor().newInstance(null);
f3.set(object,"hehe");
Student student2 = (Student) object;
System.out.println(student2.getSname());
获取类中公有、私有方法
/*-----------获取所有公有的方法-----------*/
//只要看见 native 方法底层代码都是用 c 或 c++ 编写的
Method[] m = c3.getMethods();
for (int i = 0; i < m.length; i++) {
System.out.println(m[i]);
}
/*-----------获取所有公有、私有的方法-----------*/
Method[] dm = c3.getDeclaredMethods();
for (int i = 0; i < dm.length; i++) {
System.out.println(dm[i]);
}
获取类中单个公有、私有方法并调用
/*-----------获取单个公有的方法,并调用-----------*/
Method method = c3.getMethod("getInfo");
//调用这个方法,第一个参数传递是你要调用方法的对象/第二个参数是你调用方法的参数
method.invoke(c3.getConstructor().newInstance(null),null);
/*-----------获取单个私有的方法,并调用-----------*/
Method method1 = c3.getDeclaredMethod("getString", String.class);
method1.setAccessible(true);
Object result = method1.invoke(c3.getConstructor().newInstance(null), "hehe");
System.out.println(result);
用反射来忽略泛型
/*-----------用反射来忽略泛型-----------*/
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
//获取其 class 文件
Class classList = list.getClass();
Method method2 = classList.getMethod("add",Object.class);
method2.invoke(list,2);
for (Object o : list) {
System.out.println(o);
}