auto commit
This commit is contained in:
parent
1085339936
commit
8a14e463c0
320
notes/Java 基础.md
320
notes/Java 基础.md
@ -4,8 +4,10 @@
|
|||||||
* [static](#static)
|
* [static](#static)
|
||||||
* [二、Object 通用方法](#二object-通用方法)
|
* [二、Object 通用方法](#二object-通用方法)
|
||||||
* [概览](#概览)
|
* [概览](#概览)
|
||||||
* [clone()](#clone)
|
|
||||||
* [equals()](#equals)
|
* [equals()](#equals)
|
||||||
|
* [hashCode()](#hashcode)
|
||||||
|
* [toString()](#tostring)
|
||||||
|
* [clone()](#clone)
|
||||||
* [四、继承](#四继承)
|
* [四、继承](#四继承)
|
||||||
* [访问权限](#访问权限)
|
* [访问权限](#访问权限)
|
||||||
* [抽象类与接口](#抽象类与接口)
|
* [抽象类与接口](#抽象类与接口)
|
||||||
@ -154,6 +156,147 @@ public final void wait() throws InterruptedException
|
|||||||
protected void finalize() throws Throwable {}
|
protected void finalize() throws Throwable {}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## equals()
|
||||||
|
|
||||||
|
**1. equals() 与 == 的区别**
|
||||||
|
|
||||||
|
- 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
|
||||||
|
- 对于引用类型,== 判断两个实例是否引用同一个对象,而 equals() 判断引用的对象是否等价。
|
||||||
|
|
||||||
|
```java
|
||||||
|
Integer x = new Integer(1);
|
||||||
|
Integer y = new Integer(1);
|
||||||
|
System.out.println(x.equals(y)); // true
|
||||||
|
System.out.println(x == y); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. 等价关系**
|
||||||
|
|
||||||
|
(一)自反性
|
||||||
|
|
||||||
|
```java
|
||||||
|
x.equals(x); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
(二)对称性
|
||||||
|
|
||||||
|
```java
|
||||||
|
x.equals(y) == y.equals(x) // true
|
||||||
|
```
|
||||||
|
|
||||||
|
(三)传递性
|
||||||
|
|
||||||
|
```java
|
||||||
|
if(x.equals(y) && y.equals(z)) {
|
||||||
|
x.equals(z); // true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
(四)一致性
|
||||||
|
|
||||||
|
多次调用 equals() 方法结果不变
|
||||||
|
|
||||||
|
```java
|
||||||
|
x.equals(y) == x.equals(y); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
(五)与 null 的比较
|
||||||
|
|
||||||
|
对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
|
||||||
|
|
||||||
|
```java
|
||||||
|
x.euqals(null); // false;
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. 实现**
|
||||||
|
|
||||||
|
- 检查是否为同一个对象的引用,如果是直接返回 true;
|
||||||
|
- 检查是否是同一个类型,如果不是,直接返回 false;
|
||||||
|
- 将 Object 实例进行转型;
|
||||||
|
- 判断每个关键域是否相等。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class EqualExample {
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private int z;
|
||||||
|
|
||||||
|
public EqualExample(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
EqualExample that = (EqualExample) o;
|
||||||
|
|
||||||
|
if (x != that.x) return false;
|
||||||
|
if (y != that.y) return false;
|
||||||
|
return z == that.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## hashCode()
|
||||||
|
|
||||||
|
hasCode() 返回散列值,而 equals() 是用来判断两个实例是否相等。相等的两个实例散列值一定要相同,但是散列值相同的两个实例不一定相等。
|
||||||
|
|
||||||
|
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证相等的两个实例散列值也相等。
|
||||||
|
|
||||||
|
下面的代码中,新建了两个等价的实例,并将它们添加到 HashSet 中。我们希望将这两个实例当成一样的,只在集合中添加一个实例,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个实例的散列值是不同的,最终导致集合添加了两个等价的实例。
|
||||||
|
|
||||||
|
```java
|
||||||
|
EqualExample e1 = new EqualExample(1, 1, 1);
|
||||||
|
EqualExample e2 = new EqualExample(1, 1, 1);
|
||||||
|
System.out.println(e1.equals(e2)); // true
|
||||||
|
HashSet<EqualExample> set = new HashSet<>();
|
||||||
|
set.add(e1);
|
||||||
|
set.add(e2);
|
||||||
|
System.out.println(set.size()); // 2
|
||||||
|
```
|
||||||
|
|
||||||
|
理想的散列函数应当具有均匀性,即不相等的实例应当均匀分不到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来,可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。
|
||||||
|
|
||||||
|
一个数与 31 相乘可以转换成移位和减法:31\*x == (x<<5)-x。
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + x;
|
||||||
|
result = 31 * result + y;
|
||||||
|
result = 31 * result + z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## toString()
|
||||||
|
|
||||||
|
默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class ToStringExample {
|
||||||
|
private int number;
|
||||||
|
|
||||||
|
public ToStringExample(int number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
ToStringExample example = new ToStringExample(123);
|
||||||
|
System.out.println(example.toString());
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
ToStringExample@4554617c
|
||||||
|
```
|
||||||
|
|
||||||
## clone()
|
## clone()
|
||||||
|
|
||||||
**1. cloneable**
|
**1. cloneable**
|
||||||
@ -161,21 +304,48 @@ protected void finalize() throws Throwable {}
|
|||||||
clone() 是 Object 的受保护方法,这意味着,如果一个类不显式去重载 clone() 就没有这个方法。
|
clone() 是 Object 的受保护方法,这意味着,如果一个类不显式去重载 clone() 就没有这个方法。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class CloneTest {
|
public class CloneExample {
|
||||||
private int a;
|
private int a;
|
||||||
private int b;
|
private int b;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
CloneTest x = new CloneTest();
|
CloneExample e1 = new CloneExample();
|
||||||
CloneTest y = x.clone(); // 'clone()' has protected access in 'java.lang.Object'
|
CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'
|
||||||
```
|
```
|
||||||
|
|
||||||
接下来重载 Object 的 clone() 得到以下实现:
|
接下来重载 Object 的 clone() 得到以下实现:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class CloneTest{
|
public class CloneExample {
|
||||||
|
private int a;
|
||||||
|
private int b;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CloneExample clone() throws CloneNotSupportedException {
|
||||||
|
return (CloneExample)super.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
CloneExample e1 = new CloneExample();
|
||||||
|
try {
|
||||||
|
CloneExample e2 = e1.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
java.lang.CloneNotSupportedException: CloneTest
|
||||||
|
```
|
||||||
|
|
||||||
|
以上抛出了 CloneNotSupportedException,这是因为 CloneTest 没有实现 Cloneable 接口。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CloneExample implements Cloneable {
|
||||||
private int a;
|
private int a;
|
||||||
private int b;
|
private int b;
|
||||||
|
|
||||||
@ -186,44 +356,130 @@ public class CloneTest{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
|
||||||
CloneTest x = new CloneTest();
|
|
||||||
try {
|
|
||||||
CloneTest y = (CloneTest) x.clone();
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
java.lang.CloneNotSupportedException: CloneTest
|
|
||||||
```
|
|
||||||
|
|
||||||
以上抛出了 CloneNotSupportedException,这是因为 CloneTest 没有实现 Cloneable 接口。应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
|
|
||||||
|
|
||||||
**2. 深拷贝与浅拷贝**
|
**2. 深拷贝与浅拷贝**
|
||||||
|
|
||||||
- 浅拷贝:拷贝对象和原对象的引用类型引用同一个对象;
|
- 浅拷贝:拷贝实例和原始实例的引用类型引用同一个对象;
|
||||||
- 深拷贝:引用不同对象。
|
- 深拷贝:拷贝实例和原始实例的引用类型引用不同对象。
|
||||||
|
|
||||||
实现深拷贝的方法:
|
```java
|
||||||
|
public class ShallowCloneExample implements Cloneable {
|
||||||
|
private int[] arr;
|
||||||
|
|
||||||
- [Defensive copying](http://www.javapractices.com/topic/TopicAction.do?Id=15)
|
public ShallowCloneExample() {
|
||||||
- [copy constructors](http://www.javapractices.com/topic/TopicAction.do?Id=12)
|
arr = new int[10];
|
||||||
- [static factory methods](http://www.javapractices.com/topic/TopicAction.do?Id=21).
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> [How do I copy an object in Java?](https://stackoverflow.com/questions/869033/how-do-i-copy-an-object-in-java)
|
public void set(int index, int value) {
|
||||||
|
arr[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
## equals()
|
public int get(int index) {
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
|
||||||
**1. == 与 equals() 区别**
|
@Override
|
||||||
|
protected ShallowCloneExample clone() throws CloneNotSupportedException {
|
||||||
|
return (ShallowCloneExample) super.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
|
```java
|
||||||
- 对于引用类型,== 判断两个引用是否引用同一个对象,而 equals() 判断引用的对象是否等价。
|
ShallowCloneExample e1 = new ShallowCloneExample();
|
||||||
|
ShallowCloneExample e2 = null;
|
||||||
|
try {
|
||||||
|
e2 = e1.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
e1.set(2, 222);
|
||||||
|
System.out.println(e2.get(2)); // 222
|
||||||
|
```
|
||||||
|
|
||||||
**2. 等价性**
|
```java
|
||||||
|
public class DeepCloneExample implements Cloneable {
|
||||||
|
private int[] arr;
|
||||||
|
|
||||||
> [散列](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Java%20%E5%AE%B9%E5%99%A8.md#%E4%B8%89%E6%95%A3%E5%88%977)
|
public DeepCloneExample() {
|
||||||
|
arr = new int[10];
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int index, int value) {
|
||||||
|
arr[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get(int index) {
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DeepCloneExample clone() throws CloneNotSupportedException {
|
||||||
|
DeepCloneExample result = (DeepCloneExample) super.clone();
|
||||||
|
result.arr = new int[arr.length];
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
result.arr[i] = arr[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
DeepCloneExample e1 = new DeepCloneExample();
|
||||||
|
DeepCloneExample e2 = null;
|
||||||
|
try {
|
||||||
|
e2 = e1.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
e1.set(2, 222);
|
||||||
|
System.out.println(e2.get(2)); // 2
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CloneConstructorExample {
|
||||||
|
private int[] arr;
|
||||||
|
|
||||||
|
public CloneConstructorExample() {
|
||||||
|
arr = new int[10];
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CloneConstructorExample(CloneConstructorExample original) {
|
||||||
|
arr = new int[original.arr.length];
|
||||||
|
for (int i = 0; i < original.arr.length; i++) {
|
||||||
|
arr[i] = original.arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int index, int value) {
|
||||||
|
arr[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get(int index) {
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
CloneConstructorExample e1 = new CloneConstructorExample();
|
||||||
|
CloneConstructorExample e2 = new CloneConstructorExample(e1);
|
||||||
|
e1.set(2, 222);
|
||||||
|
System.out.println(e2.get(2)); // 2
|
||||||
|
```
|
||||||
|
|
||||||
# 四、继承
|
# 四、继承
|
||||||
|
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
* [二、容器中的设计模式](#二容器中的设计模式)
|
* [二、容器中的设计模式](#二容器中的设计模式)
|
||||||
* [迭代器模式](#迭代器模式)
|
* [迭代器模式](#迭代器模式)
|
||||||
* [适配器模式](#适配器模式)
|
* [适配器模式](#适配器模式)
|
||||||
* [三、散列](#三散列)
|
* [三、源码分析](#三源码分析)
|
||||||
* [四、源码分析](#四源码分析)
|
|
||||||
* [ArrayList](#arraylist)
|
* [ArrayList](#arraylist)
|
||||||
* [Vector](#vector)
|
* [Vector](#vector)
|
||||||
* [LinkedList](#linkedlist)
|
* [LinkedList](#linkedlist)
|
||||||
@ -15,7 +14,7 @@
|
|||||||
* [LinkedHashMap](#linkedhashmap)
|
* [LinkedHashMap](#linkedhashmap)
|
||||||
* [ConcurrentHashMap - JDK 1.7](#concurrenthashmap---jdk-17)
|
* [ConcurrentHashMap - JDK 1.7](#concurrenthashmap---jdk-17)
|
||||||
* [ConcurrentHashMap - JDK 1.8](#concurrenthashmap---jdk-18)
|
* [ConcurrentHashMap - JDK 1.8](#concurrenthashmap---jdk-18)
|
||||||
* [五、参考资料](#五参考资料)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
@ -102,51 +101,7 @@ List list = Arrays.asList(arr);
|
|||||||
List list = Arrays.asList(1,2,3);
|
List list = Arrays.asList(1,2,3);
|
||||||
```
|
```
|
||||||
|
|
||||||
# 三、散列
|
# 三、源码分析
|
||||||
|
|
||||||
hasCode() 返回散列值,使用的是对象的地址。
|
|
||||||
|
|
||||||
而 equals() 是用来判断两个对象是否相等的,相等的两个对象散列值一定要相同,但是散列值相同的两个对象不一定相等。
|
|
||||||
|
|
||||||
相等必须满足以下五个性质:
|
|
||||||
|
|
||||||
**1. 自反性**
|
|
||||||
|
|
||||||
```java
|
|
||||||
x.equals(x); // true
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. 对称性**
|
|
||||||
|
|
||||||
```java
|
|
||||||
x.equals(y) == y.equals(x) // true
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. 传递性**
|
|
||||||
|
|
||||||
```java
|
|
||||||
if(x.equals(y) && y.equals(z)) {
|
|
||||||
x.equals(z); // true;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**4. 一致性**
|
|
||||||
|
|
||||||
多次调用 equals() 方法结果不变
|
|
||||||
|
|
||||||
```java
|
|
||||||
x.equals(y) == x.equals(y); // true
|
|
||||||
```
|
|
||||||
|
|
||||||
**5. 与 null 的比较**
|
|
||||||
|
|
||||||
对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
|
|
||||||
|
|
||||||
```java
|
|
||||||
x.euqals(null); // false;
|
|
||||||
```
|
|
||||||
|
|
||||||
# 四、源码分析
|
|
||||||
|
|
||||||
建议先阅读 [算法-查找](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E6%9F%A5%E6%89%BE) 部分,对容器类源码的理解有很大帮助。
|
建议先阅读 [算法-查找](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E6%9F%A5%E6%89%BE) 部分,对容器类源码的理解有很大帮助。
|
||||||
|
|
||||||
@ -745,7 +700,7 @@ JDK 1.8 的实现不是用了 Segment,Segment 属于重入锁 ReentrantLock。
|
|||||||
|
|
||||||
并且 JDK 1.8 的实现也在链表过长时会转换为红黑树。
|
并且 JDK 1.8 的实现也在链表过长时会转换为红黑树。
|
||||||
|
|
||||||
# 五、参考资料
|
# 参考资料
|
||||||
|
|
||||||
- Eckel B. Java 编程思想 [M]. 机械工业出版社, 2002.
|
- Eckel B. Java 编程思想 [M]. 机械工业出版社, 2002.
|
||||||
- [Java Collection Framework](https://www.w3resource.com/java-tutorial/java-collections.php)
|
- [Java Collection Framework](https://www.w3resource.com/java-tutorial/java-collections.php)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user