7

To my understand correctly anonymous classes are always final:

This has been mentioned specifically in JLS 15.9.5

However, when i run the following code to check that it is showing that Inner class is not final.

    public class Test{
    static class A<T> {
    }
    public static void main(String arg[]) {
        A<Integer> obj = new A() {
        };
        if ((obj.getClass().getModifiers() & Modifier.FINAL) != 0) {
            System.out.println("It is a final  " + obj.getClass().getModifiers());
        } else {
            System.out.println("It is not final " + obj.getClass().getModifiers());
        }
    }
}

Output of above program is :

It is not final 0

Please clear my doubt as i am not able to understand this behavior.

T-Bag
  • 10,916
  • 3
  • 54
  • 118

3 Answers3

3

I agree this may be considered a bug, given that other cases in the JLS exhibit a different behavior. Case in point is an interface: As per section 9.1.1.1:

Every interface is implicitly abstract.

And when running the below:

interface X {
    void foo();
}

public static void main(String arg[]) {
    System.out.println(Modifier.isAbstract(X.class.getModifiers()));
}

It returns true.

Another example is an enum where the JLS specifies:

An enum declaration is implicitly final unless it contains at least one enum constant that has a class body

And the below example is perfectly aligned with it.

enum X {

}

public static void main(String arg[]) {
    System.out.println(Modifier.isFinal(X.class.getModifiers()));  // true
}
M A
  • 71,713
  • 13
  • 134
  • 174
  • Every interface is implicitly abstract, but you have made it explicit. You'd better remove the `abstract` keyword. – MC Emperor Jun 29 '17 at 07:12
  • I disagree with the term "bug". The problem is that *implicitly* is too vague and the case of interfaces/enums is different than this of anonymous classes. What is a final class? a class that you can't subclass, so it is the case for anonymouses, there is no necessity to mark them as such, there is no interesting benefit in either cases (or?). – Jean-Baptiste Yunès Jun 29 '17 at 07:45
  • @Jean-BaptisteYunès I would tend to understand the word "implicitly" as that you don't need to explicitly mark it in the code, but still after all it is final and the modifier implementation does not reflect that, which is the "bug" that I'm referring to. The same word "implicitly" occurs elsewhere in the JLS and the reflection code yields a positive result in those cases. – M A Jun 29 '17 at 08:06
  • 1
    @Jean-BaptisteYunès it *was* a bug and the solution was , [to change the specification](https://stackoverflow.com/a/54019398/2711488): “*an anonymous class is never final*”. – Holger Jan 10 '19 at 18:21
1

Explicit is something what is written in the source code. So, if something is declared as public final class, it means that the class is explicitly final.

Implicit is something that is not written down in the source code, but that in the context of a certain construct or based on the language rules, an element behaves as it were declared with the specified modifier.

For example, the keyword enum in the declaration enum SomeEnum { } causes SomeEnum to be final, because the language rules prescribe it. Its effect is the same as the effect of the keyword final.

The example of an anonymous class being implicitly final is because no language construct exists to override an anonymous class. So it behaves as if it were final. I think the word "effectively" is better here.


However, you cannot make assumptions based on how reflection presents things. Consider the following snippet:

public class Test {
    interface SomeInterface { }
    abstract interface SomeAbstractInterface { }
    static abstract class SomeAbstractClass { }
    enum SomeEnum { }

    public static void main(String arg[]) {
        System.out.println(Modifier.toString(SomeInterface.class.getModifiers()));
        System.out.println(Modifier.toString(SomeAbstractInterface.class.getModifiers()));
        System.out.println(Modifier.toString(SomeAbstractClass.class.getModifiers()));
        System.out.println(Modifier.toString(SomeEnum.class.getModifiers()));
    }
}

The result is this:

abstract static interface
abstract static interface
abstract static
static final

Both interface and abstract interface are considered an abstract interface. They are also considered static by reflection. Apparently, in the process of parsing and compiling the Java source code, some modifiers could be removed or added.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • Actually, the Reflection behavior is consistent with the compile time behavior, e.g. `javac` allows an instance of an anonymous inner class to be cast to an interface type it does not implement, which would not be allowed for `final` types, indicating that the anonymous inner class is not actually final. Nowadays, [even the specification reflects this fact](https://stackoverflow.com/a/54019398/2711488), “*an anonymous class is never final*”. – Holger Jan 10 '19 at 18:20
0

JLS 15.9.5 "...implicitly final"... But that is not "final", what is meant is that you just can't extend an anonymous class. There is no syntactic construction for this, but the class is not marked as final.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • I can understand there is no syntactic construction but it should pass the final check isn't. – T-Bag Jun 29 '17 at 06:31
  • No, it is `final` because it can't be extended, not because it is marked `final`. So there is no modifier to it, but no matter what you try, you will not be able to extend an anonymous class, meaning it is by definition `final`. – AxelH Jun 29 '17 at 06:39