如果我在 getter 内初始化会出现任何问题吗?

发布于 2025-01-13 11:42:16 字数 2046 浏览 3 评论 0原文

我在旅游领域工作。例如,创建了 Main 类。这些 bean 在 web-java-project 中使用。下面的代码按预期工作正常。我仍然怀疑将来是否可能发生任何未知问题(Vechiles 类在应用程序中广泛使用)。

Singleton 应该通过 constructor 获得,但在本例中我是通过 getter 实现的。 setter 也保持原样(所以我不确定它是否可以称为单例。

汽车

public class Car {
    private int wheelCount;

    public int getWheelCount() {
        return wheelCount;
    }

    public void setWheelCount(int wheelCount) {
        this.wheelCount = wheelCount;
    }
}

车辆

public class Vehicles {
    private Car car;

    public Car getCar() {
        if(car == null){
            Car newCar = new Car();
            this.car = newCar;
            return newCar;
        }
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}

< strong>主类

public class Foo {
    public static void main(String[] args) {
        Vehicles vehicles = new Vehicles();
        Car car1 = vehicles.getCar();
        car1.setWheelCount(3);
        System.out.println(vehicles.getCar().getWheelCount());
        
        Car anotherCar = vehicles.getCar();
        vehicles.setCar(anotherCar);
        vehicles.getCar().setWheelCount(4);
        System.out.println(vehicles.getCar().getWheelCount());
        
        Car car_withNew = new Car();
        vehicles.setCar(car_withNew);

        System.out.println(vehicles.getCar().getWheelCount());
    }
}

输出:(符合预期)

3
4
0

要求
vehicles.getCar().setWheelCount(x); 应该是可能的。否则,每次我都需要检查 Car 是否存在。如果不存在,则使用 new 关键字创建一个,然后使用 setter 设置它。
应该像这样初始化内部 getter 吗?

我发现的一个问题
注意:通常车辆可能包含汽车,也可能不包含。但在这种情况下,Vehicles 将始终包含一个 Car(当调用 getter 时)!!!因此,在这种情况下,对于给定的汽车模型,没有选项可以检查它是否为 NULL(汽车是否存在)。它永远不会是NULL。

还有其他问题吗?

I work in travel domain. The Main class is created for example. The beans are used in web-java-project. The code below is working fine as expected. Still I doubt if there's any unknown problem which may happen in future (the Vechiles class is used widely in the application).

Singleton should be attained through constructor but in this case I did it through getter. Also the setter is kept as it is (so I am not sure it can be called as Singleton or not.

Car

public class Car {
    private int wheelCount;

    public int getWheelCount() {
        return wheelCount;
    }

    public void setWheelCount(int wheelCount) {
        this.wheelCount = wheelCount;
    }
}

Vehicles

public class Vehicles {
    private Car car;

    public Car getCar() {
        if(car == null){
            Car newCar = new Car();
            this.car = newCar;
            return newCar;
        }
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}

Main class

public class Foo {
    public static void main(String[] args) {
        Vehicles vehicles = new Vehicles();
        Car car1 = vehicles.getCar();
        car1.setWheelCount(3);
        System.out.println(vehicles.getCar().getWheelCount());
        
        Car anotherCar = vehicles.getCar();
        vehicles.setCar(anotherCar);
        vehicles.getCar().setWheelCount(4);
        System.out.println(vehicles.getCar().getWheelCount());
        
        Car car_withNew = new Car();
        vehicles.setCar(car_withNew);

        System.out.println(vehicles.getCar().getWheelCount());
    }
}

Output: (comes as expected)

3
4
0

Requirement:
vehicles.getCar().setWheelCount(x); should be possible. Otherwise, each time, I need to check, whether a Car exists or not. If does not exists, create one with new keyword and then set it with setter.

Should initialize inside getter like this?

One problem I found :
Note: Usually The Vehicles might contain a Car or might not. But in this case, the Vehicles will always contain a Car (when getter is called) !!! So, in that case, with the given Car model, there's no option to check whether it is NULL or not (car exists or not). It will never be NULL.

Is there any other problems?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

娇纵 2025-01-20 11:42:16

我不会将您的代码称为 Singleton,因为单例指的是给定类的单个实例(对象),并在整个应用程序运行时维护。没有什么可以阻止您的代码创建 Car 类的多个实例,因此从某种意义上来说,car 不是单例(并且拥有并使用 Car 的多个实例) carVehicles 中的 setter 方法隐含。

我认为您想要实现的目标是确保调用链 vehicles.getCar().getWheelCount() 永远不会抛出 NullPointerException,这将是正确的。

在单线程场景中,您的代码可能会按预期工作,但是当您有多个线程在同一个 vehicles 对象上调用 getCar() 时,可能会导致不良结果。想象一下,您有两个线程持有同一个 vehicles 对象,并且它们都同时调用 getCar()。在这种情况下,有可能两者都将 car == null 视为 true,并且都创建了 car 对象。然后,调用 this.car = newCar 的最后一个线程将设置 vehicles 对象中的 car 字段,并覆盖该值。

话虽如此,您可以考虑 Vehicles 需要服务的确切目的:它是汽车工厂(即构造但不保存引用),还是需要保存所有 曾经创建过的 car 对象(从这个意义上说,单个 Car 实例是不够的)。

如果它可以用作工厂,那么您只需提供一个返回新创建的 Car 实例的方法 newCar 即可简化 Vehicles

如果它应该保存汽车作为参考,那么您应该保留汽车的集合,并确保该集合可以同时修改。

I wouldn't call your code a Singleton because singletons refer to a single instance (object) of a given class, maintained throughout the whole application runtime. There's nothing stopping your code from creating multiple instances of the Car class, so in a sense the car is not a singleton (and having and using multiple instances of a car is implied by the setter method in Vehicles).

What I see you are trying to achieve, is to ensure that the call chain vehicles.getCar().getWheelCount() never throws a NullPointerException, and that will be true.

Your code may work as desired when in a single-thread scenario, however may lead to undesirable outcomes when you have multiple threads calling getCar() on the same vehicles object. Imagine you have two threads that hold the same vehicles object, and they both call getCar() at the same time. In such a situation, it is possible that both see car == null as true, and they both create a car object. Then the last thread to call this.car = newCar will set the car field in the vehicles object, overwriting the value.

Having said that, you can think about what exact purpose Vehicles needs to serve: is it a factory for cars (i.e. construct but don't hold references), or does it need to hold all car objects that have been created ever (in that sense a single Car instance is not sufficient).

If it can serve as a factory, then you can simplify Vehicles by simply providing a method newCar that returns a newly created Car instance.

If it should hold cars as references, then you should keep a collection of cars, and make sure this collection can be concurrently modified.

末骤雨初歇 2025-01-20 11:42:16

如果我在 getter 内初始化会出现任何问题吗?

这是一个“固执己见”的问题,但对此有一个简单的事实答案:团队内的惯例比“更全球化”的惯例更重要。

含义:从概念上讲,getter() 应该就是“读取”值并将其提供给调用者的方法。在 C++ 术语中,您会想到一个 const 方法,它改变所调用的对象的状态。但 getter 方法的一个关键方面是:它们不仅仅是简单的字段访问。事实上,客户端使用 x = foo.getX() 而不是 x = foo.x 来实现这一点:除了返回值之外,还可以执行“其他操作”。

所以:是的,getCar()有时创建一个Car对象可能会让一些读者感到惊讶,但是当你的团队理解这些方面并同意时“这就是我们想要的”,那么这对你来说没问题。因为你的团队考虑了这个问题,并做出了这个决定。

当然:更有意义的解决方案是首先不将其称为 getter:为什么不重命名该方法,并将其称为 getWithCreateIfNeeded() 或类似的名称? !

当然,另一个答案是正确的:您在此处显示的代码是不是线程安全的。时期。当在多线程环境中使用时,这是唯一可以造成真正损坏的东西。

Will there be any issues if I initialize inside a getter?

This is sort of an "opinionated" question, but there is a simple factual answer to that: the conventions within your team matter more than "more global" conventions.

Meaning: conceptually, a getter() should be exactly that, a method that "reads" a value and provides that to the caller. In C++ terms, you would think of a const method that does not alter the state of the object it is called on. But a key aspect of getter methods is: they can be more than a simple field access. The fact that clients do x = foo.getX() instead of x = foo.x allows for exactly that: doing "other things" besides returning a value.

So: yes, getCar() sometimes creating a Car object might be surprising to some readers, but when your team understands such aspects, and agrees "this is what we want", then that is okay for you. Because your team thought about it, and made that decision.

Of course: the more meaningful solution would be to not call it a getter in the first place: why not rename that method, and call it getWithCreateIfNeeded() or something alike?!

Also of course, the other answer is spot on: the code you are showing here is not thread safe. Period. When used in a multi threaded environment, that is the only thing that can create real damage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文