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类来调用对象的构造函数。

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

目录
相关文章
|
5天前
|
安全 Java API
Java反射(Reflection)的技术性文章
Java反射(Reflection)的技术性文章
20 1
|
21天前
|
Java C++
Java反射的简单使用
Java反射的简单使用
25 3
|
21天前
|
Java
【专栏】Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性
【4月更文挑战第27天】本文探讨了Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性。反射通过Class、Constructor、Method和Field类实现。文中列举了反射的应用场景,如动态创建对象、调用方法、访问属性和处理注解,并提供了相关实例代码演示。
|
4天前
|
缓存 安全 Java
【Java——反射机制详解】
RTTI(Run-Time Type Identification)运行时类型识别。在《Thinking in Java》一书第十四章中有提到,其作用是在运行时识别一个对象的类型和类的信息。主要有两种方式:一种是“传统的”RTTI,它假定我们在编译时已经知道了所有的类型;另一种是“反射”机制,它允许我们在运行时发现和使用类的信息。 反射就是把java类中的各种成分映射成一个个的Java对象 例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
|
6天前
|
JSON Java 数据库连接
Java的反射
Java的反射
|
19天前
|
安全 Java API
JAVA-不安全的反射--RCE
JAVA不安全的反射造成的RCE小案例
|
21天前
|
SQL 存储 Java
【Java反射详解】
【Java反射详解】
16 1
|
21天前
|
Java
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识
【5月更文挑战第2天】JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识。入坑JAVA因它的面向对象特性、平台无关性、强大的标准库和活跃的社区支持。
43 2
|
21天前
|
Java 测试技术
滚雪球学Java(24):Java反射
【4月更文挑战第13天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 0
滚雪球学Java(24):Java反射
|
21天前
|
Java
Java 反射
Java 反射