Question

I have to create a deep copy constructor of a Movie which should have the same serial like the committed Object. The first steps I think are already correct but when I try: "this.serial = that.serial" it gives a warning and says I can't override final variables.

I could solve this problem when I remove the final keyword, but that is not allowed. Can anyone help me to change the final int serial variable without removing the final keyword?

private int serial;
private String title;
private FSK fsk;
private boolean isRent;

private final int serial;
private static int nextSerial;

Movie(String title, FSK fsk) {
    this.title = title; 
    this.fsk = fsk;
    this.serial = nextSerial;
    nextSerial++;

}
Movie(Movie that) {
    this(new String(that.title), that.fsk);
    this.serial = that.serial;
    }
Was it helpful?

Solution

Don't call the other constructor: this(new String(that.title), that.fsk);

You are getting this error because this.serial is getting set in the other constructor you call. Once a final variable is set, you cannot set it again. That is why you're getting the error.

OTHER TIPS

As noted by aglassman, you would end up setting serial twice - once in the chained constructor, and again in the one which calls it. You're not allowed to do that. (You also don't want to increment nextSerial, I suspect.)

I suggest you create one constructor which sets all the fields - then call it from the other constructors. For example:

Movie(String title, FSK fsk) {
    // Note: Change nextSerial to an AtomicInteger
    this(title, fsk, nextSerial.incrementAndGet());
}

Movie(Movie that) {
    this(that.title, that.fsk, that.serial);
}

private Movie(String title, FSK fsk, int serial) {
    this.title = title;
    this.fsk = fsk;
    this.serial = serial;
}

Note that there's no need to use new String(that.title) as strings are already immutable. Also I've changed your use of nextSerial to use an AtomicInteger, as otherwise you'll have thread safety issues.

You can't define a field and then define it again.

private int serial;
...
private final int serial;

I'll be al little pawky here, but please hold on before downvoting and read whole response ;) First of all it's not true that you can't change final field. In Java you can do almost everything ;) Check this out:

    public class Movie {

    static class FSK { /* TODO */ }

    private String title;
    private FSK fsk; 
    private boolean isRent;
    private final int serial;
    private static int nextSerial;

    Movie(String title, FSK fsk) {
        this.title = title;
        this.fsk = fsk;
        this.serial = nextSerial;
        nextSerial++;

    }

    Movie(Movie that) {
        this(new String(that.title), that.fsk);
        setFinalSerial(that.serial);
    }

    void setFinalSerial(int newValue) {
        try {
            java.lang.reflect.Field field = getClass().getDeclaredField("serial");
            field.setAccessible(true);

            java.lang.reflect.Field modifiersField = java.lang.reflect.Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~java.lang.reflect.Modifier.FINAL);

            field.set(this, newValue);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }

        /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Movie m1 = new Movie("title", new FSK());
       Movie m2 = new Movie(m1);
       System.out.println(m1.serial);
       System.out.println(m2.serial);
    }
}

But this is only an ugly trick. I guess that your class should look like this:

    public class Movie {

    static class FSK { /* TODO */ }

    private String title;
    private FSK fsk; 
    private boolean isRent;
    private final int serial;
    private static int nextSerial;

    Movie(int serial, String title, FSK fsk) {
        this.title = title;
        this.fsk = fsk;
        this.serial = serial;
    }

    Movie(String title, FSK fsk) {
        this (nextSerial++, title, fsk);
    }

    Movie(Movie that) {
        this(that.serial, that.title, that.fsk);
    }

        /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Movie m1 = new Movie("title", new FSK());
       Movie m2 = new Movie(m1);
       System.out.println(m1.serial);
       System.out.println(m2.serial);
    }
}

The point is that you should create "copy constructor" in which you can set final variable without tricks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top