【笔记】Java的反射

前言

Java的反射学习笔记

获取类对象

通过类名获取类对象

1
2
3
class Cls {}

Class<Cls> clazz = Cls.class;

通过类的全局限定名获取类对象

1
2
3
class Cls {}

Class<?> clazz = Class.forName("com.example.Cls");

通过对象获取类对象

1
2
3
4
class Cls {}
Cls cls = new Cls();

Class<? extends Cls> clazz = cls.getClass();

基本类型获取类对象

1
2
3
4
Class<Integer> clazz1 = int.class;
Class<Integer> clazz2 = Integer.TYPE;

System.out.println(clazz1 == clazz2); // true
  • 基本类型的类对象和包装类的类对象不是相同的
1
2
3
4
Class<Integer> clazz1 = int.class;
Class<Integer> clazz2 = Integer.class;

System.out.println(clazz1 == clazz2); // false

获取viod类对象

1
Class<Void> clazz = void.class;
  • Void值只有null
1
Void v = null;

获取数组类对象

1
Class<int[]> clazz = int[].class;

多维数组

1
Class<int[][]> clazz = int[][].class;

类对象的实例方法

获取类对象名

获取类对象名

  • 除了数组类对象,其他类对象都返回类的全局限定名
1
String name = clazz.getName();

获取类对象简单名

  • 返回类名
1
String simpleName = clazz.getSimpleName();

获取类对象类型名

  • 返回类的全局限定名
1
String typeName = clazz.getTypeName();

类对象转换为实例对象

1
2
3
4
5
6
7
class Cls {}
Class<Cls> clazz = Cls.class;
Cls cls1 = new Cls();

Cls cls2 = clazz.cast(cls1);

System.out.println(cls1 == cls2); // true

获取子类类对象

1
Class<? extends Cls> subclass = clazz.asSubclass(Cls.class);

获取父类类对象

1
Class<? super Cls> superclass = clazz.getSuperclass();

包含泛型参数

1
Type genericSuperclass = clazz.getGenericSuperclass();

获取接口类对象数组

1
Class<?>[] interfaces = clazz.getInterfaces();

包含泛型参数

1
Type[] genericInterfaces = clazz.getGenericInterfaces();

通过类对象获取包对象

1
Package package = clazz.getPackage();

包对象的实例方法

获取包名

1
String name = package.getName();

直接通过类对象创建对象

  • 直接通过类对象创建对象时,只能使用类定义的无参构造器,如果无参构造器不存在则会报错
1
2
3
4
5
class Cls {
public Cls() {}
}

Cls cls = clazz.newInstance();

通过类对象获取构造器对象

通过构造器对象创建对象

无参构造

1
2
3
4
5
6
class Cls {
public Cls() {}
}

Constructor<Cls> constructor = clazz.getConstructor();
Cls cls = constructor.newInstance();
  • 强制使用私有构造器对象创建对象
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
class Cls {
private Cls() {}
}

Constructor<Cls> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Cls cls = constructor.newInstance();

有参构造

  • 在调用getConstructor()方法时指定形参类型
1
2
3
4
5
6
class Cls {
public Cls(String str) {}
}

Constructor<Cls> constructor = clazz.getConstructor(String.class);
Cls cls = constructor.newInstance();
  • 强制使用私有构造器对象创建对象
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
class Cls {
private Cls(String str) {}
}

Constructor<Cls> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Cls cls = constructor.newInstance();

构造器对象的实例方法

获取构造器名

1
String name = constructor.getName();

通过类对象获取方法对象

通过方法对象执行实例方法

无参方法

1
2
3
4
5
6
7
class Cls {
public void method() {}
}
Cls cls = new Cls();

Method method = clazz.getMethod("method");
method.invoke(cls);
  • 强制使用私有方法对象执行方法
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
8
class Cls {
private void method() {}
}
Cls cls = new Cls();

Method method = clazz.getDeclaredMethod("method");
method.setAccessible(true);
method.invoke(cls);

有参方法

  • 在调用getMethod()方法时指定形参类型
1
2
3
4
5
6
7
class Cls {
public void method(String str) {}
}
Cls cls = new Cls();

Method method = clazz.getMethod("method", String.class);
method.invoke(cls, "");
  • 强制使用私有方法对象执行方法
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
8
class Cls {
private void method(String str) {}
}
Cls cls = new Cls();

Method method = clazz.getDeclaredMethod("method", String.class);
method.setAccessible(true);
method.invoke(cls, "");
具有可变参数作为形参的方法
  • 通过数组匹配可变参数
1
2
3
4
5
6
7
class Cls {
public void method(String... str) {}
}
Cls cls = new Cls();

Method method = clazz.getMethod("method", String[].class);
method.invoke(cls, (Object) new String[]{""});

通过方法对象执行类方法

无参方法

1
2
3
4
5
6
class Cls {
public static void method() {}
}

Method method = clazz.getMethod("method");
method.invoke(null);
  • 强制使用私有方法对象执行方法
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
class Cls {
private static void method() {}
}

Method method = clazz.getDeclaredMethod("method");
method.setAccessible(true);
method.invoke(null);

有参方法

  • 在调用getMethod()方法时指定形参类型
1
2
3
4
5
6
class Cls {
public static void method(String str) {}
}

Method method = clazz.getMethod("method", String.class);
method.invoke(null, "");
  • 强制使用私有方法对象执行方法
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
class Cls {
private static void method(String str) {}
}

Method method = clazz.getDeclaredMethod("method", String.class);
method.setAccessible(true);
method.invoke(null, "");
具有可变参数作为形参的方法
  • 通过数组匹配可变参数
1
2
3
4
5
6
class Cls {
public static void method(String... str) {}
}

Method method = clazz.getMethod("method", String[].class);
method.invoke(null, (Object) new String[]{""});

方法对象的实例方法

获取方法名

1
String name = method.getName();

获取方法的返回值类型

1
Class<?> returnType = method.getReturnType();

通过类对象获取属性对象

通过属性对象获取属性值

1
2
3
4
5
6
7
class Cls {
public String field;
}
Cls cls = new Cls();

Field field = clazz.getField("field");
String value = (String) field.get(cls);
  • 强制获取私有属性对象属性值
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
8
class Cls {
private String field;
}
Cls cls = new Cls();

Field field = clazz.getDeclaredField("field");
field.setAccessible(true);
String value = (String) field.get(cls);

通过属性对象修改属性值

1
2
3
4
5
6
7
class Cls {
public String field;
}
Cls cls = new Cls();

Field field = clazz.getField("field");
field.set(cls, "");
  • 强制修改私有属性对象属性值,即便属性被final修饰
    • 通过setAccessible()方法设置权限
1
2
3
4
5
6
7
8
class Cls {
private String field;
}
Cls cls = new Cls();

Field field = clazz.getDeclaredField("field");
field.setAccessible(true);
field.set(cls, "");

通过类对象获取注解

获取类上定义的指定注解

1
Annotation annotation = clazz.getAnnotation(注解名.class);

获取类上定义的所有注解

1
Annotation[] annotations = clazz.getAnnotations();

获取方法上所有形参上定义的所有注解

1
Annotation[][] annotations = clazz.getMethodAnnotations();

类加载器

通过类对象获取类加载器

1
ClassLoader classLoader = clazz.getClassLoader();

获取父级类加载器

1
ClassLoader classLoader = clazz.getClassLoader().getParent();

通过自定义类加载器加载Java文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClassLoader extends ClassLoader {
/**
* 加载class文件
*
* @param name 类名
* @param file `.class`文件路径
* @return 类对象
*/
public Class<?> loadClassFile(String name, String file) {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

完成