Final interface in Java?
Asked Answered
N

11

35

Can an interface be declared as final in Java?

Northington answered 4/6, 2010 at 6:10 Comment(3)
Why not try it? Type out public final interface MyInterface {} and see if it compiles.Dependency
What are you expecting from a final interface?Headland
@mathk: Maybe he expected a "final interface" to be implementable (class implements interface) but not extensible (interface extends interface). Only guessing.Suburbanite
H
26

Interfaces are 100% abstract and the only way to create an instance of an interface is to instantiate a class that implements it. Allowing interfaces to be final is completely pointless.

EDIT The questions is not as outright outrageous as I first thought. A final interface is one that cannot be extended by other interfaces but can be implemented ostensibly makes sense.

I could think of one difference between a final class and a final interface. Extending a class can compromise its integrity because it contains some state. Extending an interface simply adds operations and cannot compromise the integrity of the implementation because the interface is stateless on its own.

Hhour answered 4/6, 2010 at 6:18 Comment(10)
Your sentences do not follow from each other. Final would prevent extension, not implementation. There are some interfaces such as Clonable and RandomAccess which it is very rare for other interfaces to extend, but are commonly implemented. As to whether explicitly preventing any interface from extending an interface is pointless, that's a different point.Interdiction
Fair point. I was thinking along the lines of a final interface is an interface that can't be implemented, didn't think about extending.Hhour
@IgorZevaka, > "Allowing interfaces to be final is completely pointless"; I disagree with this statement, because sometimes we use interfaces as "markers" or "tags" if you want. The real-life example is Validation Groups: @AssertTrue(message = "You need driving license", groups = DriverChecks.class) In such cases we sometimes want to make an interface final to make our intentions more explicit, i.e. tell others that this interfaces need not be implemented nor extended, but used as a "tag".Julio
and what about the case where you have an interface just for holding constants but you don't want any class to implement it ?Myrtismyrtle
+1 for the difference between final class and final interfaceHernardo
There's also another case where you want an interface to be implementable only within your package, which means "public code" can use the interface but not be able to implement it.Quarrier
The biggest reason to have a final interface that I encountered was for Owner integration. I want an interface that can not be extended by another interface. Since Owner only defines properties as interfaces within Java, there's no easy way to do this without adding my own annotations and enforcing it somehow on my own.Eden
@Myrtismyrtle It would be better to use a final class to hold constants.Gaikwar
Would there be any point in stopping an interface from being extended by another interface? If you need additional functions, you could just write extra methods in the implementing class, or even implement other interfaces.Gaikwar
@Gaikwar why is that so ?Myrtismyrtle
C
15

No. Trying to declare an interface as final in Java results in a compilation error. This is a language design decision - Java interfaces are meant to be extendable.

Ca answered 4/6, 2010 at 6:14 Comment(0)
C
15

No. The Java Language Specification section 9.1.1. Interface Modifiers states the following:

An interface declaration may include interface modifiers.

InterfaceModifier:
  (one of)
  Annotation public protected private
  abstract static strictfp

As can be seen, the list does not include final.

Why was the language designed this way?

If an interface was declared final I suppose it could have meant that

  • No other interface could extend it

    This would be a non-sensical restriction. The reasons for why it can be useful to declare a class final, is to protect state invariants, prohibit overriding of all methods at once, etc. None of these restrictions makes sense for interfaces. (There is no state, and all methods must be overridden.)

  • No class could implement the interface

    This obviously defeats the purpose of an interface altogether.

Censorious answered 4/6, 2010 at 7:11 Comment(1)
For what it's worth, a project I'm working at contains an interface that is nothing but a collection of static constants to be used in other classes. I couldn't say whether that's bad design or not (the fact that it exists to help us sidestep SonarQube's "no magic numbers" rule without really fixing it looks a lot more questionable, on the other hand).Filament
S
9

From the Java Language Specification (Third Edition):

9.1.1.1 abstract Interfaces

Every interface is implicitly abstract. This modifier is obsolete and should not be used in new programs.

So, abstract + final is sort of an oxymoron.

Suburbanite answered 4/6, 2010 at 6:26 Comment(2)
Such class can still be used as a template for code generation.Bring
class? They are talking interface. Even so, my compiler says MyClass can either be abstract or final, not both.Suburbanite
S
4

I tried it and apparently you can create a final interface in java. I have no idea why you would do this, but you can. This is how I did it.

  1. Compile a non final interface. I saved the below code in FinalInterface.java. Then I compiled it.

    interface FinalInterface { }

  2. Run BCELifier on it. This created a file called FinalInterfaceCreator.java

  3. Edit it. Look for a line similar to below and add ACC_FINAL.

    _cg = new ClassGen("FinalInterface", "java.lang.Object", "FinalInterface.java", ACC_INTERFACE | ACC_ABSTRACT | ACC_FINAL , new String[] { });

  4. Compile and run the edited FinalInterfaceCreator.java. This should overwrite the original FinalInterface.class file with a new one that is similar but final.

To test it, I created two new java files TestInterface and TestClass. TestInterface is an interface that extends FinalInterface and TestClass is a class that implements FinalInterface. The compiler refused to compile either because FinalInterface is final.

TestClass.java:2: cannot inherit from final FinalInterface
class TestClass implements FinalInterface

TestInterface.java:2: cannot inherit from final FinalInterface
interface TestInterface extends FinalInterface

In addition, I tried creating an instance of FinalInterface using dynamic proxies

class Main
{
    public static void main ( String [ ] args )
    {
    Class < ? > ntrfc = FinalInterface . class ;
    ClassLoader classLoader = ntrfc . getClassLoader ( ) ;
    Class < ? > [ ] interfaces = { ntrfc } ;
    java . lang . reflect . InvocationHandler invocationHandler = new java . lang . reflect . InvocationHandler ( )
        {
        public Object invoke ( Object proxy , java . lang . reflect . Method method , Object [ ] args )
        {
            return ( null ) ;
        }
        } ;
    FinalInterface fi = ( FinalInterface ) ( java . lang . reflect . Proxy . newProxyInstance ( classLoader , interfaces , invocationHandler ) ) ;
    }
}

This one compiled but did not run

Exception in thread "main" java.lang.ClassFormatError: Illegal class modifiers in class FinalInterface: 0x610
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:632)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:319)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:264)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:332)
at Main.main(Main.java:6)

So the evidence suggests that you can create a final interface in java, but why would you want to?

Selfpity answered 4/6, 2010 at 12:21 Comment(2)
"apparently you can create a final interface in java" -- Nice answer, but you are mixing up bytecode with Java severely. As @Suburbanite states in his answer it is not possible to create a final interface. (Regardless of the sequence of bytes you can assemble that looks like a .class file.)Censorious
As you saw, it is not valid for an interface to have it's ACC_FINAL flag set. The compiler happens to let you compile against an invalid class file, but this doesn't really mean anything. According to the JVM specification, "If the ACC_INTERFACE flag of this class file is set, its ACC_ABSTRACT flag must also be set (JLS §9.1.1.1). Such a class file must not have its ACC_FINAL, ACC_SUPER or ACC_ENUM flags set."Surah
W
2

While a final interface would still have uses, none of them are widely considered good practice.

A final interface could be used for

  • defining constants. Generally considered a bad idea.
  • meta-information to be examined via reflection, e.g. a package descriptor
  • grouping together many public inner classes into one file. (I only suggest this is used when cut-and-pasting some sample code which has many classes as it saves you the hassle of creating a file for each class, inner classes are implicitly static)

You can do all these things with a non-final interface and marking an interface as final would not be as useful as a comment saysing you are using an interface for an incedental purpose and why you are doing so

Winona answered 4/6, 2010 at 8:56 Comment(0)
J
2

Sealed interface

If you want to limit who can extend and implement the interface, you can use sealed in Java 17+. See JEP 409: Sealed Classes.

sealed interface A permits B, C {}

final class B implements A {}

non-sealed interface C extends A {}

You have to permit both B and C. The class (B) has to be final, sealed, or non-sealed. The interface (C) has to be sealed, or non-sealed.

Jilli answered 23/9, 2023 at 20:27 Comment(0)
B
1

When designing APIs in Java I sometimes find a situation where a type in the API has to be Java interface, but the number of its implementations should be limited - e.g. only the APIs internals can implement it, not anyone else.

I realized I can now (since Java 1.6) restrict who implements an interface with the help of annotation processors (article on apidesign.org). This is the code:

package org.apidesign.demo.finalinterface;

import java.util.Collection;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.openide.util.lookup.ServiceProvider;

@ServiceProvider(service = Processor.class)
@SupportedAnnotationTypes("*")
public final class FinalEnforcingProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        checkForViolations(roundEnv.getRootElements());
        return true;
    }

    private void checkForViolations(Collection<? extends Element> all) {
        for (Element e : all) {
            if (e instanceof TypeElement) {
                TypeElement te = (TypeElement) e;
/* exception for the only known implementation:
if ("org.apidesign.demo.finalinterface.AllowedImplementationTest".equals(
  te.getQualifiedName().toString())
) continue;
*/
                for (TypeMirror m : te.getInterfaces()) {
                    if (FinalInterface.class.getName().equals(m.toString())) {
                        processingEnv.getMessager().printMessage(
                          Diagnostic.Kind.ERROR, "Cannot implement FinalInterface", e
                        );
                    }
                }
            }
            checkForViolations(e.getEnclosedElements());
        }
    }
 }

Everytime somebody includes your API JAR on classpath and tries to compile against it, the Javac compiler invokes your annotation processor and let's you fail the compilation if it detects somebody else is trying to implement your interface.

I still prefer usage of final class for Client API - e.g. an API that others are only allowed to call, but when it is not possible, the trick with annotation processor is acceptable alternative.

Bemused answered 13/8, 2015 at 5:3 Comment(2)
interesting approach though the provider example seems to be netbeans specific.Ingratiating
There seems to be one fundamental flaw of that approach: It requires the user to actually use the annotation processor. Use the -proc:none command line option, and you no longer enforce the limitation... I'd rather make the class package private and seal the package...Sackcloth
M
0

final means it can't be modified. If it's a class, it can't be modified by extending (methods can be modified by overriding, attribute's can't be modified; added attributes/methods can only be accessed as members of the 'subclass type'); if its a variable (attribute/local) then the value can't be modified after first assignment; if its a method, the implementation can't be modified (a final method can be overloaded but can't be overridden). There no point in declaring an interface final since there's normally no implementation to modify (default and static interface methods are not allowed to be final).

Momus answered 23/2, 2018 at 4:40 Comment(0)
H
-1

Instead of Declaring Interface as a Final, We can avoid Creating an Interface object.

Point of Creating Interface to implements its methods by its subclass. If we are defeating this purpose then I feel its a baseless.

If any have any other suggestions, kindly let us know

Harquebus answered 4/6, 2010 at 7:36 Comment(1)
The reason for downvoting please?Harquebus
S
-1

Whenever you create an annotation you are creating an interface that is in some ways effectively final.

Selfpity answered 4/6, 2010 at 12:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.