Java的引用和实体概念

基本概念

引用 (Reference):指向对象实体的变量,存储在栈内存中,相当于对象的"地址"或"指针"。

实体 (Object Instance):实际的对象数据,存储在堆内存中,包含对象的属性和方法。

Java 使用值传递,传递的是引用的副本。

多个引用可以指向同一个实体。

引用类型详解

1. 强引用 (Strong Reference)

public class StrongReferenceExample {
    public static void main(String[] args) {
        // 强引用 - 最常见的引用类型
        Object obj = new Object();
        // 只要引用存在,对象就不会被GC回收
        System.out.println(obj.toString());
        // 显式断开引用,对象成为垃圾
        obj = null;
        // 此时对象可以被GC回收
    }
}

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(); // 释放引用
    }
}

 

最佳实践

  1. 及时释放引用:对象不再使用时设为null

  2. 避免循环引用:小心对象间的相互引用

  3. 使用合适的引用类型:根据需求选择强、软、弱、虚引用

  4. 注意集合的使用:及时清理集合中的无用对象

  5. 理解字符串常量池:避免不必要的字符串对象创建

posted @ 2025-11-16 16:34  YukiRinLL  阅读(2)  评论(0)    收藏  举报