Search code examples
javajava-17

Why have nothing to override, but still can put @Override without syntax error?


I am using Java language level 17 on JDK 19. I have

package ocp17.ch07;

public record BeardedDragon(boolean fun) {
    
    @Override
    public boolean fun() {
        return false;
    }
    
}

enter image description here

Why have nothing to override, but still can put @Override without syntax error?


Solution

  • You are indeed overriding the fun method (which is bad in this case1). With Java records, the accessor name (which it automatically gives for you) doesn't have the get prefix - it is fun() and not getFun() or isFun().

    The Record Members section of JLS states

    Furthermore, for each record component, a record class has a method with the same name as the record component and an empty formal parameter list. This method, which is declared explicitly or implicitly, is known as an accessor method.

    The Records JEP also says,

    The meaning of the @Override annotation was extended to include the case where the annotated method is an explicitly declared accessor method for a record component.

    @Sweeper's answer points to the appropriate section of JLS for this

    So whatever you've done now counts as overriding.


    1 Why is it bad?

    Let's say you have an instance of BeardedDragon like,

    BeardedDragon dragon = new BeardedDragon(true);
    if (dragon.fun()) {
         System.out.println("Yay!!");
    } else {
        System.out.println("Dang it.. It was supposed to be fun");
    }
    

    It will return false when you call fun(). I'm not sure if that is what you want.

    Also, it violates the below requirement from the JLS.

    Consider a record class R that has components c1, ..., cn, and an implicitly declared accessor method for every component, and an implicitly declared equals method. If an instance r1 of R is copied in the following way:

    R r2 = new R(r1.c1(), r1.c2(), ..., r1.cn());

    then, assuming r1 is not the null reference, it is always the case that the expression r1.equals(r2) will evaluate to true. Explicitly declared accessor methods and equals methods should respect this invariant. It is not generally possible for a compiler to check whether explicitly declared methods respect the invariant.

    Using the example from @Johannes Kuhn (from the comments).

    var b1 = new BeardedDragon(true); 
    var b2 = new BeardedDragon(b1.fun()); 
    assert b1.equals(b2); // This will fail