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

#java #oop

#java #ооп

Вопрос:

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

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

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

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

Комментарии:

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

Ответ №1:

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

 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);
 

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

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

и

 Foo1 foo1 = createMethod(Foo1.class);
 

Ответ №2:

Вот код:

         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 расширяют панель.

Ответ №3:

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();
}
 

Ответ №4:

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

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

а затем вызвать, как в

 Bar bar = createMethod(Foo1.class);