Skip to content

Commit f7097e0

Browse files
committed
Merge branch 'nobytecode'
2 parents fe7fb20 + 7118317 commit f7097e0

File tree

4 files changed

+222
-127
lines changed

4 files changed

+222
-127
lines changed

docs/sidebar/sanfene/collection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1217,7 +1217,7 @@ for (String s : set) {
12171217

12181218
HashSet 会自动去重,因为它是用 HashMap 实现的,HashMap 的键是唯一的(哈希值),相同键的值会覆盖掉原来的值,于是第二次 set.add("沉默") 的时候就覆盖了第一次的 set.add("沉默")。
12191219

1220-
![HashSet套娃](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/collection-36.png)
1220+
![三分恶面渣逆袭:HashSet套娃](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/collection-36.png)
12211221

12221222
#### HashSet 和 ArrayList 的区别
12231223

docs/sidebar/sanfene/javase.md

Lines changed: 126 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -866,16 +866,97 @@ Object 类提供的 clone()方法可以非常简单地实现对象的浅拷贝
866866

867867
### 30.Java 创建对象有哪几种方式?
868868

869-
Java 中有以下四种创建对象的方式:
869+
![三分恶面渣逆袭:Java创建对象的四种方式](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javase-16.png)
870870

871-
![Java创建对象的四种方式](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javase-16.png)
871+
Java 有四种创建对象的方式:
872872

873-
- new 创建新对象
874-
- 通过反射机制
875-
- 采用 clone 机制
876-
- 通过序列化机制
873+
①、new 关键字创建,这是最常见和直接的方式,通过调用类的构造方法来创建对象。
877874

878-
前两者都需要显式地调用构造方法。对于 clone 机制,需要注意浅拷贝和深拷贝的区别,对于序列化机制需要明确其实现原理,在 Java 中序列化可以通过实现 Externalizable 或者 Serializable 来实现。
875+
```java
876+
Person person = new Person();
877+
```
878+
879+
②、反射机制创建,反射机制允许在运行时创建对象,并且可以访问类的私有成员,在框架和工具类中比较常见。
880+
881+
```java
882+
Class clazz = Class.forName("Person");
883+
Person person = (Person) clazz.newInstance();
884+
```
885+
886+
③、clone 拷贝创建,通过 clone 方法创建对象,需要实现 Cloneable 接口并重写 clone 方法。
887+
888+
```java
889+
Person person = new Person();
890+
Person person2 = (Person) person.clone();
891+
```
892+
893+
④、序列化机制创建,通过序列化将对象转换为字节流,再通过反序列化从字节流中恢复对象。需要实现 Serializable 接口。
894+
895+
```java
896+
Person person = new Person();
897+
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
898+
oos.writeObject(person);
899+
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
900+
Person person2 = (Person) ois.readObject();
901+
```
902+
903+
904+
#### new子类的时候,子类和父类静态代码块,构造方法的执行顺序
905+
906+
在 Java 中,当创建一个子类对象时,子类和父类的静态代码块、构造方法的执行顺序遵循一定的规则。这些规则主要包括以下几个步骤:
907+
908+
1. 首先执行父类的静态代码块(仅在类第一次加载时执行)。
909+
2. 接着执行子类的静态代码块(仅在类第一次加载时执行)。
910+
3. 再执行父类的构造方法。
911+
4. 最后执行子类的构造方法。
912+
913+
下面是一个详细的代码示例:
914+
915+
```java
916+
class Parent {
917+
// 父类静态代码块
918+
static {
919+
System.out.println("父类静态代码块");
920+
}
921+
922+
// 父类构造方法
923+
public Parent() {
924+
System.out.println("父类构造方法");
925+
}
926+
}
927+
928+
class Child extends Parent {
929+
// 子类静态代码块
930+
static {
931+
System.out.println("子类静态代码块");
932+
}
933+
934+
// 子类构造方法
935+
public Child() {
936+
System.out.println("子类构造方法");
937+
}
938+
}
939+
940+
public class Main {
941+
public static void main(String[] args) {
942+
new Child();
943+
}
944+
}
945+
```
946+
947+
执行上述代码时,输出结果如下:
948+
949+
```
950+
父类静态代码块
951+
子类静态代码块
952+
父类构造方法
953+
子类构造方法
954+
```
955+
956+
- 静态代码块:在类加载时执行,仅执行一次,按父类-子类的顺序执行。
957+
- 构造方法:在每次创建对象时执行,按父类-子类的顺序执行,先初始化块后构造方法。
958+
959+
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东面经同学 2 后端面试原题:new子类的时候,子类和父类静态代码块,构造方法的执行顺序
879960
880961
GitHub 上标星 10000+ 的开源知识库《[二哥的 Java 进阶之路](https://github.com/itwanger/toBeBetterJavaer)》第一版 PDF 终于来了!包括 Java 基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM 等等,共计 32 万余字,500+张手绘图,可以说是通俗易懂、风趣幽默……详情戳:[太赞了,GitHub 上标星 10000+ 的 Java 教程](https://javabetter.cn/overview/)
881962

@@ -1715,45 +1796,63 @@ while (!result.isDone()) {
17151796

17161797
### 45.什么是序列化?什么是反序列化?
17171798

1718-
什么是序列化,序列化就是**把 Java 对象转为二进制流**,方便存储和传输
1799+
序列化(Serialization)是指将对象转换为字节流的过程,以便能够将该对象保存到文件、数据库,或者进行网络传输
17191800

1720-
所以**反序列化就是把二进制流恢复成对象**
1801+
反序列化(Deserialization)就是将字节流转换回对象的过程,以便构建原始对象
17211802

1722-
![序列化和反序列化](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javase-30.png)
1803+
![三分恶面渣逆袭:序列化和反序列化](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javase-30.png)
17231804

1724-
类比我们生活中一些大件物品的运输,运输的时候把它拆了打包,用的时候再拆包组装。
1805+
#### Serializable 接口有什么用?
17251806

1726-
> Serializable 接口有什么用?
1807+
`Serializable`接口用于标记一个类可以被序列化。
17271808

1728-
这个接口只是一个标记,没有具体的作用,但是如果不实现这个接口,在有些序列化场景会报错,所以一般建议,创建的 JavaBean 类都实现 Serializable。
1809+
```java
1810+
public class Person implements Serializable {
1811+
private String name;
1812+
private int age;
1813+
// 省略 getter 和 setter 方法
1814+
}
1815+
```
17291816

1730-
> serialVersionUID 又有什么用
1817+
#### serialVersionUID 有什么用
17311818

1732-
serialVersionUID 就是起验证作用
1819+
serialVersionUID 是 Java 序列化机制中用于标识类版本的唯一标识符。它的作用是确保在序列化和反序列化过程中,类的版本是兼容的
17331820

17341821
```java
1735-
private static final long serialVersionUID = 1L;
1736-
```
1822+
import java.io.Serializable;
17371823

1738-
我们经常会看到这样的代码,这个 ID 其实就是用来验证序列化的对象和反序列化对应的对象 ID 是否一致。
1824+
public class MyClass implements Serializable {
1825+
private static final long serialVersionUID = 1L;
1826+
private String name;
1827+
private int age;
17391828

1740-
这个 ID 的数字其实不重要,无论是 1L 还是 IDE 自动生成的,只要序列化时候对象的 serialVersionUID 和反序列化时候对象的 serialVersionUID 一致的话就行。
1829+
// getters and setters
1830+
}
1831+
```
17411832

1742-
如果没有显示指定 serialVersionUID ,则编译器会根据类的相关信息自动生成一个,可以认为是一个指纹
1833+
serialVersionUID 被设置为 1L 是一种比较省事的做法,也可以使用 Intellij IDEA 进行自动生成
17431834

1744-
所以如果你没有定义一个 serialVersionUID, 结果序列化一个对象之后,在反序列化之前把对象的类的结构改了,比如增加了一个成员变量,则此时的反序列化会失败
1835+
但只要 serialVersionUID 在序列化和反序列化过程中保持一致,就不会出现问题
17451836

1746-
因为类的结构变了,所以 serialVersionUID 就不一致
1837+
如果不显式声明 serialVersionUID,Java 运行时会根据类的详细信息自动生成一个 serialVersionUID。那么当类的结构发生变化时,自动生成的 serialVersionUID 就会发生变化,导致反序列化失败
17471838

1748-
> Java 序列化不包含静态变量
1839+
#### Java 序列化不包含静态变量吗
17491840

1750-
序列化的时候是不包含静态变量的
1841+
是的,序列化机制只会保存对象的状态,而静态变量属于类的状态,不属于对象的状态
17511842

1752-
> 如果有些变量不想序列化,怎么办?
1843+
#### 如果有些变量不想序列化,怎么办?
17531844

1754-
对于不想进行序列化的变量,使用`transient`关键字修饰。
1845+
可以使用`transient`关键字修饰不想序列化的变量。
1846+
1847+
```java
1848+
public class Person implements Serializable {
1849+
private String name;
1850+
private transient int age;
1851+
// 省略 getter 和 setter 方法
1852+
}
1853+
```
17551854

1756-
`transient` 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 `transient` 修饰的变量值不会被持久化和恢复。`transient` 只能修饰变量,不能修饰类和方法。
1855+
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东面经同学 2 后端面试原题:用过序列化和反序列化吗?
17571856
17581857
### 46.说说有几种序列化方式?
17591858

0 commit comments

Comments
 (0)