Java 默认行为
字符串的加法运算
java
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println("hee" + person);
System.out.println(1 + "Hee");
}
}
// 反编译的class文件
public class Main {
public static void main(String[] args) {
Person person = new Person();
// String的vlueOf(Object obj) 方法如果传入对象为null则为"null", 否则调用对象的 toString() 方法
System.out.println("hee" + String.valueOf(person));
System.out.println("1.0Hee");
}
}深拷贝和浅拷贝
在 Java 中,拷贝对象时有两种方式:浅拷贝和深拷贝。
- 浅拷贝:只复制对象本身,对于对象中的引用类型字段,只复制引用地址, 共用同一份对象, 对于基本数据类型字段则复制其值, 各自拥有独立的值, 修改不会相互影响.
- 深拷贝:不仅复制对象本身,还会递归复制对象中的所有引用类型字段,拷贝出的对象与原对象完全独立,互不影响。


TIP
无论是深拷贝还是浅拷贝都会创建一个新对象
java
class Person implements Cloneable {
String name;
Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// 深拷贝
public Person deepClone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) address.clone();
return cloned;
}
}
class Address implements Cloneable {
String city;
public Address(String city) { this.city = city; }
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}对比总结
| 特性 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 基本类型 | 复制值 | 复制值 |
| 引用类型 | 复制引用地址(指向同一对象) | 复制新对象(完全独立) |
| 影响 | 修改引用对象会互相影响 | 修改互不影响 |
| 实现方式 | Object.clone() 默认行为 | 需手动递归拷贝引用类型字段 |
TIP
深拷贝常见实现方式:重写 clone() 方法、序列化与反序列化、第三方库(如 Apache Commons Lang)。
对象生命周期
Java 对象的生命周期包括以下几个阶段:
- 创建/实例化阶段:调用类的构造方法,产生一个新的对象。
- 初始化阶段:对象已创建但尚未被正式使用,可能执行一些额外操作(如预初始化数据库连接池)。
- 运行使用期:对象初始化完毕,程序正常运行,对象被使用。
- 销毁阶段:对象准备被销毁,通常已不再被使用,需要预先处理自身占用的资源(如关闭、释放数据库连接)。
- 回收阶段:对象已完全没有被引用,将在合适的时机被垃圾回收器回收。

默认包
Java 默认包(Default Package)是指没有显式声明包名的类所在的包。当你在 Java 源文件中没有使用 package 语句时,编译器会将该类放入默认包中。
特点:
- 默认包中的类只有在同一默认包中的其他类才能访问
- 默认包中的类不能被其他包中的类导入使用
自动装箱与拆箱
在 Java 中, 自动装箱(Autoboxing)和拆箱(Unboxing)是指基本数据类型与其对应的包装类之间的自动转换。
- 自动装箱:将基本数据类型自动转换为对应的包装类对象。
- 自动拆箱:将包装类对象自动转换为对应的基本数据类型。
java
public class Main {
public static void main(String[] args) {
// 自动装箱
Integer a = 10; // 实际等价与 Integer a = Integer.valueOf(10);
int b = 10;
System.out.println(a == b); // 实际等价与 System.out.println(a.intValue() == b);
}
}对应字节码:
java
public class Main {
// compiled from: Main.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 9 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lfilter/Main; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 11 L0
SIPUSH 128
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; // 自动装箱
ASTORE 1
L1
LINENUMBER 12 L1
SIPUSH 128
ISTORE 2
L2
LINENUMBER 13 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/lang/Integer.intValue ()I // 自动拆箱
ILOAD 2
IF_ICMPNE L3
ICONST_1
GOTO L4
L3
ICONST_0
L4
INVOKEVIRTUAL java/io/PrintStream.println (Z)V
L5
LINENUMBER 14 L5
RETURN
L6
LOCALVARIABLE args [Ljava/lang/String; L0 L6 0
LOCALVARIABLE a Ljava/lang/Integer; L1 L6 1
LOCALVARIABLE b I L2 L6 2
MAXSTACK = 3
MAXLOCALS = 3
}TIP
当基本数据类型和其包装类进行比较时,Java 会先进行自动拆箱, 然后才进行比较
