РЕДАКТИРОВАТЬ: Начиная с Java 8, статические методы теперь разрешены в интерфейсах.
Вот пример:
public interface IXMLizable<T>
{
static T newInstanceFromXML(Element e);
Element toXMLElement();
}
Конечно, это не сработает. Но почему нет?
Одной из возможных проблем будет то, что происходит, когда вы звоните:
IXMLizable.newInstanceFromXML(e);
В этом случае я думаю, что он должен просто вызвать пустой метод (то есть {}). Все подклассы будут вынуждены реализовать статический метод, поэтому все они будут в порядке при вызове статического метода. Так почему же это невозможно?
РЕДАКТИРОВАТЬ: Я думаю, что я ищу ответ, который глубже, чем «потому что это так, как Java».
Есть ли конкретная технологическая причина, по которой статические методы нельзя перезаписать? То есть, почему разработчики Java решили сделать методы экземпляров переопределенными, а не статическими?
РЕДАКТИРОВАТЬ: проблема с моим дизайном в том, что я пытаюсь использовать интерфейсы для обеспечения соблюдения правил кодирования.
То есть цель интерфейса двояка:
Я хочу, чтобы интерфейс IXMLizable позволял мне преобразовывать классы, которые его реализуют, в элементы XML (используя полиморфизм, работает нормально).
Если кто-то хочет создать новый экземпляр класса, который реализует интерфейс IXMLizable, он всегда будет знать, что будет статический конструктор newInstanceFromXML (Element e).
Есть ли другой способ обеспечить это, кроме размещения комментария в интерфейсе?
источник
Ответы:
Java 8 допускает статические методы интерфейса
В Java 8 интерфейсы могут иметь статические методы. Они также могут иметь конкретные методы экземпляра, но не поля экземпляра.
Здесь действительно два вопроса:
Статические методы в интерфейсах
Не было веской технической причины, по которой интерфейсы не могли иметь статические методы в предыдущих версиях. Это хорошо подытожено постером дубликата вопроса. Методы статического интерфейса изначально рассматривались как небольшое изменение языка, а затем было официальное предложение добавить их в Java 7, но позднее оно было отброшено из-за непредвиденных сложностей.
Наконец, Java 8 представила статические методы интерфейса, а также перезаписываемые методы экземпляров с реализацией по умолчанию. Они все еще не могут иметь поля экземпляра, хотя. Эти функции являются частью поддержки лямбда-выражений, и вы можете прочитать больше о них в Части H JSR 335.
Переопределение статических методов
Ответ на второй вопрос немного сложнее.
Статические методы разрешимы во время компиляции. Динамическая диспетчеризация имеет смысл для методов экземпляра, где компилятор не может определить конкретный тип объекта и, следовательно, не может разрешить вызываемый метод. Но для вызова статического метода требуется класс, и поскольку этот класс известен статически - во время компиляции - динамическая диспетчеризация не .
Небольшое представление о том, как работают экземпляры, необходимо, чтобы понять, что здесь происходит. Я уверен, что фактическая реализация совершенно иная, но позвольте мне объяснить мое представление о методе диспетчеризации, который модели точно наблюдал поведение.
Представьте, что у каждого класса есть хеш-таблица, которая отображает сигнатуры методов (имена и типы параметров) на фактический кусок кода для реализации метода. Когда виртуальная машина пытается вызвать метод в экземпляре, она запрашивает у объекта свой класс и ищет запрошенную подпись в таблице класса. Если тело метода найдено, оно вызывается. Иначе, родительский класс класса получен, и поиск там повторяется. Это продолжается до тех пор, пока метод не будет найден или не останется родительских классов, что приведет к
NoSuchMethodError
.Если и суперкласс, и подкласс имеют записи в своих таблицах для одной и той же сигнатуры метода, сначала встречается версия подкласса, а версия суперкласса никогда не используется - это «переопределение».
Теперь предположим, что мы пропускаем экземпляр объекта и просто начинаем с подкласса. Разрешение может продолжаться, как указано выше, давая вам своего рода «переопределенный» статический метод. Однако все это может произойти во время компиляции, поскольку компилятор запускается из известного класса, а не ждет времени выполнения, чтобы запросить объект неопределенного типа для своего класса. Нет смысла «переопределять» статический метод, поскольку всегда можно указать класс, который содержит желаемую версию.
Конструктор "Интерфейс"
Вот немного больше материала, чтобы обратиться к недавнему редактированию вопроса.
Похоже, вы хотите эффективно назначить метод, похожий на конструктор, для каждой реализации
IXMLizable
. Забудьте о попытке применить это с помощью интерфейса на минуту и представьте, что у вас есть некоторые классы, отвечающие этому требованию. Как бы вы использовали это?Поскольку вы должны явно указывать конкретный тип
Foo
при «создании» нового объекта, компилятор может убедиться, что он действительно имеет необходимый фабричный метод. А если нет, ну и что? Если я могу реализовать ,IXMLizable
что не хватает «конструктора», и я создаю экземпляр и передать его в код, он являетсяIXMLizable
всем необходимым интерфейсом.Конструкция - это часть реализации, а не интерфейс. Любой код, который успешно работает с интерфейсом, не заботится о конструкторе. Любой код, который заботится о конструкторе, в любом случае должен знать конкретный тип, и интерфейс можно игнорировать.
источник
RESET()
на данный класс? Ты бы написалSomeClass.RESET()
. Таким образом, вам не нужен интерфейс для описания этого API; это статично. Интерфейсы используются, когда вы не знаете конкретный тип во время компиляции. Это никогда не происходит со статическим методом.T
не знаяT
статически, потому что я обещаю в интерфейсе, что определенный конструктор (или статический метод) будет существовать во время выполнения. Тот факт, что поколение невозможно определить в Java, не означает, что это не имеет смысла делать.Об этом уже спрашивали и отвечали, вот
Чтобы дублировать мой ответ:
Нет смысла объявлять статический метод в интерфейсе. Они не могут быть выполнены обычным вызовом MyInterface.staticMethod (). Если вы вызываете их, указывая класс реализации MyImplementor.staticMethod (), то вы должны знать фактический класс, поэтому не имеет значения, содержит ли его интерфейс или нет.
Что еще более важно, статические методы никогда не переопределяются, и если вы попытаетесь это сделать:
правила для static говорят о том, что метод, определенный в объявленном типе var, должен быть выполнен. Поскольку это интерфейс, это невозможно.
Причина, по которой вы не можете выполнить «result = MyInterface.staticMethod ()», заключается в том, что ему придется выполнить версию метода, определенного в MyInterface. Но не может быть версии, определенной в MyInterface, потому что это интерфейс. У него нет кода по определению.
Хотя вы можете сказать, что это «потому что Java делает это таким образом», на самом деле решение является логическим следствием других проектных решений, также принятых по очень веской причине.
источник
static
любом случае, я считаю, что это терминология в языках, и она слишком растянута, как есть. Так что само по себе это уже отрывочно. Смотрите мой пример выше stackoverflow.com/questions/512877/… {shrug}.Обычно это делается с использованием шаблона Factory
источник
С появлением Java 8 теперь возможно писать стандартные и статические методы в интерфейсе. docs.oracle/staticMethod
Например:
Результат : 6
СОВЕТ: Вызов метода статического интерфейса не требует реализации каким-либо классом. Конечно, это происходит потому, что те же правила для статических методов в суперклассах применяются к статическим методам на интерфейсах.
источник
Потому что статические методы не могут быть переопределены в подклассах, и, следовательно, они не могут быть абстрактными. И все методы в интерфейсе де-факто являются абстрактными.
источник
На самом деле вы можете в Java 8.
Согласно документу Java :
В Java 8 интерфейс может иметь методы по умолчанию и статические методы . Это облегчает нам организацию вспомогательных методов в наших библиотеках. Мы можем хранить статические методы, специфичные для интерфейса, в одном интерфейсе, а не в отдельном классе.
Пример метода по умолчанию:
вместо
Пример статического метода (из самого документа ):
источник
Интерфейсы связаны с полиморфизмом, который по своей сути связан с экземплярами объектов, а не с классами. Поэтому static не имеет смысла в контексте интерфейса.
источник
Во-первых, все языковые решения - это решения, принимаемые создателями языка. В мире разработки программного обеспечения или определения языка или написания компилятора / интерпретатора нет ничего, что говорило бы о том, что статический метод не может быть частью интерфейса. Я создал пару языков и написал для них компиляторы - все это просто село и определяло смысловую семантику. Я бы сказал, что семантика статического метода в интерфейсе удивительно ясна - даже если компилятор должен отложить разрешение метода до времени выполнения.
Во-вторых, то, что мы используем статические методы, означает, что есть веская причина иметь шаблон интерфейса, который включает статические методы - я не могу говорить ни за кого из вас, но я использую статические методы на регулярной основе.
Наиболее вероятный правильный ответ заключается в том, что в то время, когда был определен язык, не было ощущения необходимости в статических методах в интерфейсах. За прошедшие годы Java значительно выросла, и этот вопрос, по-видимому, вызвал некоторый интерес. То, что он рассматривался для Java 7, указывает на то, что он поднялся до уровня интереса, который может привести к изменению языка. Я, например, буду счастлив, когда мне больше не придется создавать экземпляр объекта просто для того, чтобы я мог вызвать свой нестатический метод получения, чтобы получить доступ к статической переменной в экземпляре подкласса ...
источник
Статические методы не являются виртуальными, как методы экземпляров, поэтому я предполагаю, что разработчики Java решили, что они не хотят их использовать в интерфейсах.
Но вы можете поместить классы, содержащие статические методы, в интерфейсы. Вы можете попробовать это!
источник
Позвольте мне перефразировать этот вопрос для вас, заполнив определения.
Или, если говорить более полно, если я хочу вызвать метод без экземпляра, но зная класс, как я могу разрешить его на основе экземпляра, которого у меня нет.
источник
В нескольких ответах обсуждались проблемы с концепцией переопределяемых статических методов. Однако иногда вы сталкиваетесь с тем, что кажется, что это именно то, что вы хотите использовать.
Например, я работаю с объектно-реляционным слоем, который имеет объекты-значения, но также имеет команды для управления объектами-значениями. По разным причинам каждый класс объекта значения должен определять некоторые статические методы, которые позволяют каркасу находить экземпляр команды. Например, чтобы создать персона, вы должны сделать:
и загрузить человека по идентификатору вы бы сделали
Это довольно удобно, однако у него есть свои проблемы; Примечательно, что существование статических методов не может быть реализовано в интерфейсе. Перезаписываемый статический метод в интерфейсе был бы именно тем, что нам нужно, если бы только он мог как-то работать.
EJB решают эту проблему, имея домашний интерфейс; каждый объект знает, как найти свой Дом, а Дом содержит «статические» методы. Таким образом, «статические» методы могут быть переопределены по мере необходимости, и вы не загромождаете нормальный (он называется «удаленный») интерфейс методами, которые не применяются к экземпляру вашего компонента. Просто установите в обычном интерфейсе метод getHome (). Возврат экземпляра объекта Home (который может быть одноэлементным, я полагаю), и вызывающая сторона может выполнять операции, которые влияют на все объекты Person.
источник
Комментирование
EDIT: As of Java 8, static methods are now allowed in interfaces.
Это верно, статические методы, так как Java 8 допускается в интерфейсах, но ваш пример все равно не будет работать. Вы не можете просто определить статический метод: вам нужно его реализовать, иначе вы получите ошибку компиляции.
источник
Что ж, без обобщений статические интерфейсы бесполезны, поскольку все вызовы статических методов разрешаются во время компиляции. Таким образом, нет никакой реальной пользы для них.
С дженериками они имеют применение - с реализацией по умолчанию или без нее. Очевидно, что нужно будет переопределить и так далее. Тем не менее, я предполагаю, что такое использование не было очень уместным (как и другие ответы указывают тупо) и, следовательно, не считалось стоящим усилий, которые они потребовали бы для полезной реализации.
источник
Все методы в интерфейсе явно абстрактны, и поэтому вы не можете определить их как статические, потому что статические методы не могут быть абстрактными.
источник
Интерфейс никогда не может быть разыменован статически, например
ISomething.member
. Интерфейс всегда разыменовывается через переменную, которая ссылается на экземпляр подкласса интерфейса. Таким образом, ссылка на интерфейс никогда не может знать, на какой подкласс он ссылается, без экземпляра своего подкласса.Таким образом, самым близким приближением к статическому методу в интерфейсе будет нестатический метод, который игнорирует «this», то есть не обращается к каким-либо нестатическим элементам экземпляра. На низкоуровневой абстракции каждый нестатический метод (после поиска в любой vtable) на самом деле является просто функцией с областью действия класса, которая принимает «this» в качестве неявного формального параметра. Смотрите одноэлементный объект Scala и совместимость с Java качестве доказательства этой концепции. И, таким образом, каждый статический метод является функцией с областью действия класса, которая не принимает параметр «this». Таким образом, обычно статический метод может вызываться статически, но, как было сказано ранее, интерфейс не имеет реализации (является абстрактным).
Таким образом, чтобы получить наиболее близкое приближение к статическому методу в интерфейсе, используйте нестатический метод, затем не обращайтесь ни к одному из нестатических элементов экземпляра. Не было бы никакого возможного выигрыша в производительности любым другим способом, потому что нет никакого способа статически связать (во время компиляции) a
ISomething.member()
. Единственное преимущество, которое я вижу от статического метода в интерфейсе, состоит в том, что он не будет вводить (то есть игнорировать) неявное «это» и, таким образом, запрещать доступ к любому из нестатических элементов экземпляра. Это неявно заявило бы, что функция, которая не имеет доступа к «this», является иммутированной и даже не только для чтения по отношению к содержащему ее классу. Но объявление «статического» в интерфейсеISomething
также может запутать людей, которые пытались получить к нему доступISomething.member()
что приведет к ошибке компилятора. Я полагаю, если бы ошибка компилятора была достаточно объяснительной, это было бы лучше, чем пытаться научить людей использовать нестатический метод для достижения того, чего они хотят (по-видимому, в основном фабричные методы), как мы делаем здесь (и повторялось для 3 Вопросы и ответы на этом сайте), так что это, очевидно, проблема, которая не является интуитивно понятной для многих людей. Я должен был подумать об этом некоторое время, чтобы получить правильное понимание.Чтобы получить изменяемое статическое поле в интерфейсе, используйте нестатические методы получения и установки в интерфейсе, чтобы получить доступ к тому статическому полю в подклассе. Sidenote, по-видимому, неизменяемая статика может быть объявлена в интерфейсе Java с
static final
.источник
Интерфейсы просто предоставляют список того, что будет предоставлять класс, а не фактическую реализацию этих вещей, каковым является ваш статический элемент.
Если вам нужна статика, используйте абстрактный класс и наследуйте его, в противном случае удалите статический.
Надеюсь, это поможет!
источник
Вы не можете определить статические методы в интерфейсе, потому что статические методы принадлежат классу, а не экземпляру класса, и интерфейсы не являются классами. Узнайте больше здесь.
Однако, если вы хотите, вы можете сделать это:
В этом случае у вас есть два класса с двумя различными статическими методами, которые называются methodX ().
источник
Предположим, вы могли бы сделать это; рассмотрим этот пример:
источник
A.thisIsTheMethod()
он напечатает «Я класс B».B.thisIsTheMethod()
он напечатает "Я класс B".Нечто, что можно реализовать, - это статический интерфейс (вместо статического метода в интерфейсе). Все классы, реализующие данный статический интерфейс, должны реализовывать соответствующие статические методы. Вы можете получить статический интерфейс SI из любого класса, используя
тогда вы можете позвонить
si.method(params)
. Это было бы полезно (например, для шаблона проектирования фабрики), потому что вы можете получить (или проверить реализацию) реализацию статических методов SI из неизвестного класса времени компиляции! Динамическая диспетчеризация необходима, и вы можете переопределить статические методы (если не финальные) класса, расширив его (при вызове через статический интерфейс). Очевидно, что эти методы могут обращаться только к статическим переменным своего класса.источник
Хотя я понимаю, что Java 8 решает эту проблему, я решил присоединиться к сценарию, над которым я сейчас работаю (заблокирован с помощью Java 7), в котором было бы полезно указать статические методы в интерфейсе.
У меня есть несколько определений перечисления, в которых я определил поля «id» и «displayName», а также вспомогательные методы, оценивающие значения по разным причинам. Реализация интерфейса позволяет мне гарантировать, что методы getter находятся на месте, но не статические вспомогательные методы. Будучи перечислением, на самом деле нет чистого способа разгрузить вспомогательные методы в унаследованный абстрактный класс или что-то подобное, поэтому методы должны быть определены в самом перечислении. Кроме того, поскольку это enum, вы никогда не сможете фактически передать его как экземплярный объект и трактовать его как тип интерфейса, но мне нравится возможность наличия статических вспомогательных методов через интерфейс. это поддерживается в Java 8.
Вот код, иллюстрирующий мою точку зрения.
Определение интерфейса:
Пример одного определения перечисления:
Общее определение утилиты enum:
источник
Давайте предположим, что статические методы были разрешены в интерфейсах: * Они заставили бы все реализующие классы объявить этот метод. * Интерфейсы обычно используются через объекты, поэтому единственными эффективными методами для них будут нестатические. * Любой класс, который знает конкретный интерфейс, может вызывать его статические методы. Следовательно, статический метод реализующего класса будет вызван снизу, но класс invoker не знает, какой именно. Как это узнать? У него нет экземпляров, чтобы догадаться об этом!
Считалось, что интерфейсы используются при работе с объектами. Таким образом, объект создается из определенного класса, поэтому этот последний вопрос решен. Вызывающий класс не должен знать, какой именно это класс, потому что создание экземпляра может быть выполнено третьим классом. Таким образом, вызывающий класс знает только интерфейс.
Если мы хотим, чтобы это было распространено на статические методы, у нас должна быть возможность предварительно определить реализующий класс, а затем передать ссылку на вызывающий класс. Это может использовать класс через статические методы в интерфейсе. Но в чем разница между этой ссылкой и объектом? Нам просто нужен объект, представляющий, что это был за класс. Теперь объект представляет старый класс и может реализовывать новый интерфейс, включая старые статические методы - теперь они нестатические.
Метаклассы служат для этой цели. Вы можете попробовать класс Class of Java. Но проблема в том, что Java недостаточно гибка для этого. Вы не можете объявить метод в объекте класса интерфейса.
Это мета проблема - когда нужно делать задницу
.. бла бла
в любом случае, у вас есть простой способ - сделать метод нестатичным с той же логикой. Но тогда вам придется сначала создать объект для вызова метода.
источник
Чтобы решить эту проблему: ошибка: отсутствует тело метода или объявлена абстрактная статическая пустота main (String [] args);
выход: 20
Теперь мы можем использовать статический метод в интерфейсе
источник
Я думаю, что у Java нет статических методов интерфейса, потому что они вам не нужны. Вы можете думать, что делаете, но ... Как бы вы их использовали? Если вы хотите назвать их как
тогда вам не нужно объявлять это в интерфейсе. Если вы хотите назвать их как
тогда оно не должно быть статичным. Если вы на самом деле собираетесь использовать первый способ, но просто хотите, чтобы каждая реализация имела такой статический метод, тогда это действительно соглашение о кодировании, а не контракт между экземпляром, который реализует интерфейс и вызывающий код.
Интерфейсы позволяют вам определять контракт между экземпляром класса, который реализует интерфейс, и вызывающим кодом. И java помогает вам быть уверенным, что этот контракт не нарушен, поэтому вы можете положиться на него и не беспокоиться о том, какой класс реализует этот контракт, достаточно просто «того, кто подписал контракт». В случае статических интерфейсов ваш код
не полагается на тот факт, что каждая реализация интерфейса имеет этот метод, поэтому вам не нужна Java, чтобы быть уверенным в этом.
источник
Для чего нужен статический метод в интерфейсе, статические методы используются в основном, когда вам не нужно создавать экземпляр объекта, и вся идея интерфейса состоит в том, чтобы ввести концепции ООП с введением статического метода, который вы отклоняете от концепции.
источник