Interface finale en Java?

Une interface peut-elle être déclarée comme finale en Java?

29
demandé sur aioobe 2010-06-04 10:10:51

11 réponses

Les Interfaces sont 100% abstraites et la seule façon de créer une instance d'une interface est d'instancier une classe qui l'implémente. Permettre aux interfaces d'être final est complètement inutile.

EDIT les questions ne sont pas aussi scandaleuses que je le pensais. Une interface finale est une interface qui ne peut pas être étendue par d'autres interfaces mais qui peut être implémentée de manière ostensiblement logique.

Je pourrais penser à une différence entre une classe finale et une interface finale. Étendre une classe peut compromettre son intégrité car elle contient un État. L'extension d'une interface ajoute simplement des opérations et ne peut pas compromettre l'intégrité de l'implémentation car l'interface est sans état seule.

21
répondu Igor Zevaka 2010-06-04 08:04:15

Non. Essayer de déclarer une interface comme finale en Java entraîne une erreur de compilation. Il s'agit d'une décision de conception de langage - les interfaces Java sont destinées à être extensibles.

14
répondu Jordan Lewis 2010-06-04 06:14:16

Non. La section Spécification du langage Java 9.1.1. Les modificateurs d'Interface indiquent ce qui suit:

Une déclaration d'interface peut inclure des modificateurs d'interface.

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

Comme on peut le voir, la liste n'inclut pas final.

Pourquoi le langage conçu de cette façon?

Si une interface a été déclarée final je suppose que cela aurait pu signifier que

  • Aucune autre interface ne pourrait l'étendre

    , Ce serait un non-sens restriction. Les raisons pour lesquelles il peut être utile de déclarer uneclasse final, est de protéger les invariants d'état, d'interdire le remplacement de toutes les méthodes à la fois,etc. Aucune de ces restrictions n'a de sens pour les interfaces. (Il n'y a pas d'état, et toutes les méthodes doivent être remplacées.)

  • Aucune classe n'a pu implémenter l'interface

    Cela va évidemment à l'encontre du but d'une interface tout à fait.

10
répondu aioobe 2016-08-25 11:14:43

De la spécification du langage Java (troisième édition):

9.1.1.1 des Interfaces abstraites

Chaque interface est implicitement abstract. Ce modificateur est obsolète et ne doit pas être utilisé dans le nouveau programme.

, de Sorte, abstract + final est une sorte d'oxymore.

8
répondu bakkal 2010-06-04 06:26:22

, je l'ai essayé et apparemment, vous pouvez créer une interface finale en java. Je ne sais pas pourquoi vous feriez ça, mais vous pouvez. C'est la façon dont je l'ai fait.

  1. Compiler une interface non finale. J'ai enregistré le code ci-dessous dans FinalInterface.Java. Puis j'ai compilé.

    Interface FinalInterface { }

  2. Exécutez BCELifier dessus. Cela a créé un fichier appelé FinalInterfaceCreator.java

  3. Éditez-le. Recherchez une ligne similaire à ci-dessous et ajouter ACC_FINAL.

    _cg = New ClassGen ("FinalInterface", " java.lang.Objet", " FinalInterface.java", ACC_INTERFACE / ACC_ABSTRACT | ACC_FINAL, nouvelle chaîne [] { });

  4. Compilez et exécutez le FinalInterfaceCreator édité.Java. Cela devrait écraser la FinalInterface d'origine.fichier de classe avec un nouveau qui est similaire, mais définitive.

Pour le tester, j'ai créé deux nouveaux fichiers java TestInterface et TestClass. TestInterface est une interface qui étend FinalInterface et TestClass est une classe qui implémente FinalInterface. Le compilateur a refusé de compiler soit parce que FinalInterface est 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

En outre, j'ai essayé de créer une instance de FinalInterface en utilisant des proxies dynamiques

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 ) ) ;
    }
}

Celui-ci compilé mais n'a pas exécuté

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)

Ainsi, la preuve suggère que vous pouvez créer une interface finale en java, mais pourquoi voudriez-vous?

4
répondu emory 2010-06-04 12:21:46

Bien qu'une interface finale ait encore des utilisations, aucune d'entre elles n'est largement considérée comme une bonne pratique.

Une interface finale pourrait être utilisée pour

  • définition des constantes. Généralement considérée comme une mauvaise idée.
  • méta-informations à examiner par réflexion, par exemple un descripteur de paquet
  • regrouper de nombreuses classes internes publiques en un seul fichier. (Je ne suggérer ceci est utilisé lorsque couper-coller un exemple de code qui a beaucoup de classes comme il sauve vous les tracas de la création d'un fichier pour chaque classe, les classes internes sont implicitement statiques)

Vous pouvez faire toutes ces choses avec une interface non finale et marquer une interface comme finale ne serait pas aussi utile qu'un commentaire disant que vous utilisez une interface dans un but incédental et pourquoi vous le faites

2
répondu Peter Lawrey 2016-08-25 10:01:20

Lors de la conception D'API dans Java je trouve parfois une situation où un type dans L'API doit être Java interface, mais le nombre de ses implémentations doit être limité - par exemple, seules les API internes peuvent l'implémenter, pas n'importe qui d'autre.

J'ai réalisé que je peux maintenant (depuis Java 1.6) restreindre qui implémente une interface à l'aide de processeurs d'annotation (article sur apidesign.org ). C'est le 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());
        }
    }
 }

Chaque fois que quelqu'un comprend votre jar API sur classpath et essaie de compiler contre lui, le compilateur Javac appelle votre processeur d'annotation et vous permet d'échouer la compilation s'il détecte que quelqu'un d'autre essaie d'implémenter votre interface.

Je préfère toujours l'utilisation de Final class pour Client API - par exemple une API que les autres ne sont autorisés à appeler, mais quand ce n'est pas possible, l'astuce avec le processeur d'annotation est une alternative acceptable.

1
répondu Jaroslav Tulach 2015-08-13 05:03:58

Finale signifie qu'il ne peut pas être modifié. Si c'est une classe, elle ne peut pas être modifiée en étendant (les méthodes peuvent être modifiées en remplaçant, les attributs ne peuvent pas être modifiés; les attributs/méthodes ajoutés ne peuvent être accessibles qu'en tant que membres du 'type de sous-classe'); si c'est une variable (attribut/local), la valeur ne peut pas être modifiée après la première affectation; si c'est une méthode, l'implémentation ne peut pas être modifiée (une méthode finale peut être surchargée mais ne peut pas être remplacée). Il ne sert à rien de déclarer une interface finale comme il n'y a normalement aucune implémentation à modifier (les méthodes d'interface par défaut et statiques ne sont pas autorisées à être finales).

0
répondu Roy Aliin 2018-02-23 04:50:31

Au lieu de déclarer L'Interface comme finale, nous pouvons éviter de créer un objet Interface.

Point de création D'Interface pour implémenter ses méthodes par sa sous-classe. Si nous vainquons ce but, alors je sens que c'est sans fondement.

Si vous avez d'autres suggestions, veuillez nous le faire savoir

-1
répondu gmhk 2010-06-04 07:36:14

Chaque fois que vous créez une annotation, vous créez une interface qui est effectivement définitive.

-1
répondu emory 2010-06-04 12:32:16

Une interface qui n'a pas de membre est connue sous le nom de marqueur ou d'interface étiquetée. Par exemple: Serializable, Cloneable, à distance etc. Ils sont utilisés pour fournir des informations essentielles à la JVM afin que la JVM puisse effectuer une opération utile.

-1
répondu Roopam 2015-04-11 16:11:37