Недавно Lukas JOOQ Eder опубликовал и статью о вложенных классах и их использовании. Это интересная тема, и его статья, как всегда, интересна и заслуживает прочтения. Было только одно небольшое утверждение, с которым я не мог согласиться, и у нас была короткая цепочка ответов, приводящая к методу по умолчанию, и почему не может быть что-то вроде
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
class Outer { <non- static > interface Inner { default void x() { System.out.println(Outer. this .toString()); } } Inner2 y() { return new Inner2(); } } class Inner2 implements Inner { } // This would now print Outer.toString() // to the console new Outer().y().x(); |
на Яве. В приведенном выше коде метод по умолчанию для внутреннего интерфейса будет относиться к экземпляру, который включает в себя интерфейс, так сказать. Я считал, что «ответ» был не самой лучшей формой общения для этого, так как оригинальная тема была другой, и здесь я иду.
Какие методы по умолчанию
Вы, наверное, знаете. Если не Google, или прочитайте мои статьи Java 8 по умолчанию методы: что можно, а что нельзя? и Как не использовать методы Java 8 по умолчанию .
Если вы погуглили, вы увидите, что методы по умолчанию в Java 8 содержат Ханаан, доступно множественное наследование.
Существует очень хорошая дискуссия об этом над стековым потоком с настоящими профессионалами, которые знают Java:
У Java всегда было множественное наследование типов. Методы по умолчанию добавляют множественное наследование поведения, но не состояния. (Множественное наследование состояний в таких языках, как C ++, является источником большинства проблем.) — Брайан Гетц 21 июня ’14 в 2:05
В этой статье я немного расскажу, как интерпретировать и понять это утверждение.
Типы наследования
Цитата Брайана Гетца упоминает:
- наследование типов
- наследование поведения и
- наследство гос.
Наследование типов очень просто и хорошо известно программистам Java. Вы определяете абстрактные методы в интерфейсе, но не указываете, как они работают, только возвращаемое значение и подпись методов. С методами по умолчанию Java 8 ввел наследование поведения без наследования состояния. Но разве можно наследовать поведение без наследования государства? На самом деле, нет. По крайней мере, в Java 8 вы можете иметь наследование состояния, хотя это не рекомендуется, неэффективно (я имею в виду: оно может быть медленным), а также громоздким и подверженным ошибкам программы. Но вы можете, и я покажу здесь, как. (В дополнение к ветке местной чепухи я опубликовал в статье, которую я упоминал выше.)
Я считаю, что изобретатели Java 8 хотели, чтобы метод по умолчанию сохранял обратную совместимость при реализации функциональных интерфейсов (например, потоков) в стандартное время выполнения. Недавно я смотрел сериал Fargo, и я чувствую, что дизайнеры языка просто забыли ответить «да» на вопрос «Ты действительно этого хочешь?»
Наследование состояний с помощью методов по умолчанию
Методы по умолчанию не могут получить доступ к полям (кроме статических полей, которые в любом случае являются окончательными в интерфейсах, поэтому давайте на время их забудем). Точно так же, как вы не можете получить доступ к закрытым полям класса A из класса B, расширяющего A. Или наоборот: вы не можете получить доступ к закрытым полям B из A. Однако вы можете иметь методы получения и установки в B, и если вы объявите их как абстрактные методы в A вы получаете доступ. Сезам, откройся. Геттеры и сеттеры являются решением.
Когда вы объявляете абстрактные методы в интерфейсе для всех полей состояния, к которым вы хотите получить доступ из методов по умолчанию, вы можете получить к ним доступ. Таким образом, вы получите тот же результат, как если бы существовало реальное наследование состояния. Разница заключается в синтаксисе: вы используете методы getter и setter вместо имени поля, и вы должны объявить их в интерфейсе. Таким образом, фаза компиляции проверяет, что геттеры и сеттеры действительно есть.
Вы можете видеть, что вещи с Java 8 становятся действительно сложными. Смешайте это с дженериками, и вы не сможете найти живую душу, которая все это понимает. Имея конструкцию, как
1
|
Outer. this .toString() |
из приведенного выше примера кода, возможно, будет еще сложнее, без реальных рычагов.
Я считаю, что у меня есть некоторые знания о том, какие методы по умолчанию в Java 8 и что вы можете с ними сделать. Однако, имея 10 лет работы с Java и более 30 лет опыта программирования, я не могу сказать, как использовать методы по умолчанию. Я завидую разработчикам, которые все еще работают с Java 1.6 или более ранней версией в производственном коде: им не нужно беспокоиться о методах по умолчанию. (Это должно было быть шуткой.)
Хотя я пытаюсь дать несколько советов.
Рекомендация
Никогда не имитируйте наследование состояния в методах по умолчанию. Трудно сказать, что это на практике, хотя. Вызов геттера или сеттера явно есть. Вызов некоторых абстрактных методов, которые реализованы в реализующем классе, может быть или не быть. Если сомневаешься: лучше не надо.
Никогда не используйте трюк с локальным потоком, который я написал в другой статье.
Используйте методы по умолчанию для того, что использовали изобретатели языка Java: сохраняйте обратную совместимость в интерфейсах вашей библиотеки. Если вы когда-либо выпускали библиотеку, и она содержит интерфейс (как иначе, кстати) , не меняйте ее… Подумайте о клиентском коде, использующем вашу библиотеку, которая реализует интерфейс. С Java 8 у вас есть возможность закончить предложение: не меняйте его несовместимым. Если есть новый метод: создайте реализацию по умолчанию, чтобы код, который уже реализовал предыдущую версию, оставался совместимым, и нет необходимости расширять эти классы.
Ссылка: | Методы по умолчанию и множественное наследование от нашего партнера JCG Питера Верхаса из блога Java Deep . |