• 官方文档:https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html

  • 反射(reflect)就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等),操作字节码文件,也可以操作代码片段

  • 作用:

    1. 基本作用:可以得到一个类的全部成分然后操作。

    2. 可以破坏封装性。

    3. 最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。

初始化

这里先定义一个用于测试的实体类:

这里用了lombok的三个注解,具体作用如下所示。

@NoArgsConstructor(access = AccessLevel.PUBLIC)  // 为Albums类生成一个无参构造器,访问权限为public。
@AllArgsConstructor(access = AccessLevel.PUBLIC) // 为Albums类生成一个全参数构造器,访问权限为public。
@Data // 为Albums类提供常见的getter、setter方法,还包括equals、hashCode和toString方法。
public class Albums{
    private String albumsName; // 专辑名称
    private String artist; // 艺术人
    private String albumsInfo; // 简介
    private int songsNum; // 歌曲数量
    public void write(){
      System.out.println("写作~");
    }

    public void sing() {
        System.out.println("唱歌~");
    }
    
    public String sing(String name){
        return name + "在唱歌~";
    }
}

1.加载类,获取类的字节码:Class对象

@Test
public void Test1Class() throws ClassNotFoundException {
    // 1.任何类型的.class
    Class albumsClass1 = Albums.class;
    System.out.println(albumsClass1); // albumsClass的引用地址
    //输出:class com.reflect.Albums
    System.out.println(albumsClass1.getName()); // 全类名
    //输出:com.reflect.Albums
    System.out.println(albumsClass1.getSimpleName()); // 类名
    //输出:Albums

    // 2.Class.forName(全类名)
    Class albumsClass2 =  Class.forName("com.reflect.Albums");
    System.out.println(albumsClass1 == albumsClass2);
    //输出:true

    // 3.对象.getClass()
    Albums albums = new Albums();
    Class albumsClass3 = albums.getClass();
    System.out.println(albumsClass2 == albumsClass3);
    //输出:true
}

2.获取类的构造器:Constructor对象

获取类的构造器,并对其进行操作

@Test
public void testGetConstructors(){
    Class albumsClass = Albums.class;
    //获取类的全部构造器
//        Constructor[] constructors = albumsClass.getConstructors(); 注意构造器只能public修饰,否则找不到!!!
    Constructor[] constructors = albumsClass.getDeclaredConstructors();
    for(Constructor<?> constructor : constructors){
        System.out.println(constructor.getName() +
                " ---> " + constructor.getParameterCount());
    }
}
// 输出:com.reflect.Albums ---> 0  可以看到拿到了无参构造
//       com.reflect.Albums ---> 4  这是全参构造
@Test
public void testGetConstructor() throws Exception {
    Class albumsClass = Albums.class;
    //获取无参构造器
//        Constructor constructor = albumsClass.getConstructor(); 注意构造器只能public修饰,否则找不到!!!
    Constructor constructor1 = albumsClass.getDeclaredConstructor();
    System.out.println(constructor1.getName() +
            " ---> " + constructor1.getParameterCount());
    System.out.println("=======================================");
    
    //获取全参构造器
    Constructor constructor2 = albumsClass.
            getDeclaredConstructor(String.class,String.class,String.class,int.class);
    System.out.println(constructor2.getName() +
            " ---> " + constructor2.getParameterCount());
}
//输出:com.reflect.Albums ---> 0
//=======================================
//     com.reflect.Albums ---> 4

获取类构造器的作用:依然是初始化对象返回

这里我重新定义了构造器内容。

public Albums(){
    System.out.println("这是无参构造器");
}

public Albums(String albumsName, String artist, String albumsInfo, int songsNum){
    System.out.println("这是全参数构造器");
    this.albumsName = albumsName;
    this.artist = artist;
    this.albumsInfo = albumsInfo;
    this.songsNum = songsNum;
}

正常调用:

Albums albums1 = new Albums();
Albums albums2 = new Albums("albums1","artist1","albumsInfo1",1);

使用反射:

//constructor1是获取到的无参构造器   
  constructor1.setAccessible(true); //暴力反射
  Albums albums1 = (Albums) constructor1.newInstance();
  System.out.println(albums1);
//输出:
//  这是无参构造器
//  Albums(albumsName=null, artist=null, albumsInfo=null, songsNum=0)

//constructor2是获取到的全参构造器  
  constructor2.setAccessible(true);
  Albums albums2 = constructor2.newInstance("albums1","artist1","albumsInfo1",1);
  System.out.println(albums2);
// 输出:
//  这是全参数构造器
//  Albums(albumsName=albums1, artist=artist1, albumsInfo=albumsInfo1, songsNum=1)

没有开启暴力反射,那么构造器的访问权限不能设置成private,否则就报错:

3.获取类的成员变量:Field对象

获取类的成员变量

@Test
public void testGetField() throws Exception{
    Class albumsClass = Albums.class;
    // 获取类的全部成员对象
    Field[] declaredFields = albumsClass.getDeclaredFields();

    // 遍历这个数组,获取每个成员对象
    for(Field field : declaredFields){
        System.out.println(field.getName() + "---->" + field.getType());
    }
//输出:albumsName---->class java.lang.String
//    artist---->class java.lang.String
//    albumsInfo---->class java.lang.String
//    songsNum---->int

    // 获取类的某个成员变量
    Field fName = albumsClass.getDeclaredField("albumsName");
    System.out.println(fName.getName() + "---->" + fName.getType());
//输出: albumsName---->class java.lang.String
}

获取到成员变量的作用:依然是赋值、取值。

正常调用:

Albums albums = new Albums();
albums.setAlbumsName("albums2");
String albumsName = albums.getAlbumsName();

使用反射:

// 设置值
Albums albums = new Albums();
fName.setAccessible(true);
fName.set(albums,"albums2");

// 获取值
String name = (String) fName.get(albums);

4.获取类的成员方法:Method对象

Class提供了从类中获取成员方法的API

// 获取类的全部方法
Method[] declaredMethods = albumsClass.getDeclaredMethods();

// 获取某个方法对象
Method sing1 = albumsClass.getDeclaredMethod("sing"); // 无参数拿sing方法
//输出:sing---->0---->void

Method sing2 = albumsClass.getDeclaredMethod("sing", String.class); // 有参拿sing方法
//输出:sing---->1---->class java.lang.String

成员方法的作用:依然是执行

正常调用:

Albums albums = new Albums();
albums.write();
String li = albums.sing("李磊");

使用反射:

Albums albums = new Albums();
Method write = albumsClass.getDeclaredMethod("write");
Method sing = albumsClass.getDeclaredMethod("sing", String.class);

write.setAccessible(true); // 暴力反射,不设置时注意方法的访问权限不能是private!
Object invoke1 = write.invoke(albums); // 调用无参方法write,用albums对象触发调用。
//输出:写作~

sing.setAccessible(true);
String invoke2 = sing.invoke(albums,"李磊").toString();
System.out.println(invoke2);
//输出:李磊在唱歌~

参考来自:04、Java高级技术:反射_哔哩哔哩_bilibili