У меня есть следующие классы: Foo1 расширяет Bar и Foo2 расширяет панель
Я хотел бы передать тип Foo1 или Foo2 в моем методе, чтобы создать либо Foo1, либо Foo2, например:
public Bar createMethod( "either type of Foo1, or Foo2" fooType) {
//returns the foo1 or foo2
}
Есть ли какой-нибудь подход для достижения этого?
Вы можете объявить
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();
}
Это звучит как проблема XY. Чего вы на самом деле пытаетесь достичь?