У нас будет следующая иерархия классов:
public class ParentClass implements SomeInterface {
}
public class ChildClass extends ParentClass {
}
Тогда давайте возьмем эти два экземпляра:
ParentClass parent;
ChildClass child;
Тогда у нас есть следующие ИСТИННЫЕ утверждения
(parent instanceof SomeInterface) == true
(child instanceof SomeInterface) == true
Можно ли не реализовать SomeInterface в ChildClass, чтобы при проверке с помощью оператора instanceof он возвращал false?
Если это невозможно, есть ли обходной путь?




Это невозможно, и это нарушит подразумеваемые отношения IS-A между ChildClass и ParentClass. почему ты хочешь сделать это?
Возможно, у вас есть конкретный случай, когда можно было бы придумать лучшее решение, но для общего случая вам понадобится черная магия. В конце концов, Javassist можно было бы использовать для «взлома» ваших объектов, но я в этом не уверен.
Я не думаю, что вы можете «не реализовать» его, но вы можете проверить, является ли он экземпляром родительского класса. Интерфейс твой? Если это так, вы можете расширить его, включив метод «IsObjectDerived» с семантикой, которая возвращает истину, если класс только является производным от объекта. Поскольку вы пишете класс, все, что вам нужно сделать, это реализовать его в родительском элементе и вернуть true, если объект имеет класс Parent, и false в противном случае.
Вы также можете сделать это с помощью отражения, проверив суперкласс текущего класса и убедившись, что это объект. Я бы, наверное, так и поступил, поскольку тогда реализация классов не может лгать. Вы можете посмотреть руководство при отражении в Java, которое я нашел.
[РЕДАКТИРОВАТЬ] В целом я согласен с тем, что это кажется ненужным при разумном дизайне, но это можно сделать.
Я думаю, вы должны воспринимать эту проблему как четкое указание на то, что ваш интерфейс и дизайн классов ошибочны. Даже если бы вы могли сделать это на Java (а я не думаю, что это возможно), вам не следует этого делать.
Как насчет повторного факторинга ParentClass, чтобы у вас была реализация SomeInterface отдельно от той, которая вам нужна в ChildClass. Возможно, вам нужен общий базовый класс для ParentClass и ChildClass.
Нет, это невозможно, и ваше намерение сделать это является хорошим намеком на то, что в вашей иерархии классов есть изъян.
Обходной путь: измените иерархию классов, например. нравится:
interface SomeInterface {}
abstract class AbstractParentClass {}
class ParentClass extends AbstractParentClass implements SomeInterface {}
class ChildClass extends AbstractParentClass {}
Возможно, вам нужна композиция вместо наследования, т.е. иметь объект «базового класса» в качестве члена и просто реализовать нужные вам интерфейсы, перенаправляя любые методы, необходимые члену.
Я не понимаю, насколько это будет разумной практикой, но вы мог изменяете класс динамически, используя отличный пакет Javassist, созданный Шигеру Чиба и др. Используя это, вы можете добавлять и удалять компоненты из классов, а затем использовать экземпляры этих классов без сохранения в виде файлов классов.
Динамичный, интересный и запутанный для всех. Я советую использовать его с осторожностью, но поэкспериментируйте с ним, поскольку, на мой взгляд, это сделает вас лучшим программистом.
(Я считаю, что ASM работает аналогичным образом, но я пока не пробовал его. Кажется, он очень популярен среди создателей не-java языков, работающих над JVM, так что, вероятно, это хорошо.)
Я согласен с другими ответами, что это невозможно в Java.
Другие ответы также предполагают, что это указывает на недостаток вашего дизайна.
Хотя я согласен с ними, будет справедливо отметить, что некоторые видные эксперты по объектно-ориентированному проектированию (в частности, Бертран Мейер) не согласны с нами и считают, что такой дизайн должен быть разрешен.
Другие модели объектно-ориентированного наследования (в частности, язык программирования Meyer Eiffel) действительно поддерживают функцию «Изменение доступности или типа» (CAT), которую вы ищете.
Поскольку наследование, основа полиморфизма ООП, обозначает отношения «есть-А», ваш вопрос, похоже, требует способа переопределить отношения «есть», чтобы быть «не есть».
Это не сработает.
Вернитесь к некоторым вводным объектно-ориентированным текстам или онлайн-материалам и изучите, что означает объектно-ориентированный подход: полиморфизм, инкапсуляция и идентичность.
Если вы хотите такую ситуацию, то запрограммируйте на «С». Не балуйтесь, делая вид, что пишете ООП-код с использованием языковых функций ООП. Просто используйте структуру для хранения ваших данных. Ставьте профсоюзы везде. С энтузиазмом используйте приведение типов.
Ваша программа, скорее всего, не будет работать надежно, но вы сможете обойти любые ограничения, введенные такими языками, как Java и C++, чтобы сделать программы более надежными, более легкими для чтения и более легкими для написания / изменения.
В динамическом языке программирования, таком как SmalTalk или Python, вы можете оторвать крылья у бабочки во время выполнения. Но только изменением / повреждением типа объекта.
Это ничего вам не даст. Существуют методы кодирования / проектирования и шаблоны проектирования, которые позволяют достичь любого «хорошего» результата, который может быть у вас после этого, аналогично этому.
Лучше всего, если вы подумаете о том, что именно вы пытаетесь сделать в своем приложении, а затем попытаетесь найти самый безопасный / простой способ сделать это, используя звуковые методы.