1. hashcode
留个坑,等到 java 容器那里再重写。 2021.10.03 填坑。
- 重写 hashcode 方法
1
2
3
4
5
6
@Override
public int hashCode() {
int result = name.hashCode();
result = result*17 + id.hashCode();
return result;
}
- 为什么要重写 hashcode 方法?
- 查找对象比较快 假设,在一个 List 中存储了一万个对象,如何找到一个与给定对象相等的对象? 直接比较 hashcode 值。 总之,hashcode 值一样,对象不一定相等,hashcode 值不一样,对象必定不相等。
- Map 中存储的重复问题 往 map 中存储对象,如何判定对象是否相等 ? 依靠 hashmap 值。
- 顺带留一个重写 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 的常见方法
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);
步骤说明:
- JVM 加载方法的时候,遇到
new User()
,JVM 会根据User
的全限定名去加载User.class
。 - JVM 会去本地磁盘查找
User.class
文件并加载 JVM 内存中。 - 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();
}