Java 反射之使用

反射机制

  • Java Reflection
    Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助与Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
  • 加载完类之后,在堆内存的方法去中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射

Class类

对象照镜子后可以得到的信息:某个类的属性,方法和构造器,某个类到底实现了那些接口。对于每个类而言,JRE都为其保留一个不变的CLASS类型的对象。一个CLass对象包含了特定某个结构==(class/interface/enum/annotation/primitive type/void/[])==的有关信息。

  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由那个Class实例所生成
  • Class类是Reflection的根源,针对任何你想动态加载,运行的类,唯有先获得相应的Class对象
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
   //通过反射获取类的Class对象
   Class c1 = Class.forName("com.zh.User");
   System.out.println(c1);
   //每一个类只有一个CLass对象,所以他们的hashCode值相同
   Class c2 = Class.forName("com.zh.User");
   Class c3 = Class.forName("com.zh.User");
   System.out.println(c2.hashCode());
   System.out.println(c3.hashCode());
}
}

@Setter
@Getter
class User{
private Long id;
private String name;
private Integer age;
}

Class 类中分装了三种对象

  • Field: 代表一个类的属性
  • Method: 代表一个类的方法
  • Constructor: 代表一个类的构造函数
    因为每一个对象都有多个,所有类中用Filed[], Method[] 和Consructor[] 来存储Class的结构

获取Class 对象的方式

  • Class.forName(“类的全县命名”); // 将字节码文件加载进内存,返回Class对象
  • 类名.class; // 通过类型的属性class获取
  • 对象.getClass(); // getClass() 方法在Object中定义
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class TestReflection {

    public String name;
    public Integer age;
    private String password;
    private Date birth;
    
     public TestReflection(String name){
        this.name = name;
    }

}

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {

        // 获取自定义TestReflection类的 Class 对象的三种方式
        // 1. 通过Class.forName("类的全县命名")
        Class<?> aClass = Class.forName("com.zh.reflection.TestReflection");
        // 2. 通过 类名.class()
        Class<TestReflection> aClass1 = TestReflection.class;
        // 3. 通过 对象.getClass()
        Class<? extends TestReflection> aClass2 = new TestReflection().getClass();
        System.out.println(aClass.hashCode());
        System.out.println(aClass1.hashCode());
        System.out.println(aClass2.hashCode());
    }
}

/**
打印结果:发现都能获取到Class对象,并且获取到的Class对象是同一个
1711574013
1711574013
1711574013
*/

Class对象的操作

TestReflection testReflection = new TestReflection();
// 通过Class 对象获取类构造方法
Class<? extends TestReflection> aClass2 = testReflection.getClass();

// 根据Class对象获取父类的Class的对象
Class<?> superclass = aClass2.getSuperclass();
System.out.println(superclass);

// 根据Class对象 获取类名
System.out.println(superclass.getName());

通过Class 对象获取 类的属性

TestReflection testReflection = new TestReflection();
// 通过Class 对象获取类的属性
Class<? extends TestReflection> aClass2 = testReflection.getClass();
// 1. 根据入参获取指定属性
//    1.1 根据参数获取指定公开属性. 也可以获取到父类的公开属性
Field field = aClass2.getField("name");
System.out.println(field.getName());
//    1.2 获取私有属性,抛出异常:NoSuchFieldException
//        Field field1 = aClass2.getField("password");
//        System.out.println(field1.getName());
// 2. 获取所有公开的属性包括父类的
Field[] fields = aClass2.getFields();
// 3. 获取所有的属性,包括私有属性,但是获取不到父类的属性
Field[] declaredFields = aClass2.getDeclaredFields();
// 4. 根据入参获取指定的属性,包括私有属性,但是获取不到父类的属性
Field field1 = aClass2.getDeclaredField("password");
// 对私有属性设置值,发现抛出异常,对私有属性进行操作时,
// 需要先对私有Field设置忽略访问全县修饰符的安全检查
field1.setAccessible(true);
field1.set(testReflection,"123456");
System.out.println(testReflection.toString());

注意:当对私有属性Field进行操作的时候,会抛出异常,需要先对Field设置忽略访问权限修饰符的安全检查

Field对象 (属性对象)

// Field 对象的操作
// 2.1 设置值,参数说明:参数一:需要设置值的对象,参数二:设置的值
field.set(testReflection,"zhangsan");
System.out.println(testReflection.toString());
// 2.2 获取值,参数说明,参数一: 需要在那个对象中获取值
Object o = field.get(testReflection);
System.out.println(o);
// 2.3 根据Field获取属性的类型
String str = field.getType().getName();
// 2.4 根据Field对象获取属性的名称
String fieldName = field.getName();
// 2.5 忽略访问权限修饰符的安全检测
field.setAccessible(true); // true: 忽略,false: 不忽略

通过Class 对象获取 类的构造方法

TestReflection testReflection = new TestReflection();
// 通过Class 对象获取类构造方法
Class<? extends TestReflection> aClass2 = testReflection.getClass();
// 1.1根据入参获取指定的构造器包括私有构造方法,参数为入参的class类型,参数为可变参数
Constructor<? extends TestReflection> declaredConstructor = aClass2.getDeclaredConstructor(String.class);
System.out.println(declaredConstructor);

//  1.2根据入参获取指定的公开构造器,参数为入参的class类型,参数为可变参数
        Constructor<? extends TestReflection> constructor = aClass2.getConstructor(String.class);

// 1.3. 获取所有公开的构造方法
Constructor<?>[] constructors = aClass2.getConstructors();
        
// 1.4. 获取所有的包括私有的构造方法
Constructor<?>[] declaredConstructors = aClass2.getDeclaredConstructors();

// 1.5 根据Constructor对象创建实例对象
// 如果构造方法为私有的,则需要设置忽略修饰符访问权限的安全检测
declaredConstructor.setAccessible(true);
// 根据Constructor 创建对象
TestReflection testReflection1 = declaredConstructor.newInstance("张三");
System.out.println(testReflection1.toString());

Constructor对象 (构造方法对象)

// 1. 创建对象,参数根据declaredConstructor的参数设置
TestReflection testReflection1 = declaredConstructor.newInstance("张三");
// 2.  忽略访问权限修饰符的安全检测
// 如果构造方法为私有的,则需要设置忽略修饰符访问权限的安全检测
declaredConstructor.setAccessible(true);

通过Class对象获取 类的普通方法

// 1. 获取类所有的公开方法,包括父类的公开方法
Method[] methods = aClass2.getMethods();
// 2.根据入参获取参数的指定方法,包括父类的公开方法,参数一:方法名,参数二: 可变参数,为方法入参的类型的Class对象
Method method1 = aClass2.getMethod("eat");
// 3. 获取类所有的方法, 包括私有方法,但是获取不到父类的方法
Method[] declaredMethods = aClass2.getDeclaredMethods();
// 4. 根据入参获取参数的指定方法,包括私有方法 ,但是获取不到父类的方法,参数一:方法名,参数二: 可变参数,为方法入参的类型的Class对象
Method sleep = aClass2.getDeclaredMethod("sleep");

// 执行方法,如果方法为私有方法,则需要设置忽略访问权限修饰符的权限检查
sleep.setAccessible(true);
// 参数说明:参数一:执行的对象,可以用反射的方法,参数二:方法的入参
sleep.invoke(aClass2.newInstance());

Method 对象(方法对象)

// 执行方法
// 执行方法,如果方法为私有方法,则需要设置忽略访问权限修饰符的权限检查
sleep.setAccessible(true);
// 参数说明:参数一:执行的对象,可以用反射的方法,参数二:方法的入参
sleep.invoke(aClass2.newInstance());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值