Java Generics → Тип возврата функции
У меня такая ситуация:
У меня есть класс, который выглядит так:
public class TestClass<T> {
// class body here...
}
И у меня есть метод, который выглядит так:
public class AnotherTestClass<K> {
private TestClass<K> testClass;
public AnotherTestClass(TestClass<K> testClass) {
this.testClass = testClass;
}
public K testMethod() {
//call methods on param object and pass a value of the same type as testClass.
K returnVal = this.testClass.doSomething();
return returnVal;
}
}
Теперь у меня есть метод factory, который возвращает объект типа TestClass<?>
public TestClass<?> sampleFactory(int i) {
if( i==1 )
return new TestClass<Integer>();
if( i==2 )
return new TestClass<Double>();
if( i==3 )
return new TestClass<String>();
}
Но я не могу использовать этот метод для передачи параметра my testMethod
. Какое решение для этого?
В настоящее время я пишу if else
цепные блоки, чтобы получить правильный экземпляр. Я знаю, что это неверно, поскольку нецелесообразно писать блоки if else
, когда есть несколько параметров, таких как выше.
Пожалуйста, предложите элегантный способ для этого.
ИЗМЕНИТЬ: Использование примера:
package my;
import java.util.ArrayList;
import java.util.List;
public class GenericsSpike {
public static void main( String[] args ) {
TestClass1< ? > tc1 = new TestClass1<Integer>( 123 );
TestClass2< ? > tc2 = new TestClass2<Integer>( 123 );
AnotherTestClass< ? > atc = new AnotherTestClass<Integer>( tc1, tc2 );
atc.testMethod();
}
}
class TestClass1<T> {
private T value;
TestClass1( T val ) {
value = val;
}
// class body here...
public T getValue() {
return value;
}
}
class TestClass2<T> {
private T value;
TestClass2( T val ) {
value = val;
}
// class body here...
public T getValue() {
return value;
}
}
class AnotherTestClass<K> {
public TestClass1<K> testClass1, testClass2;
public AnotherTestClass( TestClass1<K> testClass, TestClass2<K> testClass2 ) {
this.testClass1 = testClass;
}
public K testMethod() {
//Any logic can come here.
System.out.println( testClass1.getValue() );
System.out.println( testClass2.getValue() );
return testClass1.getValue();
}
}
В этом случае, если tc1
и tc2
поступают из factory, который создает эти объекты, я хочу знать, какой достойный способ создать экземпляр AnotherClass
Ответы
Ответ 1
Ваша проблема заключается в этом методе:
public TestClass<?> sampleFactory(int i) {
Подстановочный знак ?
означает "какой-то тип, но я не знаю, что". Таким образом, вы можете получить значение типа TestClass<?>
, но оно вам не полезно, потому что вы не можете осмысленно взаимодействовать с типом ?
- вы не можете создавать значения типа ?
(за исключением null) и вы не можете вызывать методы типа ?
(кроме методов java.lang.Object
).
То, что вы действительно хотите, это что-то вроде:
public <T> TestClass<T> sampleFactory(TypeToken<T> typeToken) {
То есть, если вы хотите, чтобы ваш factory возвращал значения, параметризованные разными типами, вам нужно дать ему то, что сообщает ему, какой тип вы хотите. К сожалению, int
недостаточно - может знать, что i==1
означает, что тип будет Integer
, но компилятор этого не знает.
Ваше описание вашей проблемы слишком расплывчато для меня, чтобы понять, чего вы действительно пытаетесь достичь, но я предполагаю, что вам действительно нужно что-то вроде super тип токенов или, может быть, что-то вроде Guava ClassToInstanceMap
.
Ответ 2
Одним из возможных решений является использование типа raw AnotherTestClass
public class A {
public static void main(String[] args) {
TestClass<?> tc = new TestClass<Integer>();
AnotherTestClass atc = new AnotherTestClass();
atc.testMethod(tc);
}
}
class TestClass<T> {
// class body here...
}
class AnotherTestClass<K> {
public void testMethod(TestClass<K> param) {
}
}
компилируется отлично. Но не рекомендуется использовать исходные типы в общем случае
Ответ 3
Java Doc говорит:
Тип конструктора, метод экземпляра или нестатического поля M необработанного типа C, который неунаследованный от своих суперклассов или суперинтерфейсов, является стиранием его типа в родовом объявление, соответствующее C. Тип статического члена исходного типа C совпадает с типом его введите в общее объявление, соответствующее C.
Стирание типа входит в изображение, даже если подпись типа метода не использует никаких параметров типа самого класса,
Это ваш метод,
public method testMethod(TestClass param) {
}
Ваш метод factory, который возвращает объект типа TestClass<?>
, не может быть размещен в указанном выше методе.
Ответ 4
Используя этот, вы сможете передать параметр в testMethod
:
package stackoverflow;
public class Func {
static class TestClass<T> {
}
static class AnotherTestClass {
public <K> TestClass<K> testMethod(TestClass<K> param) {
return param;
}
}
static class Factory {
public static <E> TestClass<E> sampleFactory(int i) {
if (i == 1)
return (TestClass<E>) new TestClass<Integer>();
if (i == 2)
return (TestClass<E>) new TestClass<Double>();
if (i == 3)
return (TestClass<E>) new TestClass<String>();
throw new IllegalArgumentException();
}
}
public static void main(String[] args) {
new AnotherTestClass().testMethod(Factory.sampleFactory(1));
}
}