如何避免对象引用的循环依赖?

如何避免对象引用的循环依赖

在面向对象编程中,一个对象可能同时引用了另一个对象,这种引用关系如果不注意可能会出现循环依赖问题,即两个或多个对象相互引用,彼此依赖,无法被垃圾回收机制回收,导致内存泄漏。此时就需要采取一些方式来避免对象引用的循环依赖。下面介绍两种常用的方式:

方法一:使用弱引用

弱引用是一种比较常见的避免循环依赖的方式,它可以让对象之间的相互引用变为非强制性的,这样当垃圾回收器发现某个对象的所有强引用都已经被释放后,就可以回收该对象。Java中已经提供了弱引用类java.lang.ref.WeakReference,可以使用它来创建弱引用对象,示例如下:

class Person {
    private String name;
    private WeakReference<Car> car;

    public Person(String name) {
        this.name = name;
    }

    public void buyCar(Car car) {
        this.car = new WeakReference<Car>(car);
    }

    public void getPaid() {
        if(car != null && car.get() != null) {
            System.out.println("I got $" + car.get().getPrice() + " for selling " + car.get().getBrand() + ".");
        } else {
            System.out.println("I have to walk now. My car has been sold.");
        }
    }
}

class Car {
    private String brand;
    private double price;
    private Person owner;

    public Car(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    public void setOwner(Person owner) {
        this.owner = owner;
    }

    public String getBrand() {
        return brand;
    }

    public double getPrice() {
        return price;
    }
}

public class Test {
    public static void main(String[] args) {
        Person person = new Person("Tom");
        Car car = new Car("Toyota", 20000);
        person.buyCar(car);
        car.setOwner(person);

        person.getPaid(); // 输出 I got $20000.0 for selling Toyota.

        // 解除Person和Car之间的引用关系
        car.setOwner(null);
        person.buyCar(null);

        // 手动调用垃圾回收器以便观察效果
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        person.getPaid(); // 输出 I have to walk now. My car has been sold.
    }
}

在以上示例中,Person类持有了Car对象的弱引用。当Person不再持有Car时,即使Car还有其他对象的强引用,JVM也会认为Car是可以被回收的。通过手动调用System.gc()方法可以看到上述对象回收的效果。

方法二:使用中介对象

另一种避免循环依赖的方式是引入中介对象,即创建一个额外的对象来管理两个或多个对象之间的依赖关系。这种方式较为灵活,但需要额外的管理开销,示例如下:

class Person {
    private String name;
    private CarMediator carMediator;

    public Person(String name, CarMediator carMediator) {
        this.name = name;
        this.carMediator = carMediator;
    }

    public void buyCar(Car car) {
        carMediator.setCar(this, car);
    }

    public void getPaid() {
        Car car = carMediator.getCar(this);
        if(car != null) {
            System.out.println("I got $" + car.getPrice() + " for selling " + car.getBrand() + ".");
            carMediator.removeCar(car);
        } else {
            System.out.println("I have to walk now. My car has been sold.");
        }
    }
}

class Car {
    private String brand;
    private double price;

    public Car(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public double getPrice() {
        return price;
    }
}

class CarMediator {
    private Map<Person, Car> map = new HashMap<Person, Car>();

    public void setCar(Person person, Car car) {
        map.put(person, car);
        car.setOwner(person);
    }

    public Car getCar(Person person) {
        return map.get(person);
    }

    public void removeCar(Car car) {
        map.entrySet().removeIf(entry -> Objects.equals(entry.getValue(), car));
        car.setOwner(null);
    }
}

public class Test {
    public static void main(String[] args) {
        CarMediator carMediator = new CarMediator();

        Person person1 = new Person("Tom", carMediator);
        Person person2 = new Person("Jerry", carMediator);

        Car car = new Car("Toyota", 20000);

        person1.buyCar(car);

        person1.getPaid(); // 输出 I got $20000.0 for selling Toyota.

        person2.getPaid(); // 输出 I have to walk now. My car has been sold.
    }
}

在以上示例中,Person类不再直接持有Car对象,而是通过中介对象CarMediator来管理与其的关系,从而达到避免循环依赖的目的。

总结

弱引用和中介对象是两种避免对象引用的循环依赖的常见方式。开发者可以在实际开发中根据具体情况选择适合的方式来避免该问题的发生。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何避免对象引用的循环依赖? - Python技术站

(0)
上一篇 2023年5月11日
下一篇 2023年5月11日

相关文章

  • Jenkins使用Gradle编译Android项目详解

    Jenkins使用Gradle编译Android项目详解 前言 Jenkins是一个功能强大的自动化构建工具,当它和Gradle结合在一起时,可以更方便高效地构建Android项目。本文将详细讲述如何使用Jenkins和Gradle完成Android项目的自动化构建流程。 环境准备 JDK(建议使用8以上版本) Gradle(建议使用5.0以上版本) Jen…

    Java 2023年5月26日
    00
  • Java Math.round函数详解

    Java Math.round函数用于返回一个在小数点前后正确四舍五入的整数。以下是完整的攻略: 1. Math.round函数的语法 public static long round(double a) 参数为一个double型数值,返回值为最接近参数并且与参数具有相同符号的整数。 2. Math.round函数的示例1 double a = 5.6; l…

    Java 2023年5月26日
    00
  • Spring Security OAuth2 token权限隔离实例解析

    Spring Security OAuth2 token权限隔离实例解析 在本文中,将介绍如何使用Spring Security来实现OAuth2 token的权限隔离。我们将阐述基于Spring Boot的实现方式及其持久化方案,并提供两条示例。 情境描述 假设一个应用程序需要提供给多个客户端进行访问,而每个客户端都有自己的用户组并需要访问特定的资源。在这…

    Java 2023年5月20日
    00
  • Spring五大类注解读取存储Bean对象的方法

    下面是详细的讲解“Spring五大类注解读取存储Bean对象的方法”的完整攻略。 一、概述 Spring 是一种非常受欢迎的 Java 开发框架,它提供了一套非常完整的依赖注入机制,使得开发者可以轻松地使用 Spring 来管理 Bean 对象。而 Spring 的 Bean 对象的创建方式就有五大类注解方式,它们分别是:@Component、@Reposi…

    Java 2023年5月26日
    00
  • 五分钟带你了解Java的接口数据校验

    介绍Java中的接口数据校验,通常使用的是验证框架Hibernate Validator。我们可以使用它来验证javabean实例的数据是否合法。 安装 Hibernate Validator 在Maven中,我们可以使用以下代码引入Hibernate Validator: <dependency> <groupId>org.hibe…

    Java 2023年6月1日
    00
  • Java Filter过滤器的使用教程

    Java Filter过滤器的使用教程 Java Filter是Servlet规范提供的一种过滤器机制,用于在Servlet请求和响应之前对请求进行过滤和处理。Filter的使用可以提高Web应用程序的安全性和性能。在本文中,我们将详细讲解Java Filter的使用教程。 Filter过滤器的基本概念 Filter是Servlet中的一种过滤器机制,主要用…

    Java 2023年6月15日
    00
  • java 排序算法之希尔算法

    Java排序算法之希尔算法 希尔算法是插入排序的一种优化算法,也叫缩小增量排序。希尔排序的基本思路是将待排序数组元素按下标的一定增量分组,然后将每组分别进行直接插入排序。随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,整个数组恰被分成一组,此时算法终止。 做法 在希尔排序中,先将待排数组按照一定的增量分割成若干个子序列(下标间隔为增量)分别进行插入…

    Java 2023年5月19日
    00
  • 一套前后台全部开源的H5商城送给大家

    博主给大家推荐一套全部开源的H5电商项目waynboot-mall。由博主在2020年开发至今,已有三年之久。那时候网上很多的H5商城项目都是半开源版本,要么没有H5前端代码,要么需要加群咨询,属实恶心。于是博主决定自己开发一套完整的移动端H5商城,包含一个管理后台、一个前台H5商城、一套后端接口。项目地址如下: H5商城前端代码:https://githu…

    Java 2023年5月6日
    00
合作推广
合作推广
分享本页
返回顶部