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

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

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

方法一:使用弱引用

弱引用是一种比较常见的避免循环依赖的方式,它可以让对象之间的相互引用变为非强制性的,这样当垃圾回收器发现某个对象的所有强引用都已经被释放后,就可以回收该对象。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日

相关文章

  • java以json格式向后台服务器接口发送请求的实例

    下面我来详细讲解「Java以JSON格式向后台服务器接口发送请求的实例」: 1.什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。在前后端通信的接口中,JSON格式被广泛应用。它具有易读性好、可解析性强等特点,通常使用键值对表示数据。键值对之间使用冒号(:)分割,不同的键值对之间使用逗号(,)分割,键…

    Java 2023年5月26日
    00
  • Java 下数据业务逻辑开发技术 JOOQ 和 SPL

    Java 下数据业务逻辑开发技术 JOOQ 和 SPL 的完整攻略 JOOQ(Java Object Oriented Querying)是一个 Java 版本的关系型数据库操作工具,它可以让用户使用 Java 对象和方法进行 SQL 查询和更新操作,JOOQ 可以解决 SQL 代码繁琐、难以维护、不能重用等问题。而 SPL(Stored Procedure…

    Java 2023年5月19日
    00
  • 如何使用Mockito调用静态方法和void方法

    Mockito是一个Java框架,旨在通过处理代码的依赖关系来测试单元。Mockito通过一系列简单易用的API,帮助开发人员创建和操作模拟对象,以方便进行单元测试。在这里,我们将详细讲解如何使用Mockito来调用静态方法和void方法。 使用Mockito调用静态方法 在Java中,我们可以使用反射来调用静态方法。同样,在Mockito中,我们使用Moc…

    Java 2023年5月20日
    00
  • win2000/2003下整合IIS+Tomcat5支持jsp

    要在Win2000/2003下整合IIS和Tomcat5来支持JSP,需要按照以下步骤来实现: Step 1. 安装IIS和Tomcat5 首先需要在Windows服务器上安装IIS和Tomcat5。对于IIS,需要在Windows的“控制面板”中选择“添加/删除程序”,然后选择“添加/删除Windows组件”,找到IIS并安装。对于Tomcat5,可以从A…

    Java 2023年5月19日
    00
  • 详解java创建一个女朋友类(对象啥的new一个就是)==建造者模式,一键重写

    让我详细解释一下如何使用建造者模式创建一个女朋友类。 建造者模式 建造者模式是一种创建型设计模式,通过一步一步构建复杂对象,最终形成一个完整的对象。在使用建造者模式时,我们可以将对象的构建过程抽象出来,通过不同的特定构建器组合这些步骤来构造出最终的对象。 创建女朋友类 下面就来创建一个女朋友类吧!首先,我们要定义一个Girlfriend类,它包含一些属性,例…

    Java 2023年5月26日
    00
  • java中拼接字符串的5种方法效率对比

    下面我就为您详细讲解“Java中拼接字符串的5种方法效率对比”的攻略。 1. 前言 字符串是Java语言中最常用的数据类型之一,而字符串的拼接操作也是开发中经常需要用到的操作。本文将对Java中拼接字符串的5种常用方法进行效率对比。 2. String String 是Java中最基本的字符串类,它可以实现基本的字符串拼接功能。但是,由于Java语言中的字符…

    Java 2023年5月26日
    00
  • 每天练一练Java函数与算法Math函数总结与字符串转换整数

    下面我为您详细讲解“每天练一练Java函数与算法Math函数总结与字符串转换整数”的完整攻略。 攻略简介 该攻略包含了每天练习Java函数和算法方面的内容,以及Java Math函数的总结和字符串转换整数相关的知识点。通过每天练习,可以加深对Java编程基础概念的理解,提高编程能力,同时也能对Math函数和字符串转换整数等方面进行进一步掌握。 每天练一练Ja…

    Java 2023年5月26日
    00
  • Struts2 Result 参数详解

    Struts2 Result 参数详解 在 Struts2 中,结果(Result)是一个非常重要的概念。在 Action 执行完成后,它将根据 Result 配置找到一个 JSP 文件并将其渲染。在本文中,我们将详细探讨 Struts2 Result 中的参数。 结果类型 Struts2 支持多种不同类型的结果,这些结果类型在 struts.xml 文件中…

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