Java基本知识-反射

Java反射在java.lang.reflect包中,具有分析类的能力,可以检查类的结构。

1. 反射

反射之所以被称为框架的灵魂,主要是因为它赋予了在运行时分析类以及执行类中方法的能力。

通过反射可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

1.1. 应用场景

Spring,Spring Boot,MyBatis等框架中大量使用了反射机制

而框架中大量使用的注解也用到了反射。

为什么使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?

这些都是因为基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。

1.2. 案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class User{
private String name;
public int age;
public void setName(String name) {this.name = name;}
public String getName() {return name;}
public User(String name) {this.name = name;}
@Override
public String toString() {
return "User{"name='" + name + '\'' +, age=" + age +'}';
}
}

@Test
void testSystem() throws Exception {
//获取class对象
Class c = User.class;

//获取构造器
Constructor con = c.getConstructor(String.class);
//实例化
Object user = (User)con.newInstance("A");
//User{name='A', age=0}
System.out.println(user);

//获取对象中的属性元素
Field na = c.getDeclaredField("name");
//屏蔽访问检查
na.setAccessible(true);
na.set(user,"B");
//B
System.out.println(na.get(user));

Field age = c.getField("age");
age.set(user,18);
//User{name='A', age=18}
System.out.println(user);

//获取指定方法-getName()
Method getName = c.getMethod("getName");
//调用方法
String name = (String)getName.invoke(user);
//A
System.out.println(name);
}

2. 获取class实例

java.lang.class

允许程序在运行时进行自我检查,同时也允许对其内部的成员进行操作。得到一个对象所属的类,获取一个类的所有成员变量和方法,在运行时创建对象,调用对象的方法。

获取class类(专门的java类访问运行时类型信息):

  1. class.forName(“包名.类名”);

  2. 类名.class;

  3. 实例.getClass()

  4. ClassLoader.loadClass(“包名.类名”)

    通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一些列步骤,静态块和静态对象不会得到执行

实例化:必须有public的无参构造器,class.newInstance()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//调用运行时类的属性
Class c1 = User.class;
//通过运行时类的对象
Class c2 = new User().getClass();
//调用class的静态方法
Class c3 = Class.forName("com.runaccepted.online.admin.User");

//true
System.out.println(c1==c2);
//true
System.out.println(c2==c3);

//使用类的加载器
ClassLoader classLoader = SimpleTests.class.getClassLoader();
Class<?> c4 = classLoader.loadClass("com.runaccepted.online.admin.User");

//true
System.out.println(c3==c4);

3. 哪些类型可以有class对象

  1. class:外部类,成员内部类,静态内部类,局部内部类,匿名内部类

  2. interface:接口

    1
    Class c = Comparable.class;
  3. []:数组

    1
    2
    3
    4
    int[] arr = new int[10];
    Class<? extends int[]> arrClass = arr.getClass();

    Class c = String[].class;
  4. enum:枚举

    1
    Class<Enum> e = Enum.class;
  5. annotation:注解@interface

    1
    Class user = Override.class;
  6. primitive type:基本数据类型

    1
    Class<Integer> i = Integer.class;
  7. void

    1
    Class<Void> v = Void.class;

4. 分析类

java.lang.reflect

setAccessible(true) 所有域设置为可访问,屏蔽访问检查

4.1. Field域

获取Field对象方式:

  • getFields() 当前运行时类及其父类中声明为public访问权限的属性
  • getDeclaredFields() 运行时类的所有属性,不包含父类,包含private
  • getField(String name) 返回指定名称的属性

Field可用操作:

  • get(Object) 返回对象中属性的值

  • getType() 属性的类型

  • getModifiers() 属性权限修饰符 public class Modifier

    权限
    default 0
    public 1
    private 2
    protected 4
    static 8
    final 10
    synchronized 20
    volatile 40
    transient 80
    native 100
    interface 200
    abstract 400
    enum 4000
    synthetic 1000
    mandated 8000

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class User{
//4
protected int age;
//25
public static final String name="";
//2
private String password;
//0
int status;
}

@Test
void testSystem() throws Exception {
Class c = User.class;

Field[] fields = c.getDeclaredFields();
for (Field f:fields) {
System.out.println(f.getName()+" "+f.getModifiers());
}
}

4.2. Method方法

  • Method[] getMethods() 当前运行时类及其父类中声明为public访问权限的方法

  • Method[] getDeclaredMethods() 当前运行时类的所有属性,不包含父类,包含private

  • Method getDeclaredMethod(方法名,参数类型) 所有定义的方法

  • Class[] getReturnType() 返回值类型

  • Annotation[] getDeclaredAnnotations() 方法上的所有注解

  • Class[] getParameterTypes() 方法行参列表

  • Class[] getExceptionTypes 方法异常列表

  • Method getMethod(函数名,参数)

    1
    Math.class.getMethod("sqrt",double.class);
  • invoke(Object obj, Object… args) 调用当前对象中的方法

    1
    2
    3
    Employee c = new Employee("A");
    Method m = Employee.class.getMethod("getName");
    String str = (String)m.invoke(c);

4.3. Constructor构造器

  • getConstructors() 当前运行时类中声明为public的构造器
  • getConstructor(Class<?>… parameterTypes) 带参数的构造器
  • getDeclaredContructors() 所有构造器
  • getParameterTypes() 参数类型 Class[]
  • Type getGenericSuperclass() 泛型父类
  • Type getSuperclass() 父类

4.3.1. 得到父类的泛型

getGenericSuperclass()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Father<T>{
}
class User extends Father<String>{}

@Test
void testSystem() throws Exception {
Class c = User.class;
Type superclass = c.getGenericSuperclass();
//com.runaccepted.online.admin.Father<java.lang.String>
System.out.println(superclass);
ParameterizedType type = (ParameterizedType) superclass;
Type[] types = type.getActualTypeArguments();
for (Type t:types) {
//class java.lang.String
System.out.println(t);
//java.lang.String
System.out.println(t.getTypeName());

Class ct = (Class)t;

Constructor con = ct.getDeclaredConstructor(String.class);
String aaa = (String)con.newInstance("ABC");
//C
System.out.println(aaa.substring(2));
}
}
本文结束  感谢您的阅读
  • 本文作者: Wang Ting
  • 本文链接: /zh-CN/2019/09/20/Java基本知识-反射/
  • 发布时间: 2019-09-20 06:08
  • 更新时间: 2021-12-31 22:50
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!