【重学Java五】反射

简介: 每个类都有一个 Class对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。

反射

每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。

1. Class类

获取一个类的Class对象的三种方式

// 每个类都有一个隐含的静态变量
Class c1 = Apple.class;
// 通过实例化对象的getClass()方法
Apple apple = new Apple();
Class c2 = apple.getClass();
// 通过类的全限定名
Class c3 = Class.forName("com.myf.pojo.Apple");

判断是否是某个类的实例

我们可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:

public native boolean isInstance(Object obj);

通过反射生成对象

使用Class对象的newInstance()方法来创建Class对象对应类的实例。

下面示例使用的是有参构造,默认调用无参构造orangeClass.getDeclaredConstructor().newInstance()。Class.newInstance()方法在java9之后被Deprecated不推荐了。

Orange orange = new Orange("莫逸风");
Class<? extends Orange> orangeClass = orange.getClass();
Orange orange1 = orangeClass.getDeclaredConstructor(String.class).newInstance("莫逸风");

示例实体:

class Orange {
    String name;

    public Orange(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
2. java.lang.reflect

Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

  • Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
  • Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
  • Constructor :可以用 Constructor 的 newInstance() 创建新的对象。
3. Class API:
  • Field[] getFields():返回一个包含Field对象的数组,该数组包含这个类或其超类的公有域。
  • Field[] getDeclaredFields():返回这个类的全部域。如果类型没有成员变量则返回长度为0的数组。
  • Method[] getMethods():返回包含Method对象的数组,该数组包含这个类或其超类的公有方法。
  • Method[] getDeclaredMethods():返回这个类或接口的全部方法,但不包括由超类继承的方法(公有方法也没有)。
  • Constructor<?>[] getConstructors():类的所有公有有构造器
  • Constructor<?>[] getDeclaredConstructors():类的所有构造器
3. Field:
  • Object get(Object obj):获取变量的值,入参为实例对象。

    Orange orange = orangeClass.getDeclaredConstructor(String.class).newInstance("莫逸风");
    Field[] fields = orangeClass.getDeclaredFields();
    Object o = fields[0].get(orange);
    System.out.println(o);    //莫逸风
  • void set(Object obj, Object value):设置变量的值。

    fields[0].set(orange,"莫逸雪");
    Object o = fields[0].get(orange);
    System.out.println(o);    //莫逸雪
  • Class<?> getType():返回属性的类型。

    Class<?> aClass = fields[0].getType();
    System.out.println(aClass==String.class);  //true
  • void setAccessible(boolean flag):设置属性的访问权限。

    如果我们将上述示例属性值改为private,则在get,set反射操作变量时会报IllegalAccessException异常。在操作之前设置setAccessible(true)可以解决这个问题。

    fields[0].setAccessible(true);
  • String getName():返回变量名称。

    String name = fields[0].getName();
    System.out.println(name);        //name
4. Method:
  • void setAccessible(boolean flag):设置方法的访问权限。
  • String getName():返回方法名称。
  • <T extends Annotation> T getAnnotation(Class<T> annotationClass):如果存在,返回对应的注解

    没找到合适测试的注解,自定义一个

    @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Tag {
        String value();
    }
    
    // Orange的getName方法添加此注解
    @Tag("设置名称")
    public String getName() {
      return name;
    }
    
    Method[] methods = orangeClass.getMethods();
    Tag annotation = methods[0].getAnnotation(Tag.class);
    System.out.println(annotation.value()); //设置名称
  • Annotation[] getAnnotations():内部实现是调用getDeclaredAnnotations
  • Annotation[] getDeclaredAnnotations():返回方法上的注解,忽略继承的注解,如果没有直接存在的注解返回长度为0的注解。
  • Object invoke(Object obj, Object... args):执行方法。

    Orange orange = orangeClass.getDeclaredConstructor(String.class).newInstance("莫逸风");
    methods[1].invoke(orange1,"莫逸雪");
    Object invoke = methods[0].invoke(orange1);
    System.out.println(invoke);  //莫逸雪
5. Constructor:
  • T newInstance(Object ... initargs):使用构造方法创建对象。
  • Class<T> getDeclaringClass():获取所属类的Class对象。

    Class<? extends Orange> orangeClass = orange.getClass();
    Class<?> declaringClass = constructors[0].getDeclaringClass();
    System.out.println(declaringClass==orangeClass); // true
  • void setAccessible(boolean flag):设置构造器的访问权限。
  • int getModifiers():返回一个用于描述构造器、方法或域的修饰符的整形数值。使用
6. Modifier:
// Orange中添加第二个变量
public static String test;

int modifiers = fields[1].getModifiers();
System.out.println(modifiers);                                                    // 9
System.out.println(Modifier.toString(modifiers));                // public static
System.out.println(Modifier.isAbstract(modifiers));            // false
System.out.println(Modifier.isFinal(modifiers));                // false
System.out.println(Modifier.isInterface(modifiers));        // false
System.out.println(Modifier.isNative(modifiers));                // false
System.out.println(Modifier.isPrivate(modifiers));            // false
System.out.println(Modifier.isProtected(modifiers));        // false
System.out.println(Modifier.isPublic(modifiers));                // true
System.out.println(Modifier.isStatic(modifiers));                // true
System.out.println(Modifier.isStrict(modifiers));                // false
System.out.println(Modifier.isSynchronized(modifiers));    // false
System.out.println(Modifier.isVolatile(modifiers));            // false
  • static String toString(int mod):返回对应的修饰符
  • static boolean isAbstract(int modifiers)
  • static boolean isFinal(int modifiers)
  • static boolean isInterface(int modifiers)
  • static boolean isNative(int modifiers)
  • static boolean isPrivate(int modifiers)
  • static boolean isProtected(int modifiers)
  • static boolean isPublic(int modifiers)
  • static boolean isStatic(int modifiers)
  • static boolean isStrict(int modifiers)
  • static boolean isSynchronized(int modifiers)
  • static boolean isVolatile(int modifiers)
7. 结语

由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。

另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

目录
相关文章
|
17天前
|
监控 Java
Java基础——反射
本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
|
1月前
|
Java
Java的反射
Java的反射。
26 2
|
2月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
27 0
[Java]反射
|
3月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
67 9
Java——反射&枚举
|
2月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 2
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
17 0
|
3月前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。
|
3月前
|
存储 安全 Java
扫盲java基础-反射(一)
扫盲java基础-反射(一)
|
3月前
|
Java
扫盲java基础-反射(二)
扫盲java基础-反射(二)