Java-Day-10
Object 常用类
equals 方法
-
== 与 equals
-
== 是一个比较运算符
- 既可以判断基本类型,又可以判断引用类型
- 如果判断基本类型,判断的是值是否相等
- 如果判断引用类型,判断的就是地址是否相同,即判断是否是一个对象
-
equals 是 Object 类中的方法,只能判断引用类型
- 默认判断的是地址是否相等 ( Object 里的 equals 可以看源码分析,实际就是 == ),但子类中往往重写该方法,用于判断内容是否相等 ( String、Integer 里的 equals 是重写了 Object 源码里的 equals )
-
例:
Person p1 = new Person(); p1.name = "zhu"; Person p2 = new Person(); p2.name = "zhu"; System.out.println(p1 == p2); // F System.out.println(p1.name.equals(p2.name)); // T System.out.println(p1.equals(p2)); // F,因为Person对象没对equals方法重写
-
-
Object 里的 equals
public boolean equals(Object obj) { return (this == obj); }
仿 String 重写 — 能判断 Person 类的属性相等的话对象 equals 就返回 true
public boolean equals(Object obj) { // 两者同一个对象,就一定是true if(this == obj){ return true; } if(obj instanceof Person){ // 向下转型,因为想要得到 obj 的各个属性 Person p = (Person)obj; return this.name.equals(p.name) && this.age == p.age; } return false; } // main中初始化过了的person1和2 System.out.println(person1.equals(person2));
-
小练习
int n1 = 65; float n2 = 65.0f; System.out.println(it == fl); // T,值相等 char ch1 = 'A'; char ch2 = 65; System.out.println(ch1 == ch2); // T,A的ASCII码为65 String str1 = new String("hello"); String str2 = new String("hello"); System.out.println(str1.equals(str2)); // T,因为String重写了此方法,值相等也可以true
hashCode 方法
-
集合部分再详细讲解
-
暂且需要记住的结论
-
作用是为了提高具有哈希结构的容器的效率
-
两个引用,如果指向的是同一个对象,则哈希值肯定是一样的
-
两个引用,如果指向的是不同对象,则哈希值是不一样的
-
哈希值主要根据地址来的 ( 针对不同的对象返回不同的整数 ),但不能等价于地址
// 查看某一对象的哈希值 System.out.println(对象名.hashCode());
-
在讲到集合的时候,需要的话也会重写 hashCode()
-
toString 方法
- 默认返回:全类名 + @ + 哈希值的十六进制
- 子类往往重写 toString 方法,用于返回对象的属性信息
- 一般可以直接在 alt + insert —> toString 方法直接导入方法,返回当前对象的所有属性名 + 值
- 当直接输出一个对象时,toString 方法会被默认的调用
finalize 方法
- 当对象被回收时,系统自动调用该对象的 finalize 方法
- 子类可以重写该方法,做一些释放资源的操作
- 什么时候被回收:当某个对象没有任何引用时 ( new 了的对象变成仅一个栈名头,无任何指向,可以理解为 = null 了时 ) ,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象 ( 把 new 时开辟的堆里的空间给销毁了,就可以重又能被分配了 ),在销毁该对象前,会先调用该对象的 finalize 方法 ( 默认 Object 类里的,也可以选择重写在里面编写自己的业务逻辑代码,比如释放资源:数据库连接、打开文件 ... )
- 但不是某一个对象变成垃圾后就会立即被 finalize 回收,那样要实时监控很麻烦,而是垃圾回收机制的调用是由系统来决定的,它自己自带一套算法 ( GC ),jvm 时细讲
- 但想要测试,一般情况下也可以通过 System.gc() 来主动触发垃圾回收机制,但 gc() 执行时不会造成阻塞,代码仍会继续往下走
- 但实际开发时,几乎不会运用 finalize
JDK 源码
-
用 IDEA 举例,一般来说 IDEA 配置好 JDK 后,jdk 的源码也就配置好了
-
如果没有的话点击菜单 File —> Project Structure —> SDKs —> Sourcepath 然后点击绿色加号加进去
-
在需要查看某个方法源码时,将光标放在该方法,ctrl + b 即可,或者在方法上点击右键 —> Go To —> Declaration or...
断点调试
(debug)
-
了解
- 断点调试一步一步看源码执行的过程,从而发现错误所在
- 断点调试过程中是运行状态,是以对象的运行类型来执行的
- 断点调试也能帮助我们查看 java 底层源代码的执行过程
-
快捷键
- F7 — 跳入 — 方法内
- F8 — 跳过 — 逐行执行代码
- shift + F8 — 跳出 — 跳出方法
- alt + shift + F7 — 强制跳入
- F9 — resume program — 执行到下一个断点
-
断点使用
-
左键单击出红点,即一个断点,可点出多个
-
右键 Debug
-
打开 Debug 页面
-
Debug 开始,F8 一步步执行,蓝底 — 到哪一行了 ( 运行的下一行 )
红底 — 断点行处
-
遇到 System 控制台输出语句就点击 Console 查看控制台
-
代码运行完成后就自行跳出 Debug
-
-
在 Debug 追源码
-
在某想要查看的方法所在行按 F7,若只是继续执行了此方法没进去方法源码就
-
alt + shift + F7 强制执行,就能进入所在行的方法的源码处了
-
Setting —> Build,Execution,Deployment —> Debugger —> Stepping —> Do not step into the classes 中取消勾选 java.* 和 javax.*,其他随意,Apply —> OK,就可进入源码了
-
-
有时 F7 进方法后,还有一层要再 F7 才能看到真正执行的方法所在,一直追到最里层的代码实现处
- F7 多层跳进后,要 shift + F8 才能一层层跳出返回到想要的那一层
-
-
F9 直接执行下一个断点
- 断点在 Debug 过程中可以动态地下断点
- 利用此动态下断点,可以在系统代码里下一个断点,F9 没能执行到所下断点处,即可判断代码不会执行所下断点处的代码,走的是另一条路,从而可以更好的理解复杂性代码
-
小练习
- 追踪对象创建的过程
- 对象 new 创建的代码行处下断点,F7 进入 ( 强制进入 ),到 loadClass 加载类方法处,跳出,再进入,就到构造器方法处, 默认初始化后进行显式初始化把属性值填入
- 跳入方法后记得跳出,跳入后可以再选择逐行执行
- 追踪动态访问机制
- 了然子父类方法调用与属性的变化
- 追踪对象创建的过程