Способ найти, что объект Java был инициализирован как вместо объявленного типа? - PullRequest
2 голосов
/ 01 августа 2011

Я не знаю, упускаю ли я что-то здесь, но у меня возникают проблемы при приведении объекта к его фактическому инициализированному типу.По сути, если я создаю объект с «SuperClass sc = new SubClass ()», то я вызываю метод на sc, я хочу, чтобы метод мог вызывать метод (Subclass) вместо метода (Superclass).Пример, показанный ниже:

public class Example
{
    public static void act(SuperClass a) {
        System.out.println("SuperClass");
    }

    public static void act(SubClass a) {
        System.out.println("SubClass");
    }

    public static void main(String[] args) {
        SuperClass sc = new SubClass();

        // want to find a way to call act(SubClass) instead of act(SuperClass)
        act(sc);
   }
}

class SuperClass {}
class SubClass extends SuperClass {}

Я сейчас использую шаблон посетителя, но мне интересно, есть ли другие способы сделать это, возможно, через Java Reflection API?

Спасибомного заранее!

== edit ==

Я знаю, что обычно с OO лучше привязывать функциональность к самим суперклассам / подклассам, но для моих конкретных случаев использования у меня естьгруппа подклассов, которые являются неизменяемыми модельными классами, которые должны быть переданы различным видам исполнительных механизмов (представьте разные классы «Пример»).Подклассы / классы моделей должны содержать только неизменяемую информацию, и ничего более, а фактическая реальная функциональность зависит от механизма выполнения (Пример класса).Вот почему я задаюсь вопросом об альтернативах шаблону посетителя.У кого-нибудь есть способ восстановить актуальную «инициализированную» информацию в Java?Если так, большое спасибо.

И из-за характера проблемы я не могу использовать прямое приведение ... Представьте, если у меня есть массив списков SuperClass, где каждый элемент может быть SubClass1, SubClass2, SubClass3, все выходящие из SuperClass.

Теперь, когда вы извлекаете вещи из Arraylist, вы получаете объект SuperClass, даже если они действительно могут быть SubClass1, SubClass2, SubClass3 и т. Д.

Далее я хочу вызвать act (SubClass1) и иметь возможность вызывать правильный метод act () для текущего типа.Поэтому я хочу в конечном итоге вызывать акт (SubClass1), акт (SubClass2), акт (SubClass3) вместо акта (SuperClass).

== изменить снова ==

Я имеюпридумал способ сделать это через Java Reflection API, найдя фактический базовый тип подкласса, используя Class.forName (classname), а затем динамически вызывал метод с правильной сигнатурой метода.Я написал это в форме ответа где-то внизу этой страницы для тех, кто интересуется этой проблемой.Обратите внимание, что это не очень эффективный способ выполнить то, что я пытаюсь сделать здесь, и вам, вероятно, лучше использовать шаблон посетителей или операторы if-else, если вы застряли в моей ситуации.


Таким образом, ответ, который дал Никола Мусатти, наиболее близок к ответу на мой вопрос, хотя, как он также отметил, по мере увеличения числа подклассов список операторов if-else становится очень длинным.Я выберу его ответ в качестве ответа на принятие, так как в своем вопросе я четко не указал, что надеюсь избежать проверок if-else.

В любом случае, поэтому я немного поигрался с JavaReflection API сегодня и придумал следующее:

SuperClass sc = new SubClass();

// Get the actual class of sc. actualClass now is SubClass.
Class actualClass = Class.forName(sc.getClass().getCanonicalName());

// Basically invoking act(SubClass sc) instead of act(SuperClass sc)
Class parameters[] = {actualClass};
Method method = Example.class.getMethod("act", parameters);
Object arguments[] = {sc};
method.invoke(null, arguments);

Это, безусловно, не лучший способ сделать что-то, особенно из-за потери производительности, налагаемой Java Reflection API.Это может быть лучше, чем шаблон посетителя или if-else, проверяет, есть ли у вас миллион подклассов, поскольку, вероятно, меньше кода для управления, однако сейчас я буду придерживаться шаблона посетителя, поскольку у меня нет миллиона подклассов для управления.

Несмотря на это, просто подумал, что я опубликую это здесь, чтобы показать, что это может быть сделано, только для тех, кому любопытно.

Ответы [ 4 ]

6 голосов
/ 01 августа 2011

Разве вы не должны определять act() в SuperClass и SubClass? Таким образом, правильный метод будет вызываться независимо от типа ссылки на объект.

Редактировать: Если я правильно помню, шаблон посетителя определяет что-то вроде accept() метода для элементов, которые нужно посетить, что позволяет посетителю полиморфно получать доступ ко всему, что ему интересно в посещаемых элементах.

1 голос
/ 01 августа 2011

Общее решение - шаблон Visitor.Если у вас есть конкретная ситуация, когда вы знаете фактический тип sc, вы действительно можете использовать приведение, как уже было предложено, возможно, перед проверкой типа, как в

if ( sc instanceof SubClass ) act((SubClass)sc);

Однако шаблон Visitor был изобретен, потому чтоэтот подход не масштабируется, когда количество классов, которые вам нужно обработать, растет.

И последнее, но не менее важное, иногда самый простой подход - просто сохранить переменную фактического типа:

SubClass scc = new SubClass();
SuperClass sc = scc;
act(scc);
1 голос
/ 01 августа 2011

А как же

act((SubClass)sc);

??

0 голосов
/ 01 августа 2011

Возможно, вам следует сделать метод act членом класса SupperClass, а затем переопределить его в классе SubClass.

...