1. 反射概述
1.1 概述
- 反射是指对于任何一个Class类,在“运行的时候”都可以直接得到这个类的全部成分
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量对象:Field
- 在运行时,可以直接得到这个类的成员方法对象:Method
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
1.2 反射的关键
- 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分

2. 反射获取类对象
- 反射的第一步:获取Class类对象,如此才可以解析类的全部成分
- 获取Class类的对象的三种方式
public class Test {
public static void main(String[] args) throws Exception {
Class c = Class.forName("com.lenyoo.d2_reflect_class.Student");
System.out.println(c);
Class c1 = Student.class;
System.out.println(c1);
Student s = new Student();
Class c2 = s.getClass();
System.out.println(c2);
}
}
3. 反射获取构造器对象
3.1 利用反射技术获取构造器对象的方式
public class TestStudent01 {
@Test
public void getDeclaredConstructors(){
Class c = Student.class;
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
@Test
public void getDeclaredConstructor() throws Exception {
Class c = Student.class;
Constructor cons = c.getDeclaredConstructor();
System.out.println(cons.getName() + "===>" + cons.getParameterCount());
Constructor cons1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());
}
}
3.2 反射得到的构造器用途
- T newInstance(Object… initargs)
创建对象,注入构造器需要的数据。 - void setAccessible(true)
修改访问权限,true代表暴力攻破权限,false表示保留不可访问权限(暴力反射)
反射可以破坏封装性,私有的也可以执行了
public class TestStudent02 {
@Test
public void getDeclaredConstructor() throws Exception {
Class c = Student.class;
Constructor cons = c.getDeclaredConstructor();
System.out.println(cons.getName() + "===>" + cons.getParameterCount());
cons.setAccessible(true);
Student s = (Student) cons.newInstance();
System.out.println(s);
System.out.println("-------------------------");
Constructor cons1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());
Student s1 = (Student) cons1.newInstance("孙悟空", 1000);
System.out.println(s1);
}
}
4. 反射获取成员变量对象
4.1 利用反射技术获取成员变量的方式
- getDeclaredFields()
- getDeclaredField (String name)
public class FieldDemo01 {
@Test
public void getDeclaredFields(){
Class c = Student.class;
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + "==>" + field.getType());
}
}
@Test
public void getDeclaredField() throws Exception {
Class c = Student.class;
Field f = c.getDeclaredField("age");
System.out.println(f.getName() + "==>" + f.getType());
}
}
4.2 反射得到成员变量用途
- 依然是在某个对象中取值和赋值。
void set (Object obj, Object value):
Object get (Object obj) - 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
setAccessible(boolean)
public class FiledDemo02 {
@Test
public void setField() throws Exception {
Class c = Student.class;
Field ageF = c.getDeclaredField("age");
ageF.setAccessible(true);
Student s = new Student();
ageF.set(s, 18);
System.out.println(s);
int age = (int)ageF.get(s);
System.out.println(age);
}
}
5. 反射获取方法对象
5.1 利用反射技术获取成员方法对象的方式
- getDeclaredMethods()
- getDeclaredMethod (String name, Class<?>… parameterTypes)
5.2 反射得到成员方法的用途
- 在某个对象中触发该方法执行。
Object invoke (Object obj, Object… args) - 如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行
setAccessible(boolean)
public class MethodDemo01 {
@Test
public void getDeclaredMethods(){
Class c = Dog.class;
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName() + " 返回值类型:" + method.getReturnType() + " 参数个数:" + method.getParameterCount());
}
}
@Test
public void getDeclardMethod() throws Exception{
Class c = Dog.class;
Method m = c.getDeclaredMethod("eat");
Method m2 = c.getDeclaredMethod("eat", String.class);
m.setAccessible(true);
m2.setAccessible(true);
Dog d = new Dog();
Object result = m.invoke(d);
System.out.println(result);
Object result2 = m2.invoke(d, "骨头");
System.out.println(result2);
}
}
public class Dog {
private String name ;
public Dog(){
}
public Dog(String name) {
this.name = name;
}
public void run(){
System.out.println("狗跑的贼快~~");
}
private void eat(){
System.out.println("狗吃骨头");
}
private String eat(String name){
System.out.println("狗吃" + name);
return "吃的很开心!";
}
public static void inAddr(){
System.out.println("在黑马学习Java!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
6. 反射的作用
6.1 绕过编译阶段为集合添加数据
- 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。
- 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
- 反射是作用在运行时的技术,此时已经不存在泛型了。
public class ReflectDemo {
public static void main(String[] args) throws Exception {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list1.getClass() == list2.getClass());
System.out.println("-------------------------");
ArrayList<Integer> list3 = new ArrayList<>();
list3.add(23);
list3.add(22);
Class c = list3.getClass();
Method add = c.getDeclaredMethod("add", Object.class);
boolean rs = (boolean) add.invoke(list3, "黑马");
System.out.println(rs);
System.out.println(list3);
}
}
6.2 通用框架的底层原理
public class MybatisUtil {
public static void save(Object obj){
try (
PrintStream ps = new PrintStream(new FileOutputStream("junit-reflect-annotation-proxy-app/src/data.txt", true))
){
Class c = obj.getClass();
ps.println("=============" + c.getSimpleName() + "=============");
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
field.setAccessible(true);
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ReflectDemo {
public static void main(String[] args) throws Exception{
Student s = new Student();
s.setName("猪八戒");
s.setClassName("西天跑路1班");
s.setAge(1000);
s.setHobby("吃,睡");
s.setSex('男');
MybatisUtil.save(s);
Teacher t = new Teacher();
t.setName("波仔");
t.setSex('男');
t.setSalary(6000);
MybatisUtil.save(t);
}
}