Как использовать тип класса параметра метода?

У меня есть следующие классы: Foo1 расширяет Bar и Foo2 расширяет панель

Я хотел бы передать тип Foo1 или Foo2 в моем методе, чтобы создать либо Foo1, либо Foo2, например:

public Bar createMethod( "either type of Foo1, or Foo2" fooType) {
    
    //returns the foo1 or foo2
}

Есть ли какой-нибудь подход для достижения этого?

Это звучит как проблема XY. Чего вы на самом деле пытаетесь достичь?

Turing85 20.12.2020 20:41
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
72
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете объявить

public Bar createMethod(Class<? extends Bar> fooType) {
    //returns the foo1 or foo2
}

а затем позвоните, как в

Bar bar = createMethod(Foo1.class);
Ответ принят как подходящий

Вы можете иметь некоторую гибкость, используя дженерики, объявив:

public <T extends Bar> T createMethod(Class<T> foo) {
    // do the factoring
    retrun (T) foo1 // (or foo2 depending on the foo passed);
} 

При этом действительны все следующие назначения:

Bar b1 = createMethod(Foo1.class);
Bar b2 = createMethod(Foo2.class);
Foo1 f1 = createMethod(Foo1.class);
Foo2 f2 = createMethod(Foo2.class);

Примечание: во время выполнения вы получите ClassCastException, если не вернете ожидаемый тип. Итак, если вы, например, сделаете это:

public <T extends Bar> T createMethod(Class<T> foo) {
    return (T)new Foo2();
}

и

Foo1 foo1 = createMethod(Foo1.class);

Вот код:

        public static void main(String args[]){

        Bar barB = createMethod(FooB.class);
        Bar barA = createMethod(FooA.class);

        System.out.println("barB is instance of B " + (barB instanceof FooB) );
        System.out.println("barA is instance of A " + (barA instanceof FooA) );

    }



    public static Bar createMethod(Class foo) {
        if (foo.equals(FooA.class)) {
            FooA fooA = new FooA();
            return (Bar) fooA;
        }
        else{
            FooB fooB = new FooB();
            return (Bar) fooB;
        }
    }

}

    class Bar{}
    
    class FooA extends Bar{}
    
    class FooB extends Bar{}

А ваши FooA и FooB расширяют Bar.

В Java нет типов объединения, поэтому тип, подобный A | B, в Java невозможен.

В Java 15 запечатанные типы были добавлены через JEP 360, поэтому вы можете создать иерархию запечатанных типов только с двумя типами, которые нельзя расширить, эффективно имитируя типы объединения для ваших собственных типов.

Передав экземпляр Class, вы можете использовать отражение для создания экземпляра типа.

public sealed interface FooBar permits Foo, Bar { }
public final class Bar implements FooBar { }
public final class Foo implements FooBar { }

public FooBar createMethod(Class<? extends FooBar> type) {
   return type.newInstance();
}

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

Другая возможность — использовать строки и использовать Class.forName(String) для получения типа, связанного с полным классом:

public FooBar createMethod(String type) {
   if (type.equals("your.type.Foo") || type.equals("your.type.Bar"))
        return Class.forName(type).newInstance();
}

Другие вопросы по теме