Posts java反射详解
Post
Cancel

java反射详解

1. hashcode

留个坑,等到 java 容器那里再重写。 2021.10.03 填坑。

  1. 重写 hashcode 方法
1
2
3
4
5
6
    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = result*17 + id.hashCode();
        return result;
    }
  1. 为什么要重写 hashcode 方法?
  • 查找对象比较快 假设,在一个 List 中存储了一万个对象,如何找到一个与给定对象相等的对象? 直接比较 hashcode 值。 总之,hashcode 值一样,对象不一定相等,hashcode 值不一样,对象必定不相等。
  • Map 中存储的重复问题 往 map 中存储对象,如何判定对象是否相等 ? 依靠 hashmap 值。
  1. 顺带留一个重写 equals 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   public boolean equals(Object obj) {
        if( ! (obj instanceof User)){
            return false;
        }

        User user = (User) obj;

//        1.
        if (this == user){
            return true;
        }

//        2.
        if(user.name.equals(this.name) && user.id.equals(this.id)){
            return true;
        }else {
            return false;
        }

java 内存 内存模型

留第二个坑 , 下次填。

2. Class 类

2.1 Class 的常见方法

p1

2.2 Class 示例

要想使用反射,首先需要获得待操作的类所对应的 Class 对象。Java 中,无论生成某个类的多少个对象,这些对象都会对应于同一个 Class 对象。这个 Class 对象是由 JVM 生成的,通过它能够获悉整个类的结构。

1
2
3
4
5
6
7
8
9
10
11
//        方法一: 通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);

//        方法二:通过类名.class获得
        Class c2 = Person.class;
        System.out.println(c2);

//        获得父类类型
        Class c3 = c1.getSuperclass();
        System.out.println(c3);

步骤说明:

  1. JVM 加载方法的时候,遇到 new User(),JVM 会根据 User 的全限定名去加载 User.class
  2. JVM 会去本地磁盘查找 User.class 文件并加载 JVM 内存中。
  3. JVM 通过调用类加载器自动创建这个类对应的 Class 对象,并且存储在 JVM 的方法区。注意:一个类有且只有一个 Class 对象

2.3 Class 常见方法示范

在各个方法中,在方法名中加 Declared 的是返回所有的,不加 Declared 的只返回 public 访问权限

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
45
46
47
48
49
50
51
52
        Person person = new Student();
        System.out.println("这个人是"+person.name);
        System.out.println("============================");

        Class c1 = person.getClass();
        String name = c1.getName();    // 获得包名加类名
        System.out.println(name);
        String simpleName = c1.getSimpleName();
        System.out.println(simpleName);  //  获得类名

        System.out.println("==================================");
//        获得类的属性值
        Field[] fields = c1.getFields();   // 只能找到public属性
        for (Field field : fields) {
            System.out.println(field);
        }

        Field[] fields1 = c1.getDeclaredFields();   //  不管共有属性或者私有属性都能找到
        for (Field field : fields1) {
            System.out.println(field);
        }

        Field age = c1.getDeclaredField("age");  // 获得指定的属性值
        System.out.println(age);

        System.out.println("==================================");
        System.out.println("获得类的方法");

        Method[] methods = c1.getMethods();   // 获得本类以及父类的所有public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("==================================");
        Method[] methods1 = c1.getDeclaredMethods();   // 获得本类的所有方法,不管共有私有。
        for (Method method : methods1) {
            System.out.println(method);
        }
        System.out.println("==================================");
        Method method1 = c1.getMethod("method2", null);  // 获得指定方法,因为重载的原因,要加上方法参数。
        System.out.println(method1);

        System.out.println("==================================");
        Constructor[] constructors = c1.getConstructors();    // 获得public类的构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        Constructor[] declaredConstructors = c1.getDeclaredConstructors();  // 返回所有的构造器
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

3.反射

3.1 有了 Class,可以做什么?

动态的创建对象执行

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
        // 1.获得一个对象
        Class aClass = Class.forName("com.xm.User11");

        // 2. 无参构造对象
        User11 user = (User11) aClass.newInstance();  // 本质上通过无参构造器构造,如果没有无参构造器,改方法报错。
        System.out.println(user);
        // 2.2 有参构造器构造
        Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class, String.class, int.class);
        User11 instance = (User11) declaredConstructor.newInstance("周杰伦", "123", 33);
        System.out.println(instance);
        System.out.println("=========================");


        //3. 通过反射调用普通方法
        User11 user11 = (User11) aClass.newInstance();   // 实例化对象
        Method setName = aClass.getDeclaredMethod("setName", String.class); // 获取一个方法
        setName.invoke(user11, "林俊杰");
        System.out.println(user11);
        System.out.println("=======================");

        //4.通过反射操作属性
        User11 user1111 = (User11) aClass.newInstance();
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);   // 不能直接操作私有属性,需要关闭安全检测
        name.set(user1111,"周杰伦1111111111");
        System.out.println(user1111);

3.2 反射操作泛型

这个用的不是很多,暂略。

3.3 反射与注解

如果没有反射机制,那么注解跟注释的意义相差并不大

自定义注解,模拟 entity 实体类与数据库字段自动匹配。

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package com.xm;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class test5 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.xm.Student3");

        // 通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        System.out.println("----------------------");

//        获得注解的value值
        TableDb annotation = (TableDb) c1.getAnnotation(TableDb.class);
        System.out.println(annotation.value());
        System.out.println("----------------------");
        // 获得属性的注解值
        Field name = c1.getDeclaredField("name");
        FileDb annotation1 = name.getAnnotation(FileDb.class);
        System.out.println(annotation1);


    }
}



@TableDb("student")
class Student3{
    @FileDb(columnName = "name",type = "varchar",length = 5)
    private String name;
    @FileDb(columnName = "id",type = "varchar",length = 5)
    private int id;
    @FileDb(columnName = "pwd",type = "varchar",length = 5)
    private String pwd;

    public Student3(String name, int id, String pwd) {
        this.name = name;
        this.id = id;
        this.pwd = pwd;
    }

    public Student3() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "Student3{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}



// 类名注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableDb{
    String value() ;
}

// 属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FileDb{
    String columnName();
    String type();
    int length();
}
This post is licensed under CC BY 4.0 by the author.

Contents

Trending Tags