How to use a static variable correctly in my code?

I have two classes: Car and LearnArrayList. Car is encapsulated class, having properties like: manufacturer,gearbox,ps,fuelType, static carID(PROBLEM WITH THIS VARIABLE). I put in Car constructor statement what increases carID by 1 (carID++). I have created such a code to learn arrayList:

public class LearnArrayList implements FutureFunctionality {

    public static void main(String[] args) {

        LearnArrayList learn = new LearnArrayList();
        learn.createObjects();
        learn.getInfo();
    }

    List<Car> listOfCars = new ArrayList();

    public void createObjects() {

        Car bmw = new Car("bmw", "mechanic", 200, "diesel");
        Car ford = new Car("ford", "automatic", 150, "petrol");
        Car vw = new Car("vw", "mechanic", 120, "petrol");
        Car audi = new Car("audi", "mechanic", 100, "petrol");
        Car mercedes = new Car("mercedes", "mechanic", 200, "diesel");
        Car opel = new Car("opel", "automatic", 105, "petrol");
        Car toyota = new Car("toyota", "mechanic", 103, "petrol");
        Car renault = new Car("renault", "automatic", 100, "diesel");
        Car dacia = new Car("dacia", "mechanic", 250, "petrol");
        Car lada = new Car("lada", "mechanic", 80, "petrol");

        Car[] cars = { bmw, ford, vw, audi, mercedes, opel, toyota, renault, dacia, lada };

        for (int i = 0; i < cars.length; i++) {
            addToArrayList(cars[i]);
        }
    }

    @Override
    public void addToArrayList(Car car) {
        listOfCars.add(car);
    }

    @Override
    public void getInfo() {
        for (int i = 0; i < listOfCars.size(); i++) {
            System.out.println(listOfCars.get(i).toString());
        }
    }
}

My output should be 10 records. I want to have an unique ID for each car, but the result when I run a program is always 10 for each car. I want to make that bmw is 1, ford is 2, vw is 3 and so on..

A little bit of Output:

Car ID: 10 Manufacturer: bmw GearBox: mechanic PS: 200 FuelType: diesel

Car ID: 10 Manufacturer: ford GearBox: automatic PS: 150 FuelType: petrol

Car ID: 10 Manufacturer: vw GearBox: mechanic PS: 120 FuelType: petrol

Car ID: 10 Manufacturer: audi GearBox: mechanic PS: 100 FuelType: petrol

Upvotes: 1

Views: 162

Answers (5)

R. Wiles
R. Wiles

Reputation: 11

While @Mureinik's answer might seem to work, it's technically flawed and would be a bad habit to get into. Not only does will it allow for potentially duplicated Car Ids, but those sort of bugs can be difficult to find.

One additional thing to ensure proper multi-threaded behavior of CarId in Christopher Schultz's answer would be to add the "volatile" to ensure that the Java Virtual Machine properly treats it as a shared variable and ensures a consistent view of it's value to each thread.

Details about Java's field modifiers can be found here: Java Language Specification - Field Modifiers

Upvotes: 1

Christopher Schultz
Christopher Schultz

Reputation: 20837

To be absolutely safe, you need to use synchronization. @Mureinik's answer will probably work most of the time, but there are edge cases where multi-threaded accesses can be out of sync. In your "car" example, it doesn't matter. When controlling a self-driving car, the problem may be more serious.

The safest implementation of your Car class looks like this:

public class Car {
    private static CarId = 0;
    private static synchronized int nextCarId() { return CarId++ };

    private int id;
    public Car() {
      this.id = nextCarId();
    }
}

This will ensure that all threads always see the correct value for Car.CarId and each Car instance gets a unique value for its own id member.

Upvotes: 2

Marcos Boaventura
Marcos Boaventura

Reputation: 4741

This is because the value of static field carId inside your Car class will be the same for every instace of Car class. You can create a static idCounter then increment and pass this value for a normal carId field. But this approach is not thread safe.

  public class Car{
        private static long m_idCounter = 0; // initial value
        private long m_carId;
         // .. other fields

   public Car () {
        this.m_carId = m_idCounter; // new id simulation
        this.m_idCounter+=1; // id for next car instance. Same value for all instances of Car class.
        //... do other stuffs
   }

  //... stuffs
}

Upvotes: 1

Mureinik
Mureinik

Reputation: 311073

Making the car id static means that all the cars will share the id. Instead, you can have an instance member with the id, and keep a static counter for the next id. E.g.:

public class Car {
    private static int nextId = 1;
    private int id;
    // Other data members...

    public Car(/* arguemnts... */) {
        id = nextId;
        ++nextId;
        // Handle the other arguments and store them in data member
    }
}

Upvotes: 3

Haroldo_OK
Haroldo_OK

Reputation: 7230

You should make carID non-static and create a separate static variable to serve as the auto increment, like, say, nextCarID. Then you can populate carID via this.carID = nextCarID++;.

Upvotes: 3

Related Questions