前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java反射机制

Java反射机制

作者头像
月梦@剑心
发布2023-12-03 12:14:55
1240
发布2023-12-03 12:14:55
举报

在Java中,所有对象都有两种类型,即编译时类型和运行时类型。

编译时类型是在程序代码编译解决确定的类型,而运行时类型是在程序运行时根据实际的对象类型确定的。

并且由于多态机制,很多时候一个对象的编译时类型和运行时类型并不是一致的。

譬如,对于如下代码:

代码语言:javascript
复制
Object i = new String("qwe");
i.getClass();

对象i的编译时类型为Object,但是当我们使用getClass()获取它的所属类的Class类对象时,得到的结果却是java.lang.String

如果想要调用对象运行时类型的方法,那么就需要反射机制,因为在编译的时候,并不知道对象的运行时信息。

反射概述

反射机制允许我们在运行时借助Reflection API获取到任何类的内部信息,并可以直接操作任何对象的属性和方法。

当类被JVM加载之后,会在方法区产生一个Class类型的对象,这个类包含了完整的类的结构信息。

反射机制就是基于每个类的唯一的Class对象实现的。

反射第一步——获得Class对象

在反射操作的第一步,首先是要获得一个Class类对象,之后的反射操作都是基于这个Class实例来完成的,可以说,Class对象是反射的基本。

Class

Object类中,有一个方法,public final Class getClass(),Java所有的对象都继承了这个方法,通过这个方法可以返回一个Class对象。

一个Class对象具有如下特点:

  1. Class对象只能由系统建立
  2. 一个被加载的类在JVM中只会有一个Class实例
  3. Class类是Reflection的根源,任何想要动态加载、运行的类,唯有先获得对应的Class对象
  4. 通过Class对象可以完整地得到一个类中所有被加载的结构

获取Class实例的方法

一共有三种获得Class实例的常用方法:

获得编译期间已知类型的Class实例 直接通过类的class属性获得,安全可靠且性能高,例如:

代码语言:javascript
复制
Class clazz = String.class;

已知实例,获取其运行时类型 通常通过实例的getClass()方法来获得

通过类的全类名来获得 使用Class类提供的静态方法forName()获取,例如:

代码语言:javascript
复制
Class clazz = Class.forName("java.lang.String");

注意:所有的Java类型都有Class对象,对于数组来说,只要类型和维度相同,就是同一个Class对象。

应用场景

在以下的案例中,都对Person类来进行反射及操作:

代码语言:javascript
复制
public class Person {
    private String name;
    private Integer age;
    public String email;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }

    public Person(String name, Integer age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

创建运行时类的对象

有两种方式构造一个运行时类的对象:

使用Class对象的newInstance()方法

不过,这种方式构造对象有两个条件:

  1. 类必须有无参构造器
  2. 构造器的访问权限满足
代码语言:javascript
复制
Object p1 = new Person("jack",34);
// 获得 p1 对象的运行时类型
Class aClass = p1.getClass();
// 调用 Class 对象的 newInstance() 方法实例化对象
Person p = (Person) aClass.newInstance();
p.setName("mick");
p.setAge(12);
System.out.println(p.toString());

这种方式构造对象只可以调用无参构造方法来构造。

通过获取构造器对象来实例化对象
代码语言:javascript
复制
Object p1 = new Person("jack",34);

// 获得 p1 对象的运行时类型
Class aClass = p1.getClass();

// 通过 Class 对象的 getDeclaredConstructor() 方法
// 获得对应类的构造器对象,根据传入的类型参数确定返回哪个构造器对象
Constructor declaredConstructor = aClass.getDeclaredConstructor();

// 通过构造器对象的 newInstance() 方法实例化对象
// 这里获得的是一个无参构造器,则参数为空
Person o = (Person)declaredConstructor.newInstance(new Object[]{});
o.setName("mick");
o.setAge(78);
System.out.println(o.toString());

// 获得有参构造器对象
Constructor declaredConstructor1 = aClass.getDeclaredConstructor(String.class,Integer.class);
Person o1 = (Person)declaredConstructor1.newInstance(new Object[]{"jack", Integer.valueOf(89)});
System.out.println(o1.toString());

获得运行时类的完整结构

常用方法:

  1. public Class<?>[] getInterfaces()获得实现的全部接口
  2. public Class<? Super T> getSuperclass()获得所继承的父类 获得方法Method:
  3. public Method[] getDeclaredMethods()返回此Class对应的类或接口的全部方法
  4. public Method[] getMethods()返回此Class对应的类或接口的public方法 在Method类中:
  5. public Class<?> getReturnType()获得方法全部的返回值
  6. public Class<?>[] getParameterTypes()获得方法全部的参数方法
  7. public int getModifiers()获得方法的修饰符
  8. public Class<?>[] getExceptionTypes()获得方法的异常信息 获得属性Field:
  9. public Field[] getFields()获得Class对应的类的属性
  10. public Field[] getDeclaredFields()获得Class对应的类的全部属性 在Filed对象中:
  11. public int getModifiers()获得属性的修饰符
  12. public Class<?> getType()获得属性类型
  13. public String getName()获得属性的名字 注解相关:
  14. getAnnotations()获取运行时类的注解
Method相关
代码语言:javascript
复制
Object o = new Person();
Class<?> aClass = o.getClass();
Method[] methods = aClass.getMethods();
for (Method m : methods) {
    System.out.println("Method");
    System.out.println(m);
    Class<?>[] parameterTypes = m.getParameterTypes();
    System.out.println("Parame");
    for (Class c : parameterTypes) {
        System.out.println(c);
    }
    System.out.println("Modifier");
    int modifiers = m.getModifiers();
    System.out.println(modifiers);
    Class<?> returnType = m.getReturnType();
    System.out.println("Return");
    System.out.println(returnType);
}
Field相关
代码语言:javascript
复制
Object o = new Person();
Class<?> aClass = o.getClass();
Field[] fields = aClass.getFields();
for (Field f : fields) {
    System.out.println("Field");
    int modifiers = f.getModifiers();
    System.out.println("Modifier");
    System.out.println(modifiers);
    Class<?> type = f.getType();
    System.out.println("Type");
    System.out.println(type);
    String name = f.getName();
    System.out.println("Name");
    System.out.println(name);
}
System.out.println("--------------getDeclaredFields---------------------");
Field[] declaredFields = aClass.getDeclaredFields();
for (Field f : declaredFields) {
    System.out.println("Field");
    int modifiers = f.getModifiers();
    System.out.println("Modifier");
    System.out.println(modifiers);
    Class<?> type = f.getType();
    System.out.println("Type");
    System.out.println(type);
    String name = f.getName();
    System.out.println("Name");
    System.out.println(name);
}

getFields()方法只能拿到public修饰的属性,而getDeclaredFields()方法可以拿到所有的属性

未完待续…随时补充!

版权声明: 如无特别声明,本文版权归 月梦の技术博客 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 Java反射机制 》

本文链接:https://ymiir.netlify.app//java/Java%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6.html

本文最后一次更新为 天前,文章中的某些内容可能已过时!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 反射概述
  • 反射第一步——获得Class对象
    • Class
      • 获取Class实例的方法
      • 应用场景
        • 创建运行时类的对象
          • 使用Class对象的newInstance()方法
          • 通过获取构造器对象来实例化对象
        • 获得运行时类的完整结构
          • Method相关
          • Field相关
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档