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) 设置构造函数的可访问性


image.gif

案例代码:

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 问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() 获取方法的参数个数。

案例代码:

packageExample1707;
importjava.lang.reflect.Method;
importjava.lang.reflect.Modifier;
classTest{
publicvoidFUnction1(){}
publicStringFunction2(){
return"调用return type为String函数";
    }
privatevoidFunction3(){
System.out.println("private修饰符的方法");
    }
privateStringFuntion4(){
return"私有化返回String的函数";
    }
}
publicclassjavaDemo {
publicstaticvoidmain(String[] args) {
Class<?>clazz=Test.class;
Methodmethods[] =clazz.getDeclaredMethods();
for (Methodm:methods) {
//            输出修饰符intx=m.getModifiers();
System.out.println(Modifier.toString(x)+" "+m.getReturnType().getSimpleName()+" "+m.getName()+"()");
        }
    }
}

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 注意:在实际的项目开发过程中很少有直接使用反射来对成员进行操作的,而一般都会用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 类中的所有属性,并打印出了每个属性的名称和类型。

目录
相关文章
|
JSON Java Apache
Bean自动映射工具对比及VO、DTO、PO、DO对象之间的转换
在实际的开发过程中,常常遇到各个层之间对象转换,比如 VO、DTO、PO、DO 等,而如果都是手动set、get,一旦属性较多时,操作起来不仅麻烦,而且浪费时间,因此经常会使用一些工具类,进行对象之间的转换,下面将对象与对象之间转换的方式进行对比,一级对象间的使用进行总结。
Bean自动映射工具对比及VO、DTO、PO、DO对象之间的转换
|
开发框架 Java 数据库
java----包的命名规范
对包的解释与命名规则
10570 0
java----包的命名规范
|
11月前
|
缓存 安全 Java
java 为什么 String 在 java 中是不可变的?
本文探讨了Java中String为何设计为不可变类型,从字符串池的高效利用、哈希码缓存、支持其他对象的安全使用、增强安全性以及线程安全等方面阐述了不可变性的优势。文中还通过具体代码示例解释了这些优点的实际应用。
265 1
java 为什么 String 在 java 中是不可变的?
|
11月前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
2287 10
|
12月前
|
存储 NoSQL 算法
面试官:Redis 大 key 多 key,你要怎么拆分?
本文介绍了在Redis中处理大key和多key的几种策略,包括将大value拆分成多个key-value对、对包含大量元素的数据结构进行分桶处理、通过Hash结构减少key数量,以及如何合理拆分大Bitmap或布隆过滤器以提高效率和减少内存占用。这些方法有助于优化Redis性能,特别是在数据量庞大的场景下。
面试官:Redis 大 key 多 key,你要怎么拆分?
|
JavaScript 前端开发 Java
SpringBoot配置文件 —— 超详细全方位教程
本文是一篇关于SpringBoot配置文件的超详细全方位教程,涵盖了配置文件的作用、SpringBoot中的配置文件格式、优先级、properties和yml配置文件的详解及语法、读取配置文件的方法、转义字符和单双引号的使用、配置对象、集合和Map,以及yml的优缺点。
1598 0
SpringBoot配置文件 —— 超详细全方位教程
|
前端开发 小程序 Java
【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅
本文详细介绍了如何在SpringBoot项目中统一处理接口返回结果及全局异常。首先,通过封装`ResponseResult`类,实现了接口返回结果的规范化,包括状态码、状态信息、返回信息和数据等字段,提供了多种成功和失败的返回方法。其次,利用`@RestControllerAdvice`和`@ExceptionHandler`注解配置全局异常处理,捕获并友好地处理各种异常信息。
6365 0
【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅
|
Java 数据库连接 mybatis
成功解决: Invalid bound statement (not found) 在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决
这篇文章讨论了在已使用MyBatis的项目中引入MyBatis-Plus后出现的"Invalid bound statement (not found)"错误,并提供了解决方法,主要是通过修改yml配置文件来解决MyBatis和MyBatis-Plus共存时的冲突问题。
成功解决: Invalid bound statement (not found) 在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决
|
数据采集 人工智能 Serverless
AI 克隆声音,只需 3 分钟(附最全教程)
文章介绍了GPT-Sovits,一个开源的生成式语音模型,因其在声音克隆上的高质量和简易性而受到关注。阿里云函数计算(Function Compute)提供了一个快速托管GPT-Sovits的方法,让用户无需管理服务器即可体验和部署该模型。通过函数计算,用户可以便捷地搭建基于GPT-Sovits的文本到语音服务,并享受到按需付费和弹性扩展的云服务优势。此外,文章还列举了GPT-Sovits在教育、游戏、新能源等多个领域的应用场景,并提供了详细的步骤指导,帮助用户在阿里云上部署和体验GPT-Sovits模型。
36590 8