官方文档:
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html 反射(reflect)就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等),操作字节码文件,也可以操作代码片段。
作用:
基本作用:可以得到一个类的全部成分然后操作。
可以破坏封装性。
最重要的用途是:适合做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);
//输出:李磊在唱歌~