繁体   English   中英

如何避免多次创建相同的对象引用?

[英]How to avoid creating the same object reference multiple times?

想象一下,我有一些看起来像这样的类:

class Car {
    private Image carImage;

    public Car(int imageIndex) {
        switch (imageIndex) {
            case 1: carImage = generateCarImage(1); break;
            # and so forth
        }
    }
}

class Audi extends Car {
    private int numberOfSeats;
    public Audi(int imageIndex, int numberOfSeats) {
        super(imageIndex);
        this.numberOfSeats = numberOfSeats;
    }
}

现在假设我使用相同的图像创建多个奥迪:

Audi car1 = new Audi(1,2);
Audi car2 = new Audi(1,3);

car1和car2会延伸相同的物体吗? 我假设没有,但有没有办法可以做到这一点? 我问,因为我想避免两次生成和存储相同的图像。

编辑:

这两个奥迪会参考同一辆车吗,例如图像只生成和存储一次,对一个的任何变化都会影响另一个吗?

class Car {
    private Image carImage;
    public Car(int imageIndex) {
        switch (imageIndex) {
            case 1: # carImage = readfile(1.jpeg)
            # and so forth
        }
    }
}

class Audi{
    private int numberOfSeats;
    private Car car;
    public Audi(Car car, int numberOfSeats) {
        this.car = car;
        this.numberOfSeats = numberOfSeats;
    }
}

Car car = new Car(1);
Audi audi1 = new Audi(car,2);
Audi audi2 = new Audi(car,2);

编辑2:

这里有很多好的答案,最后我结合使用它们来创建一个像样的解决方案。 我最初的问题并没有很好地定义,主要是因为我不知道自己究竟是什么。

无论如何,对于这个问题,不可能事先生成所有数据(下面示例中的PartsInfo ),也不能显式生成数据(如上面的switch-case示例所暗示的那样)。 下面的解决方案的最大问题是,我无法访问PartsInfo单个字段而不检索整个事物(如在调用Car.getPartsInfo()时在解决方案中完成)或创建同一对象的多个实例(其中例如,Car类将获得自己的PartsInfo变量)。

弱散列图也可以,但不是最优的,因为问题不是垃圾收集,而是存储在不同实例中的大量相同数据。

如果ID类似于“audi-a4-2003”,而且PartsInfo对于所有“audi-a4-2003”都是相同的,独立于颜色,所有者,年龄,座位数等,则该解决方案适用,但对于“audi”则完全不同a4-2004" 。

谢谢

Class PartsInfo {
    // lots of stuff I'd rather not create nor save multiple times
}

Class PartsInfoFactory {
    private static HashMap<String, PartsInfo> partsInfoMap = new HashMap<String, PartsInfo>();

    public static getPartsInfo(String id) {
        if (!partsInfoMap.containsKey(id)) {
            generatePartsInfo(id);
        }
        return partsInfoMap(id)
    }

    private static generatePartsInfo(String id) {
        // Do stuff I don't want to do twice for same ID
        partsInfoMap.put(id)
    }
}

Class Car {
    private Color color;
    private String id;
    // Notice that PartsInfo is not stored here

    public Car(Color color, String id) {
        this.color = color;
        this.id = id;
    }

    public PartsInfo getPartsInfo() {
        return PartsInfoFactory.getPartsInfo(id);
    }
}

car1car2延伸相同的物体吗?

一个类可以从另一个类扩展。对象不扩展任何东西。 在Java中,继承仅适用于类和接口。 你在这里做的是创建同一级别的两个实例, AudiAudiCar扩展。

有没有办法可以做到这一点?

没有。

我问,因为我想避免两次生成和存储相同的图像。

这是一个值得回答的正确问题。 您真正的问题是避免多次创建相同的对象实例。 为此,最好通过使用WeakHashMap来使用对象池。 以下是对使用此结构的原因的解释: 您何时使用WeakHashMap或WeakReference?

避免多次创建相同图像的好方法是使用依赖注入:将图像作为构造函数参数注入,而不是将参数传递给generateCarImage

class Car {
  private final Image image;

  Car(Image image) {
    this.image = image;
  }
}

class Audi extends Car {
  Audi(Image image, int numDoors) {
    super(image);
    // ...
  }
}

这意味着image可以来自任何地方 - 让您更加明确地控制图像的生命周期。 所以,如果你想一遍又一遍地使用相同的图像,你可以,而且你很明显:

Image image = generateCarImage(1);
Audi car1 = new Audi(image, 4);
Audi car2 = new Audi(image, 2);

此外,通过删除与generateCarImage方法的静态耦合,它使类更易测试,因为您可以创建不同的图像进行测试,例如生成起来更简单。

你永远不会扩展对象,你扩展了类。 当然,你会一直在扩展同一个班级。

在Java中没有扩展对象的东西(其他语言都有这种继承,称为原型 。但是,Java没有原型继承;只有类继承)。

在Java中扩展意味着扩展一个类,而不是一个对象,它是一个类的实例。

因此,尽管car1car2的类扩展了相同的类,但是这两个对象彼此无关。

我想避免两次生成和存储相同的图像

共享第三个对象的多个对象没有问题,在您的情况下可能是图像。 处理此问题的一种方法是创建Car所有实例共有的图像缓存,在第一次请求时生成图像,然后根据需要重新使用相同的图像对象以节省空间:

简单的图表

是否有可能不是搜索图像缓存,而是搜索所有Car实例的缓存,然后选择在Audi类中实例化哪一个?

您无法再次实例化对象。 但是,您可以创建Car对象的缓存,并在Car上实现一个工厂方法,该方法在创建新实例之前在其缓存中搜索合适的汽车。

每次使用new子句时,您都将创建一个对象的新实例,该类是一个完整的单独表示形式; 所以回答直接的问题:不,你没有扩展对象。

根本问题是你可能不想重复创建相同的图像:然后你必须采取不同的方法。 我首先建议对Java的OO方面进行另一次读取,然后考虑(可能)工厂模式,这可能是一个类,如果已经创建了另一个,将不会重复创建相等的图像。

我的解决方案是使用静态引用作为常量值。 这是最简单的解决方案,因为enum不能与对象一起使用,因为它必须在编译时进行评估。

但是我们想要获得运行时常量,以及使用类似于使用单实例的枚举的好处,并且可以在switch语句中使用。

因此,我们将实现enum以返回在编译时可用的另一个类的常量静态属性,并返回对在运行时创建的对象的常量引用。

class CarImageDirectory
{
    // Created at Run-time

    public static final Image Audi = new Image("Audi");
    public static final Image Toyota = new Image("Toyota");
    // ..etc
}

enum CarImage
{
  // Created at Compile-time

  Audi
  {
    @Override public Image image () { return CarImageDirectory.Audi; }
  },
  Toyota
  {
    @Override public Image image () { return CarImageDirectory.Toyota; }
  }; // ..etc

  public abstract Image image ();
}

CarImage将如下工作:

CarImage A = CarImage.Audi;
CarImage B = CarImage.Audi;

if (A == B) System.out.println("A and B are both Audi");

然后我们使用它来定义我们的Car类:

class Car
{
    private CarImage carImg;
    public Car (CarImage carImg) { this.carImg = carImg; }
    public Image getImage () { return carImg.image(); }
    public CarImage getCarImage () { return carImg; }
}

class AudiCar extends Car
{
    private int numOfSeats;

    public AudiCar (int numOfSeats)
    {
        super(CarImage.Audi);
        this.numOfSeats = numOfSeats;
    }
}

class ToyotaCar extends Car
{
    private int numOfSeats;

    public ToyotaCar (int numOfSeats)
    {
        super(CarImage.Toyota);
        this.numOfSeats = numOfSeats;
    }
}

CarImage本身也可以在switch语句中使用:

CarImage A = CarImage.Audi;

switch(A)
{
  case CarImage.Audi:
    System.out.println("This car is Audi");
    break;

  case CarImage.Toyota:
    System.out.println("This car is Toyota");
    break;

  default:
}

你有没有看过“轻量级”模式? 这可能会减少对象的创建。 从技术上讲,它是为了减少内存占用,但如果对象创建成本高且重用率高,则可以在启动时间不成问题的情况下使用它,例如应用程序服务器启动。

无论如何,只有在您知道这是性能问题时才进行优化。

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM