Java SE 反射

一、简单理解:

在java字节码文件(.class文件)中,存放了一个Class类的实例,通过这个实例,可以拿到字节码文件里面的信息:包括构造器、字段、方法等;

二、经典面试题:

问题1:创建Person的对象,使用new Person()还是使用反射?

回答:得看情况,一般情况下需要使用类的对象时,使用new创建;

如果出现多个类或者不确定数量的类调用同一个方法时,推荐使用反射创建,提高代码复用性,降低耦合;

问题2:反射是否破坏了面向对象的封装性?

回答:没破坏;存在即合理,封装象征规定,反射象征灵活;只是不同的业务场景使用不同的方式,使用封装提高代码的整洁性和安全性,反射提高了编写代码的灵活性,【我的理解是反射对多个类可以使用批处理,不再需要一个类一个类的去处理】;如果出现多个类或者不确定数量的类调用同一个方法时,推荐使用反射创建,提高代码复用性,降低耦合;

好比是规定男厕所只有男生能进入,女厕所只有女生能进入;

特殊情况下也能不按规定进入;

三、获取字节码信息方式:

​// 方式 1
Person person = new Person();
Class clazz1 = person.getClass();

// 方式 2
Class clazz2 = Person.class;

// 方式 3
// 最常用,调用 Class.forName()
Class clazz3 = Class.forName("allwe.pojo.Person");

// 方式 4:
// 使用类加载器
ClassLoader loder = this.getClass().getClassLoader();
Class clazz4 = loder.loadClass("allwe.pojo.Person");

四、获取构造器和创建对象

1、获取构造器:

//获取字节码信息
Class clazz = Class.forName("allwe.pojo.Student");

//通过字节码信息获取构造器数组//获取公开构造器 
publicConstructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}

System.out.println("===================");
//获取全部构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
    System.out.println(declaredConstructor);
}

System.out.println("===================");
//获取指定且开放的构造器  public
//不传参数获取空参构造器
//传入构造器的参数列表的类型
Constructor constructor = clazz.getConstructor(int.class,double.class);
System.out.println(constructor);

System.out.println("===================");
//获取任意权限修饰符的构造器
Constructor declaredConstructor = clazz.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);

2、使用构造器创建对象

//使用构造器创建对象,参数列表与使用的构造器相同即可
Object object = constructor.newInstance(2,3.0);
System.out.println(object);

System.out.println("+++++++++++++++++++++++");
//使用private修饰的构造器,需要关闭权限安全检查 true-关闭 默认开启
declaredConstructor.setAccessible(true);
Object object1 = declaredConstructor.newInstance(2);
System.out.println(object1);

System.out.println("+++++++++++++++++++++++");
//字节码文件直接调用newInstance,使用的是类的空参构造器
Object object2 = clazz.newInstance();
System.out.println(object2);

System.out.println("+++++++++++++++++++++++");
Constructor constructor1 = clazz.getConstructor();
Object object3 = constructor1.newInstance();
System.out.println(object3);

3、获取字节码文件的属性

//获取字节码信息
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz = classLoader.loadClass("allwe.pojo.Student");

//获取公开属性
Field[] fields = clazz.getFields();
for (Field field : fields) {
    System.out.println(field);
}

System.out.println("======================");
//获取全部属性,不包含父类的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println(declaredField);
}

System.out.println("======================");
//获取指定的属性,公开
Field name = clazz.getField("name");
System.out.println(name);

System.out.println("======================");
//获取指定的属性,全部修饰符
Field studentNo = clazz.getDeclaredField("studentNo");
System.out.println(studentNo);

4、获取属性的属性

System.out.println("属性的属性======================");
//属性的具体结构
System.out.println("======================");
//获取修饰符
int modifiers = studentNo.getModifiers(); //返回int类型
System.out.println(Modifier.toString(modifiers)); 

System.out.println("======================");
//获取属性的数据类型
System.out.println(studentNo.getType().getName());

System.out.println("======================");
//获取属性的名字
System.out.println(studentNo.getName());

5、给对象属性赋值

//获取字节码信息
ClassLoader classLoader = this.getClass().getClassLoader();
//获取字节码文件
Class clazz = classLoader.loadClass("allwe.pojo.Student");
//创建对象
Object object = clazz.newInstance();

//给属性设置值,必须要先有对象
Field studentNo = clazz.getDeclaredField("studentNo");
studentNo.setAccessible(true);
studentNo.set(object,2018);
System.out.println(object);

6、调用对象内部方法

//获取字节码文件
Class clazz = this.getClass().getClassLoader().loadClass("allwe.pojo.Student");
//创建对象
Object object = clazz.newInstance();
//获取指定的方法
Method getStudentNo = clazz.getDeclaredMethod("getStudentNo",int.class);
getStudentNo.setAccessible(true);
//调用方法
//需要传入对象
getStudentNo.invoke(object,2);
  • 23
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值