Java反射(通过反射获取构造函数、方法、属性)

简介: 1.通过反射获取构造函数,2.通过反射获取方法,3.通过反射调用成员属性



1.通过反射获取构造函数

Class类获取构造函数的方法如下:

方法名 作用
getConstructor(Class<?>... parameterTypes) 获取指定参数类型的公共构造函数
getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型的构造函数,可以是公共、私有或受保护的构造函数
getConstructors() 获取所有公共构造函数
getDeclaredConstructors() 获取所有构造函数,可以是公共、私有或受保护的构造函数

所有通过Class类获取到的构造函数都需要用到java.lang.reflect.Constructor类的对象来接收

以下是Constructor类的常用方法:

方法名 作用
newInstance(Object... initargs) 使用此构造函数对象创建一个新对象
getParameterTypes() 获取构造函数的参数类型数组
getModifiers() 获取构造函数的修饰符
getName() 获取构造函数的名称
getExceptionTypes() 获取构造函数声明抛出的异常类型数组
isAccessible() 检查构造函数是否可访问
setAccessible(boolean flag) 设置构造函数的可访问性

案例代码:

package Example1705;
import java.lang.reflect.Constructor;
class Member{
    private String str;
    Member(){
        System.out.println("无参构造");
    }
    Member(String str){
        this.str = str;
        System.out.println("单参构造方法");
    }
    Member(String str, int i,double d){
        System.out.println("多参数构造方法");
    }
    @Override
    public String toString() {
        return "Member{" +
                "str='" + str + '\'' +
                '}';
    }
}
public class javaDemo {
    public static void main(String[] args) throws  Exception{
        Class<?> clazz= Member.class;
        Constructor<?>[] cons = clazz.getDeclaredConstructors();
//        输出类中所有构造函数
        for (Constructor<?> con:cons) {
            System.out.println(con);
        }
//        获取单参构造方法
        Constructor<?> one = clazz.getDeclaredConstructor(String.class);
        Object obj = one.newInstance("我是你爷爷");
        System.out.println(obj);
    }
}

image.gif

image.gif编辑

问1:什么是构造函数的修饰符

答1:构造函数的修饰符是指用来修饰构造函数访问级别和特性的关键字。在Java中,构造函数可以使用以下修饰符:public、protected、private和默认(无修饰符)。这些修饰符决定了外部是否可以访问该构造函数以及哪些代码可以使用它来创建对象。

    • public修饰符表示构造函数对所有类可见,可以被任意代码调用。
    • protected修饰符表示构造函数对同一包内的类和所有子类可见,可以被同包内的类和子类调用。
    • private修饰符表示构造函数只对本类可见,只能在本类中调用。
    • 默认(无修饰符)表示构造函数对同一包内的类可见,但对其他包中的类不可见,只能在同包内调用。

    问2:为什么代码:

    Constructor<?> one = clazz.getDeclaredConstructor(String.class);

    里面参数是String.class而不是直接String,那么如果调用int ,char,double又该如何表示呢?

    答2:代码Constructor<?> one = clazz.getDeclaredConstructor(String.class);中的参数是String.class而不是直接String,是因为Java中的反射API通过.class来获取类的Class对象。.class是Java语言用于获取类的Class对象的语法,可以用于获取各种类型的Class对象。

    如果要调用的构造函数具有int、char、double等基本数据类型的参数,可以使用相应的包装类的.class来表示,例如:

      • int:int.class
      • char:char.class
      • double:double.class

      通过使用包装类的.class,可以获取对应基本数据类型的Class对象,并在获取构造函数时进行使用。


      2.通过反射获取方法

      Class类获取方法信息的方法如下:

      方法 作用
      getDeclaredMethods() 获取当前类声明的所有方法,包括公共、保护、默认和私有方法。
      getMethods() 获取当前类以及从父类继承的公共方法。
      getDeclaredMethod(String name, Class<?>... parameterTypes) 获取指定名称和参数类型的方法,包括私有方法。
      getMethod(String name, Class<?>... parameterTypes) 获取指定名称和参数类型的公共方法,包括从父类继承的方法。

      同样Class获取的方法都需要通过java.lang.reflect.Method类对象来接收

      以下是Method类的常用方法:

      方法 作用
      getName() 获取方法的名称。
      getReturnType() 获取方法的返回类型。
      getParameterTypes() 获取方法的参数类型数组。
      getModifiers() 获取方法的访问修饰符,返回一个整数值,可以使用Modifier类的方法解析该值。例如,可以使用Modifier.isPublic(modifiers)检查方法是否为public。
      isVarArgs() 检查方法是否使用可变参数。
      isAccessible() 检查方法是否可访问(即是否可以通过反射调用)。
      invoke(Object obj, Object... args) 调用方法,传入特定的对象作为方法的所有者,以及方法的参数。
      setAccessible(boolean flag) 设置方法的可访问性。如果设置为true,则可以绕过Java语言访问权限检查,强制访问私有方法。
      getAnnotation(Class<T> annotationClass) 获取方法上指定注解类型的注解对象。
      getDeclaredAnnotations() 获取方法上声明的所有注解对象的数组。
      getExceptionTypes() 获取方法声明的异常类型数组。
      getDefaultValue() 获取方法的默认值(仅适用于接口方法)。
      isDefault() 检查方法是否为默认方法(在接口中定义的具有默认实现的方法)。
      getParameterCount() 获取方法的参数个数。

      案例代码:

      package Example1707;
      import java.lang.reflect.Method;
      import java.lang.reflect.Modifier;
      class Test{
          public void FUnction1(){}
          public String Function2(){
              return "调用return type为String函数";
          }
          private void Function3(){
              System.out.println("private修饰符的方法");
          }
          private String Funtion4(){
              return "私有化返回String的函数";
          }
      }
      public class javaDemo {
          public static void main(String[] args) {
              Class<?> clazz = Test.class;
              Method methods[] = clazz.getDeclaredMethods();
              for (Method m:methods) {
      //            输出修饰符
                  int x = m.getModifiers();
                  System.out.println(Modifier.toString(x)+" "+m.getReturnType().getSimpleName()+" "+m.getName()+"()");
              }
          }
      }

      image.gif

      image.gif编辑

      问1:在类中构造方法是否也算是其中的方法,在代码中定义构造函数是否也会被输出?

      构造方法也算作类中的一种方法。在使用反射获取类的所有方法时,构造方法也会被包含在内,并可以通过反射的方式获取和操作。

      在你提供的示例代码中,使用反射获取了 Test 类的所有方法,并输出了每个方法的修饰符、返回类型和名称。注意,这里的方法包括普通方法和构造方法。

      所以,如果 Test 类中定义了构造方法,那么在你的示例代码中输出部分会包含构造方法的信息。构造方法的输出格式与普通方法相同,只是返回类型是 void,方法名与类名相同。

      如果你想要单独输出构造方法的信息,可以通过判断 Method 对象是否为构造方法来实现。可以使用 m.getName().equals("<init>") 来判断一个方法是否是构造方法(构造方法的特点是方法名为 <init>)。


      3.通过反射调用成员属性

      通过反射获取成员属性与一般获取并不相同,一般来说当一个成员的属性的修饰符为private私有后在主类之中并不能进行调用。但是通过反射是可以得到将私有化的成员属性的

      下面介绍Class类获取类中成员属性的方法:

      方法 描述
      getDeclaredFields() 返回类中所有声明的成员属性(不包括继承的属性),包括公共、受保护、默认(包)访问和私有属性。
      getDeclaredField(String name) 根据属性名获取类中指定的成员属性(不包括继承的属性),包括私有属性。
      getField(String name) 根据属性名获取类中指定的公共成员属性(包括继承的公共属性),无法获取私有属性。

      和前面都一样对于class获取到的成员属性,需要用java.lang.reflect.Field类的实例进行接收

      下面介绍Field类的常用方法:

      方法 描述
      Class<?> getType() 返回属性的类型。返回值为 Class 对象,可以使用 getName() 方法获取类的名称。
      void set(Object obj, Object value) 设置给定对象上此属性的值。
      Object get(Object obj) 获取给定对象上此属性的值。
      int getModifiers() 返回属性的修饰符。可以通过 java.lang.reflect.Modifier 类的静态方法来解析修饰符的信息。
      void setAccessible(boolean flag) 设置访问标志,使得私有属性可被访问。

      案例:

      package Example1708;
      import java.lang.reflect.Field;
      class Person{
          public String name;
          private int age;
          public String sex;
      }
      class Student extends Person{
          private String School;
      }
      public class javaDemo {
          public static void main(String[] args) throws Exception{
      //        输出School中的成员属性
              Class<?> clazz= Student.class;
              Field fields[] = clazz.getDeclaredFields();
              for (Field f:fields) {
                  System.out.println(f);
              }
      //        输出子类父类其中的成员属性
              Class<?> parent = clazz.getSuperclass();
              Field fieldss[] = parent.getDeclaredFields();
              for (Field f:fieldss) {
                  System.out.println(f);
              }
              Object obj = clazz.getDeclaredConstructor().newInstance();
              Field secreat = clazz.getDeclaredField("School");
      //        设置私有允许访问
              secreat.setAccessible(true);
              secreat.set(obj,"东方红小学");
              System.out.println(secreat.get(obj));
          }
      }

      image.gif

      image.gif编辑

      注意:在实际的项目开发过程中很少有直接使用反射来对成员进行操作的,而一般都会用setter,getter方法。但是在项目开发过程中getType方法是用得比较多的,用来确定属性类型,下面是案例代码

      假设有一个名为 Person 的类,它具有属性 nameage

      public class Person {
          private String name;
          private int age;
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
          public int getAge() {
              return age;
          }
          public void setAge(int age) {
              this.age = age;
          }
      }

      image.gif

      在使用反射时,可以使用 getType 方法来获取属性的类型。例如,我们想要获取 Person 类中的所有属性的类型:

      import java.lang.reflect.Field;
      public class ReflectionExample {
          public static void main(String[] args) {
              Person person = new Person();
              Class<? extends Person> clazz = person.getClass();
              Field[] fields = clazz.getDeclaredFields();
              for (Field field : fields) {
                  Class<?> fieldType = field.getType();
                  System.out.println("属性名:" + field.getName());
                  System.out.println("属性类型:" + fieldType.getName());
                  System.out.println("-------------------------");
              }
          }
      }

      image.gif

      以上代码使用反射获取了 Person 类中的所有属性,并打印出了每个属性的名称和类型。


      目录
      相关文章
      |
      2月前
      |
      消息中间件 Java Kafka
      在Java中实现分布式事务的常用框架和方法
      总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
      |
      17天前
      |
      移动开发 前端开发 Java
      Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
      JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
      Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
      |
      16天前
      |
      Java 数据库连接 Spring
      反射-----浅解析(Java)
      在java中,我们可以通过反射机制,知道任何一个类的成员变量(成员属性)和成员方法,也可以堆任何一个对象,调用这个对象的任何属性和方法,更进一步我们还可以修改部分信息和。
      |
      1月前
      |
      JSON 前端开发 JavaScript
      Java属性为什么不能是is开头的boolean
      在Java实体类中,阿里规约要求boolean属性不应以is开头。文章通过实际案例分析了isUpdate字段在JSON序列化过程中变为update的问题,并提供了自定义get方法或使用@JSONField注解两种解决方案,建议遵循规约避免此类问题。
      Java属性为什么不能是is开头的boolean
      |
      2月前
      |
      安全 Java 开发者
      Java中WAIT和NOTIFY方法必须在同步块中调用的原因
      在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
      51 4
      |
      2月前
      |
      Java
      深入探讨Java中的中断机制:INTERRUPTED和ISINTERRUPTED方法详解
      在Java多线程编程中,中断机制是协调线程行为的重要手段。了解和正确使用中断机制对于编写高效、可靠的并发程序至关重要。本文将深入探讨Java中的`Thread.interrupted()`和`Thread.isInterrupted()`方法的区别及其应用场景。
      72 4
      |
      2月前
      |
      Java 数据处理 数据安全/隐私保护
      Java处理数据接口方法
      Java处理数据接口方法
      29 1
      |
      2月前
      |
      监控 Java
      Java基础——反射
      本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
      Java反射 - 构造函数
      Java反射——构造函数 使用Java反射,您可以检查类的构造函数,并在运行时实例化对象。 这是通过Java类java.lang.reflect.Constructor完成的。
      830 0
      |
      5天前
      |
      监控 Java
      java异步判断线程池所有任务是否执行完
      通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
      44 17