Java反射

简介: Java反射

前言

框架通常借助设计模式、反射和配置文件等技术实现灵活的开发和可扩展性。今天我们就来了解反射这项技术。

一、反射概述

1.1 概念

Java中的反射是指在程序运行时检查、访问、修改变量、方法、调用构造函数的机制

Java中反射机制主要是由java.lang.Class类及其相关方法以及java.lang.reflect包中的Field、Method、Constructor类和访问控制相关类构成的。

1.2 作用

(1)可以在运行时动态地获取类、接口、方法、属性等对象的信息,实现了代码和数据的分离,增加了程序的灵活性和可扩展性。

(2)可以在运行时动态地创建对象、调用方法、操作属性,尤其使用在框架的开发中,可以通过反射机制灵活的使用已经存在的类库、组件库等。

(3)可以实现一些基于注解的编程技术,例如通过注解定义一些特定的属性信息,然后可以使用反射机制在程序运行时动态地读取和处理这些注解信息。

(4)反射机制可以实现一些基本Java中无法实现的特殊操作,例如通过反射机制访问私有成员,执行私有方法,实现单例模式等。

二、类类

Java中的类类是指java.lang.Class类,是Java反射机制的核心类之一。类类表示Java程序中的一个类或接口。

2.1常用方法

方法 描述
getName() 返回类的名称,包括包名
getSimpleName() 返回类的简单名称,不包括包名
getModifiers() 返回类的修饰符,例如public、private、static等
getPackage() 返回类所在的包
getFields() 返回类或接口的public字段
getDeclaredFields() 返回类或接口声明的所有字段,包括私有字段
getMethods() 返回类或接口的public方法
getDeclaredMethods() 返回类或接口声明的所有方法,包括私有方法
getConstructors() 返回类的public构造器
getDeclaredConstructors() 返回类声明的所有构造器,包括私有构造器

2.2实例化类类

这里有个Student类

package com.xqx.reflect;
public class Student {
  private String sid;
  private String sname;
  public Integer age;
  static {
    System.out.println("加载进jvm中!");
  }
  public Student() {
    super();
    System.out.println("调用无参构造方法创建了一个学生对象");
  }
  public Student(String sid) {
    super();
    this.sid = sid;
    System.out.println("调用带一个参数的构造方法创建了一个学生对象");
  }
  public Student(String sid, String sname) {
    super();
    this.sid = sid;
    this.sname = sname;
    System.out.println("调用带二个参数的构造方法创建了一个学生对象");
  }
  @SuppressWarnings("unused")
  private Student(Integer age,String sname) {
    System.out.println("调用Student类私且多参的构造方法创建一个学生对象");
    this.age = age;
    this.sname = sname;
  }
  public String getSid() {
    return sid;
  }
  public void setSid(String sid) {
    this.sid = sid;
  }
  public String getSname() {
    return sname;
  }
  public void setSname(String sname) {
    this.sname = sname;
  }
  public void hello() {
    System.out.println("你好!我是" + this.sname);
  }
  public void hello(String name) {
    System.out.println(name + "你好!我是" + this.sname);
  }
  @SuppressWarnings("unused")
  private Integer add(Integer a, Integer b) {
    return new Integer(a.intValue() + b.intValue());
  }
}

2.2.1Class.forName()

这个方法可以根据给定的类名获取对应的Class对象

Class c = Class.forName("com.xqx.reflect.Student");

2.2.2getClass()

该方法可以返回当前对象的类的Class对象。例如

Student stu=new Student();
      Class class1 = stu.getClass();

2.2.3类名.class

Class c1=Student.class;
System.out.println(c);
      System.out.println(c1);
      System.out.println(class1);

打印结果:

class com.xqx.reflect.Student
class com.xqx.reflect.Student
class com.xqx.reflect.Student

2.2.4创建类实例

获取了类的Class对象之后,就可以使用Class.newInstance()方法来创建类实例:

//一切反射从类类开始
    Class c = Class.forName("com.xqx.reflect.Student");
    //创建类实例 无参实例化
    Student stu = (Student) c.newInstance();

需要注意的是,newInstance()方法只能创建无参构造函数的类对象,如果存在有参构造函数,则需要使用Constructor类来创建类实例。同时,在Java 9中,newInstance()方法已被废弃,建议使用Class.getDeclaredConstructor()方法代替。

三、反射属性

通过Field类来获取对象的属性,也可以获取到私有属性,还可以设置属性的值。

3.1公有属性的获取与赋值

getDeclaredField()方法获取属性、get()方法打印获取到属性的值、set()方法为熟悉赋值

Student student = new Student();
    student.setSid("s001");
    student.setSname("xqx");
    student.age=18;
    //一切反射从类类开始
    Class<? extends Student> c = student.getClass();
    //获取到公有属性age
    Field ageField = c.getDeclaredField("age"); 
    System.out.println("修改前:"+ageField.get(student));
    ageField.set(student, 16);
    System.out.println("修改后:"+ageField.get(student));

打印结果:

加载进jvm中!
调用无参构造方法创建了一个学生对象
修改前:18
修改后:16

3.2私有属性的获取与赋值

获取与赋值方法跟公有属性一致,但必须打开权限setAccessible才可调用,否则报错

//拿到私有属性
    Field idField = c.getDeclaredField("sid");
    Field nameField = c.getDeclaredField("sname");
    //打开私有属性访问权限
    idField.setAccessible(true);
    nameField.setAccessible(true);
    System.out.println("修改前:"+idField.get(student));
    //修改
    idField.set(student, "s110");
    System.out.println("修改后:"+idField.get(student));
    System.out.println("修改前:"+nameField.get(student));
    nameField.set(student, "nb");
    System.out.println("修改后:"+nameField.get(student));

打印结果:

修改前:s001
修改后:s110
修改前:xqx
修改后:nb

3.3 获取所有属性

//拿到所有字段
    Field[] fields = c.getDeclaredFields();
    for (Field field : fields) {
      field.setAccessible(true);
      //拿到所有字段名、值
      System.out.println(field.getName() + ":" + field.get(student));
    }

打印结果:

sid:s110
sname:nb
age:16

3.4获取修饰符

Class类的getModifiers()方法可以返回一个int类型的修饰符,这个修饰符是由多个常量值通过位运算组合而成的。获取修饰符可以帮助我们更方便地了解一个类的特性,从而更好地理解并使用该类。

//拿到所有字段
    Field[] fields = c.getDeclaredFields();
    for (Field field : fields) {
      field.setAccessible(true);
      int modifiers = field.getModifiers();
      if (Modifier.isPublic(modifiers)) {
        System.out.println("public:"+field.getName());
        System.out.println("public修饰符的常量值:"+modifiers);
      }
      if (Modifier.isPrivate(modifiers)) {
        System.out.println("private:"+field.getName());
        System.out.println("private修饰符的常量值:"+modifiers);
      }
    }

打印结果:

private:sid
private修饰符的常量值:2
private:sname
private修饰符的常量值:2
public:age
public修饰符的常量值:1

四、反射方法

4.1 获取公有无参方法

// 一切反射从类类开始
    Class<Student> c = Student.class;
    // 创建类实例
    Student stu = (Student) c.newInstance();
    //获取无参方法  hello是方法名
    Method m = c.getMethod("hello");
    //调用方法
    Object invoke = m.invoke(stu);
    System.out.println(invoke);

打印结果:

加载进jvm中!
调用无参构造方法创建了一个学生对象
你好!我是null
null

4.2 获取公有一参方法

//获取有参方法  hello是方法名 String.class是参数类型
    Method m2 = c.getMethod("hello", String.class);
    //调用方法 stu是类实例  "nb"是要传的参数
    Object invoke2 = m2.invoke(stu, "nb");
    System.out.println(invoke2);

打印结果:

nb你好!我是null
null

4.3 获取私有多参方法

跟调用私有属性一样,必须打开访问权限setAccessible

//获取私有多参方法  add是方法名 Integer.class是参数类型
    Method m3 = c.getDeclaredMethod("add", Integer.class, Integer.class);
    // 打开访问权限
    m3.setAccessible(true);
    //调用方法 stu是类实例  22、33是要传的参数
    Object invoke3 = m3.invoke(stu, 22, 33);
    System.out.println(invoke3);

打印结果:

55

五、反射构造函数

5.1获取无参

//一切反射从类类开始
    Class c = Class.forName("com.xqx.reflect.Student");
    //创建类实例 无参实例化
    Student stu = (Student) c.newInstance();
    System.out.println(stu);

打印结果:

加载进jvm中!
调用无参构造方法创建了一个学生对象
com.xqx.reflect.Student@33909752

5.2 获取公有有参

//获取有参构造
    Constructor c1 =c.getConstructor(String.class);
    Student stu2 = (Student)c1.newInstance("s001");
    System.out.println(stu2);

打印结果:

调用带一个参数的构造方法创建了一个学生对象
com.xqx.reflect.Student@55f96302

5.3获取私有多参

//私有
    Constructor c3 =c.getDeclaredConstructor(Integer.class,String.class);
    //打开访问权限
    c3.setAccessible(true);
    Student stu4 = (Student)c3.newInstance(120,"xqx");
    System.out.println(stu4);

打印结果:

调用Student类私且多参的构造方法创建一个学生对象
com.xqx.reflect.Student@42a57993

六、总结

反射机制的基本步骤如下:

(1)获取Class对象。可以通过多种方式来获取Class对象,比如Class.forName()、Object.getClass()以及类字面常量等。

(2)创建实例对象。获取Class对象后,可以使用Class.newInstance()方法来创建类实例对象。

(3)获取或设置对象的属性。通过Field类来获取对象的属性,可以获取私有属性,也可以设置属性的值。

(4)调用对象的方法。通过Method类来获取对象的方法,可以获取私有方法,也可以调用方法。

(5)调用对象的构造函数。通过Constructor类来调用对象的构造函数。

好啦,今天的分享就到此为止!希望你看完本篇文章有所收获,祝你变得更强、未来出“粽”!!!

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