Может ли интерфейс быть объявлен как final в Java?
Заключительный интерфейс в Java?
Ответ 1
Интерфейсы являются абстрактными 100%, и единственный способ создать экземпляр интерфейса - создать экземпляр класса, который его реализует. Разрешение интерфейсов final
совершенно бессмысленно.
РЕДАКТИРОВАТЬ Вопросы не так безобразны, как я думал сначала. Конечный интерфейс - это тот, который не может быть расширен другими интерфейсами, но может быть реализован, как представляется, имеет смысл.
Я мог бы подумать об одном различии между окончательным классом и окончательным интерфейсом. Расширение класса может скомпрометировать его целостность, поскольку оно содержит некоторое состояние. Расширение интерфейса просто добавляет операции и не может скомпрометировать целостность реализации, потому что интерфейс сам по себе не имеет места.
Ответ 2
Нет. Попытка объявить интерфейс как окончательный в Java приводит к ошибке компиляции. Это решение для языкового дизайна - интерфейсы Java предназначены для расширения.
Ответ 3
Нет. Раздел "Спецификация языка Java" 9.1.1. Модификаторы интерфейса сообщают следующее:
Объявление интерфейса может включать модификаторы интерфейса.
InterfaceModifier: (one of) Annotation public protected private abstract static strictfp
Как видно, список не включает final
.
Почему язык был разработан таким образом?
Если интерфейс был объявлен final
, я полагаю, это могло означать, что
-
Никакой другой интерфейс не может его расширить
Это было бы нечувствительным ограничением. Причинами, по которым полезно объявить окончательный класс, является защита инвариантов состояния, запрещение переопределения всех методов одновременно и т.д. Ни одно из этих ограничений не имеет смысла для интерфейсов. (Нет состояния, и все методы должны быть переопределены.)
-
Ни один класс не может реализовать интерфейс
Это явно полностью лишает цель интерфейса.
Ответ 4
Из спецификации языка Java (третье издание):
9.1.1.1 аннотация Интерфейсы
Каждый интерфейс неявно
abstract
. Этот модификатор устарел и не должны использоваться в новых программы.
Итак, abstract
+ final
является своего рода оксюмороном.
Ответ 5
Я попробовал это и, видимо, вы можете создать окончательный интерфейс в java. Я понятия не имею, почему вы это сделаете, но можете. Вот как я это сделал.
-
Скомпилируйте не финальный интерфейс. Я сохранил приведенный ниже код в FinalInterface.java. Затем я скомпилировал его.
ИнтерфейсFinalInterface { }
-
Запустите BCELifier. Это создало файл FinalInterfaceCreator.java
-
Отредактируйте его. Найдите строку, подобную приведенной ниже, и добавьте ACC_FINAL.
_cg = new ClassGen ( "FinalInterface", "java.lang.Object", "FinalInterface.java", ACC_INTERFACE | ACC_ABSTRACT | ACC_FINAL, новый String [] {});
-
Скомпилируйте и запустите отредактированный файл FinalInterfaceCreator.java. Это должно перезаписать исходный файл FinalInterface.class новым, похожим, но окончательным.
Чтобы протестировать его, я создал два новых Java файла TestInterface и TestClass. TestInterface - это интерфейс, который расширяет FinalInterface, а TestClass - это класс, который реализует FinalInterface. Компилятор отказался компилировать либо потому, что FinalInterface является окончательным.
TestClass.java:2: cannot inherit from final FinalInterface
class TestClass implements FinalInterface
TestInterface.java:2: cannot inherit from final FinalInterface
interface TestInterface extends FinalInterface
Кроме того, я попытался создать экземпляр FinalInterface с помощью динамических прокси-серверов
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 ) ) ;
}
}
Этот скомпилированный, но не запущенный
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)
Итак, данные свидетельствуют о том, что вы можете создать окончательный интерфейс в java, но зачем вам это нужно?
Ответ 6
В то время как окончательный интерфейс все равно будет использоваться, ни одна из них не считается общепринятой практикой.
Окончательный интерфейс можно использовать для
- определяющие константы. В общем считается плохой идеей.
- метаинформацию, подлежащую анализу посредством отражения, например. дескриптор пакета
- группирует множество открытых внутренних классов в один файл. (Только я предположите, что это используется, когда вырезать и вставлять некоторые примеры кода который имеет много классов, поскольку он сохраняет вам сложно создать файл для каждого класса, внутренние классы неявно статичны)
Вы можете делать все это с помощью не финального интерфейса и маркировать интерфейс как final, не так полезны, как комментарий, говорящий, что вы используете интерфейс для несекретной цели и почему вы это делаете.
Ответ 7
При разработке API в Java я иногда нахожу ситуацию, когда тип API должен быть Java интерфейсом, но количество его реализаций должно быть ограничено - например. только внутренние интерфейсы API могут реализовать его, а не другие.
Я понял, что теперь могу (начиная с Java 1.6) ограничивать, кто реализует интерфейс с помощью обработчиков аннотаций (статья на apidesign.org), Это код:
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());
}
}
}
Каждый раз, когда кто-то включает ваш JAR API в classpath и пытается скомпилировать его, компилятор Javac вызывает ваш обработчик аннотаций и позволяет вам сбой компиляции, если он обнаруживает, что кто-то еще пытается реализовать ваш интерфейс.
Я по-прежнему предпочитаю использовать окончательный класс для Client API - например. API, разрешенному только для других, но когда это невозможно, трюк с процессором аннотации является приемлемой альтернативой.
Ответ 8
Вместо объявления интерфейса в качестве финала, мы можем избежать создания объекта интерфейса.
Точка создания интерфейса для реализации своих методов по подклассу. Если мы побеждаем эту цель, я чувствую ее необоснованную.
Если есть какие-либо другие предложения, любезно сообщите нам
Ответ 9
Всякий раз, когда вы создаете аннотацию, вы создаете интерфейс, который в некотором смысле эффективен окончательно.
Ответ 10
Интерфейс, который не имеет члена, известен как маркер или помеченный интерфейс. Например: Serializable, Cloneable, Remote и т.д. Они используются для предоставления некоторой важной информации JVM, чтобы JVM могла выполнить некоторую полезную операцию.