Страницы

Поиск по вопросам

четверг, 8 ноября 2018 г.

Зачем нужны inner классы в интерфейсах в Java?

На мой взгляд, интерфейсы служат для разделения абстракции и реализации. Собственно, зачем может понадобиться внутри интерфейса создавать класс, который будет обладать некоторой реализацией? Хотелось бы увидеть реальный пример использования внутренних классов в интерфейсах, чтобы понять, как такая особенность Java может быть использована.


Ответ

Пробежался структурным поиском по своему CLASSPATH и выловил следующие примеры:
Интерфейс как пространство имен
Самое частое - статический еnum, связнанный предметной областью с интерфейсом, объявленный внутри интерфейса. Интерфейс в данном случае играет роль пространства имен.
public interface Foo { void foo(Bar bar);
static enum Bar { BAR1, BAR2, BAR3 } }
Пример:
com.google.common.util.concurrent.Service

Похожий вариант - класс, описывающий value-тип, связанный с интерфейсом.
public interface Foo { void foo(Bar bar);
static class Bar { private final String id; public Bar(Sting id) { this.id = id; } public String getId() { return id; } } }
Пример:
org.hibernate.persister.entity.Queryable io.undertow.security.api.AuthenticationMechanism

Несколько маленьких классов внутри интерфейса реализующих другой очень узкий интерфейс. Интерфейс используется только как пространство имен.
public interface Convertor { String convert(Object arg); }
public interface Convertors { static class Convertor1 implements Convertor { String convert(Object arg) { /* ... */ }} static class Convertor2 implements Convertor { String convert(Object arg) { /* ... */ }} static class Convertor3 implements Convertor { String convert(Object arg) { /* ... */ }} }
Пример:
org.hibernate.tuple.TimestampGenerators

Исключение, связанное с интерфейсом.
public interface Foo { void foo() throws BarException;
static class BarException extends Exception { // ... } }
Пример:
org.hibernate.boot.spi.InFlightMetadataCollector

Интерфейс объявляет внутри себя вспомогательные helper-классы с логикой, которые предлагает использовать реализациям.
Пример:
org.eclipse.jetty.io.ByteBufferPool com.mysql.jdbc.SocketMetadata (5.1.39)

Интерфейс объявляет внутри себя готовую реализацию-заглушку.
public interface Foo { Bar foo();
static class FooImpl implements Foo { @Override public void foo() { return null; } } }
Пример:
org.junit.Test com.codahale.metrics.MetricRegistryListener

Интерфейс объявляет внутри себя Singleton, потому что "почему бы и нет": и так антипаттерн, так хоть локализовать его.
Пример:
org.asynchttpclient.channel.ChannelPoolPartitioning

Аннотация + обработчик
Статический класс реализующий некий интерфейс внутри интерфейса-аннотации описывающий логику этой аннотации. Код, анализирующий аннотации скорее всего доберется до этого статического класса через рефлексию.
@Retention(RetentionPolicy.RUNTIME) public @interface Foo { // annotation fields
static class FooHandler implements Handler { public void handle(Foo foo, Object arg) { //... } } }
public interface Handler { void handle(A a, Object arg); }
Примеры:
javax.annotation.RegEx javax.annotation.Nonnull javax.annotation.Nonnegative

Комментариев нет:

Отправить комментарий