Java的引用和实体概念
基本概念
引用 (Reference):指向对象实体的变量,存储在栈内存中,相当于对象的"地址"或"指针"。
实体 (Object Instance):实际的对象数据,存储在堆内存中,包含对象的属性和方法。
Java 使用值传递,传递的是引用的副本。
多个引用可以指向同一个实体。
引用类型详解
1. 强引用 (Strong Reference)
2. 软引用 (Soft Reference)
import java.lang.ref.SoftReference; public class SoftReferenceExample { public static void main(String[] args) { // 创建一个大对象 byte[] largeObject = new byte[1024 * 1024 * 10]; // 10MB // 创建软引用 SoftReference<byte[]> softRef = new SoftReference<>(largeObject); // 断开强引用 largeObject = null; // 当内存不足时,软引用指向的对象会被GC回收 System.gc(); } }
3. 弱引用 (Weak Reference)
import java.lang.ref.WeakReference; public class WeakReferenceExample { public static void main(String[] args) { Object obj = new Object(); // 创建弱引用 WeakReference<Object> weakRef = new WeakReference<>(obj); System.out.println("GC前: " + weakRef.get()); // 断开强引用 obj = null; // 执行GC,弱引用对象会被回收 System.gc(); System.out.println("GC后: " + weakRef.get()); // 可能为null } }
4. 虚引用 (Phantom Reference)
import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; public class PhantomReferenceExample { public static void main(String[] args) { Object obj = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<>(); // 创建虚引用 PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue); // 虚引用的get()总是返回null System.out.println("虚引用get(): " + phantomRef.get()); // null // 断开强引用 obj = null; System.gc(); // 检查引用队列,对象被回收时会加入队列 if (queue.poll() != null) { System.out.println("对象已被回收,可以进行清理操作"); } } }
方法参数传递:值传递引用
传递的是引用的副本,不是引用本身
数组的引用和实体
public class ArrayReferences { public static void main(String[] args) { // 创建数组实体 int[] arr1 = new int[]{1, 2, 3}; int[] arr2 = arr1; // 引用复制 System.out.println("修改前:"); System.out.println("arr1[0]: " + arr1[0]); // 1 System.out.println("arr2[0]: " + arr2[0]); // 1 // 通过arr2修改数组内容 arr2[0] = 100; System.out.println("修改后:"); System.out.println("arr1[0]: " + arr1[0]); // 100 System.out.println("arr2[0]: " + arr2[0]); // 100 // 创建新数组实体 arr2 = new int[]{4, 5, 6}; System.out.println("重新赋值后:"); System.out.println("arr1[0]: " + arr1[0]); // 100 System.out.println("arr2[0]: " + arr2[0]); // 4 } }
字符串的特殊性
public class StringReferences { public static void main(String[] args) { // 字符串字面量进入字符串常量池 String s1 = "hello"; String s2 = "hello"; // 指向常量池中的同一个对象 System.out.println(s1 == s2); // true - 引用相同 // new String() 在堆中创建新对象 String s3 = new String("hello"); String s4 = new String("hello"); System.out.println(s3 == s4); // false - 不同引用 System.out.println(s3.equals(s4)); // true - 内容相同 // intern() 方法返回常量池中的引用 String s5 = s3.intern(); System.out.println(s1 == s5); // true } }
空引用 (Null Reference)
public class NullReference { public static void main(String[] args) { // 声明引用但不指向任何实体 String nullRef = null; // 以下操作会抛出 NullPointerException try { System.out.println(nullRef.length()); } catch (NullPointerException e) { System.out.println("空引用异常: " + e.getMessage()); } // 安全的空引用检查 if (nullRef != null) { System.out.println(nullRef.length()); } else { System.out.println("引用为null,无法调用方法"); } } }
内存泄漏场景
import java.util.ArrayList; import java.util.List; public class MemoryLeakExample { private static List<byte[]> cache = new ArrayList<>(); public static void main(String[] args) { // 不正确的缓存使用导致内存泄漏 for (int i = 0; i < 100; i++) { cache.add(new byte[1024 * 1024]); // 1MB } // 即使不再需要,对象仍然被cache引用,无法被GC回收 // 正确的做法:及时清理不需要的引用 cache.clear(); // 释放引用 } }
最佳实践
-
及时释放引用:对象不再使用时设为null
-
避免循环引用:小心对象间的相互引用
-
使用合适的引用类型:根据需求选择强、软、弱、虚引用
-
注意集合的使用:及时清理集合中的无用对象
-
理解字符串常量池:避免不必要的字符串对象创建

浙公网安备 33010602011771号