28

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?

Vy Do
  • 46,709
  • 59
  • 215
  • 313
  • 11
    You've got a tag of `java-17` but you're talking about JDK19... which is it? (Or has Java done something "interesting" with language versions that I'm not aware of? I wouldn't rule that out...) – Jon Skeet Dec 19 '22 at 08:06
  • I revised my question. JDK 19, and set Java language level is 17. – Vy Do Dec 19 '22 at 08:08
  • Why would it be a syntax error? It is perfectly legal to put an annotation there. – Jörg W Mittag Dec 19 '22 at 19:43

2 Answers2

32

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 
Thiyagu
  • 17,362
  • 5
  • 42
  • 79
  • 3
    Correct! The 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."* – Stephen C Dec 19 '22 at 08:10
  • 2
    Yes. Maybe you could add that those methods are auto-generated by the compiler, and you're overriding *those*. So while it's not obvious, you're still overriding. – MC Emperor Dec 19 '22 at 08:10
  • 2
    @Thiyagu - At this stage it is better to quote JLS 17 rather than the JEP. Records are no longer a preview feature, so JLS is now the definitive source of information. – Stephen C Dec 19 '22 at 08:44
  • @StephenC Makes sense. Will update my answer. Btw the JEP I've linked is part of the Java 16 release. Anyway I agree that quoting from JLS is better – Thiyagu Dec 19 '22 at 08:45
  • The requirement is: `var b1 = new BeardedDragon(...); var b2 = new BeardedDragon(b1.fun(); assert b1.equals(b2);`. – Johannes Kuhn Dec 19 '22 at 13:29
  • @JohannesKuhn My last example is unrelated to the requirement excerpt. – Thiyagu Dec 19 '22 at 13:33
  • My point is: It does not violate the requirement that you did quote. Or your example doesn't show that. – Johannes Kuhn Dec 19 '22 at 13:49
  • @JohannesKuhn The way I wrote it might have been confusing. I've updated it. I was trying to bring out two points. – Thiyagu Dec 19 '22 at 14:06
  • Why do they even allow you to override the record methods? The generated methods could implicitly final. What's the use-case? – Michael Dec 20 '22 at 15:12
  • 3
    @Michael Because an accessor may want to make a defensive copy for mutable components (such as arrays, or mutable collections) before returning it to the caller. For a record with mutable components (e.g., an ArrayList), there are two valid but different sets of semantics the record might want to implement, and both should be expressible. – Brian Goetz Dec 21 '22 at 20:46
16

There is something to override, namely the accessor for the record component fun. That is also a method called fun. Though, I agree that this is not the same kind of "override" as overriding a method in a superclass, which is how @Override is most often used for.

The @Override section of the spec talks about this.

The clause about a record class is due to the special meaning of @Override in a record declaration. Namely, it can be used to specify that a method declaration is an accessor method for a record component. Consider the following record declaration:

record Roo(int x) {
    @Override
    public int x() {
        return Math.abs(x);
    }
}

The use of @Override on the accessor method int x() ensures that if the record component x is modified or removed, then the corresponding accessor method must be modified or removed too.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • 1
    Quick question - I'll read the jls later :) - does this effectively generate a new class (like `@Override` on an enum value's method ends up in a new subclass of the enum being generated)? – ernest_k Dec 19 '22 at 08:16
  • 5
    @ernest_k No. The spec says it's a "special meaning", so it is a "hardcoded" construct just for record components. Section 8.10 (records) doesn't mention any anonymous classes like the one in the enum section, either. – Sweeper Dec 19 '22 at 08:24