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 类中的所有属性,并打印出了每个属性的名称和类型。


      目录
      相关文章
      |
      5天前
      |
      Java 编译器
      【Java开发指南 | 第十九篇】Java方法
      【Java开发指南 | 第十九篇】Java方法
      9 0
      |
      5天前
      |
      Java C++
      Java反射的简单使用
      Java反射的简单使用
      22 3
      |
      1天前
      |
      并行计算 Java API
      Java 8中的接口默认方法和静态方法以及并行数组
      【5月更文挑战第19天】Java 8引入了许多新特性,其中包括接口的默认方法和静态方法,以及并行数组的能力。这些特性增强了Java的面向对象编程模型和数组处理能力。让我们深入了解它们的概念和实践。
      19 2
      |
      1天前
      |
      Java 编译器
      滚雪球学Java(34):探究Java方法的神奇魔法和参数传递奥秘
      【5月更文挑战第9天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
      10 1
      滚雪球学Java(34):探究Java方法的神奇魔法和参数传递奥秘
      |
      3天前
      |
      Java
      Java中int[]与Integer[]相互转化的方法,java基础知识面试重点总结
      Java中int[]与Integer[]相互转化的方法,java基础知识面试重点总结
      |
      3天前
      |
      安全 Java API
      JAVA-不安全的反射--RCE
      JAVA不安全的反射造成的RCE小案例
      |
      5天前
      |
      Java
      Java String 避免空指针的方法
      Java String 避免空指针的方法
      5 0
      |
      5天前
      |
      Java 编译器
      【Java开发指南 | 第十七篇】Java 方法
      【Java开发指南 | 第十七篇】Java 方法
      8 1
      |
      5天前
      |
      Java
      【Java开发指南 | 第九篇】访问实例变量和方法、继承、接口
      【Java开发指南 | 第九篇】访问实例变量和方法、继承、接口
      14 4
      |
      5天前
      |
      XML JavaScript Java
      详解Java解析XML的四种方法
      详解Java解析XML的四种方法
      16 1