47

To my understanding, the following code should have printed true as output.

However, when I ran this code it is printing false.

From Java docs of Anonymous Classes 15.9.5. :

An anonymous class is always implicitly final

public class Test {
    public static void main(String args[]) {
        Object o = new Object() {
        };
        System.out.println("Annonymous class is final: " + Modifier.isFinal(o.getClass().getModifiers()));
    }
}

Why this code is behaving like this ?

T-Bag
  • 10,916
  • 3
  • 54
  • 118
  • Possible duplicate of [Anonymous Inner classes and Final modifier](https://stackoverflow.com/questions/44817768/anonymous-inner-classes-and-final-modifier) – miken32 May 06 '19 at 19:03
  • @miken32 I have reversed the close vote on your suggestion, because the answers to this question are far more clear than on the question you suggested. – Mark Rotteveel May 07 '19 at 18:04

4 Answers4

50

Note that the wording in the JLS of that particular section has changed significantly since then. It now (JLS 11) reads:

15.9.5. Anonymous Class Declarations:

An anonymous class is never final (§8.1.1.2).

The fact that an anonymous class is not final is relevant in casting, in particular the narrowing reference conversion allowed for the cast operator (§5.5). It is also of interest in subclassing, in that it is impossible to declare a subclass of an anonymous class, despite an anonymous class being non-final, because an anonymous class cannot be named by an extends clause (§8.1.4).

This change in wording was introduced in JLS 9. The semantics of anonymous classes and the behavior of the methods in the question remained mostly unchanged, the intention was to avoid exactly the kind of confusion this question is about.

The ticket that caused the change says:

Longstanding behavior of javac, since 1.3, has been, for the most part, not to treat the classes as 'final'. To address this inconsistency, the specification should be changed to accurately reflect the reference implementation.

Specifically, anonymous classes are almost never generated with the ACC_FINAL flag set. We can't change this longstanding behavior without impacting some serialization clients (this would be permissible, but is unnecessarily disruptive). And we can't faithfully implement Class.getModifers (which promises to provide the "Java language modifiers") without the class files encoding the language's modifiers.

However, the change did actually change semantics to some degree, and this was also documented in this ticket as an acceptable impact:

The change impacts the set of legal programs, in that it allows some casts that would be considered illegal under the current specification (see JDK-6219964). But, after searching for mentions of 'final' classes in JLS, I don't anticipate any other impact, meaning that this is a source-compatible fix.

Community
  • 1
  • 1
Hulk
  • 6,399
  • 1
  • 30
  • 52
  • 3
    Though the spec has been updated, I don't think the old one is contradictory - just unclear. Anonymous classes are implicitly final in *two* senses: inherently (the developer cannot avoid it), and discreetly (not directly expressed - neither by the developer nor the class itself). – Jacob Raihle Jan 03 '19 at 16:05
  • 2
    Yeah, the good old “change the specification to match what our … implementation does”… – Holger Jan 09 '19 at 11:27
  • 2
    I do not agree that “The semantics of anonymous classes … remained unchanged”. Java 8 did not compile `CharSequence c2 = (CharSequence)new Object() {};` whereas Java 9 does. In other words, the language semantics have changed completely, for the sake of keeping compatibility to a bug that only affected Reflection. – Holger Jun 17 '20 at 16:01
  • 2
    @Holger I added a quote from the ticket - it seems that this effect was known at the time of the change and considered acceptable. – Hulk Jun 17 '20 at 16:24
10

An anonymous class is never final (§8.1.1.2).

JLS 11 - 15.9.5. Anonymous Class Declarations

I didn't know the reasoning behind this, but, according to @Hulk's answer and this bug report, it seems the specification of previous versions slightly misled us saying that anonymous classes are final.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • 3
    You've linked to exactly the same section as the OP, but a more up-to-date version of the JLS. Perhaps it is worth describing why the discrepancy exists between the two versions rather than simply quoting the newer one. – Michael Jan 03 '19 at 09:26
  • @GhostCat I usually comment on reopening, it's my bad I didn't let you know. I am a lazy as*, and probably I should have added more links instead of reopening :) – Andrew Tobilko Jun 11 '19 at 13:12
  • @AndrewTobilko Never mind, as so often Sotirios did a good job on dup-closing ;-) – GhostCat Jun 11 '19 at 13:15
9

Anonymous classes are considered implicitly final since you can't create sub-classes of them. That doesn't mean that the Modifier.FINAL modifier should be set for anonymous classes.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • When you say implicitly final, Does not that mean it is FINAL and should follow all the rules of Final keyword in java – T-Bag Jan 03 '19 at 10:32
  • 1
    @ShowStopper well, it _does_ follow the rules of `final`: you can't subclass them, because there's no way to refer to them as a type. I suppose is why they're _implicitly_ final. – Salem Jan 03 '19 at 10:40
-2

See Javadoc of Class.getModifiers(): https://docs.oracle.com/javase/10/docs/api/java/lang/Class.html#getModifiers()

It says "...The values of its other modifiers are not determined by this specification".

Prasad Karunagoda
  • 2,048
  • 2
  • 12
  • 16