我有这门课,仅仅是为了学习:
public class MyClass{ //Looking for a solution without making my class also generic <Type>
//Private Arraylist var to hold the value called myvar
public MyClass(ArrayList<MyDesiredType> incoming) {
//CODE myVar=incoming
}
public MyDesiredType getType() {
return myVar.get(0);
}
}
有没有办法在传入对象中从构造函数推断到方法的返回类型而没有警告和转换,并且失去了类型安全性,但最重要的是没有使整个类GENERIC(对我来说似乎多余)?如果没有,为什么我认为这对编译器不可行?
这是我已经做过的一个重新提出的问题,但这是我的第一个问题,我学会了如何将其公开,因为没有人理解。我试图稍后编辑原始问题,但一切都被埋没了。我改变并简化了示例,并尝试放轻松。原始问题:Java Generics Silly Thing (Why cant I infer the type?)。
如果有任何问题,请告诉我,我会将其删除。
答案 0 :(得分:8)
不,没有。编译器如何知道要返回的类型?在编译期间,将不知道构造函数中的泛型类型的ArrayList。你要么必须使整个类成为通用的,要么采取另一种方法。
考虑一下:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(arrList);
String testStr = test.returnWhat();
System.out.println("testStr");
}
private final List myList; //warning
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat() {
return (T) myList.get(0); //warning
}
}
这有效,但会在标记的行上给出警告。所以,实际上没有办法实现你所描述的内容而不会使整个类变得通用。 因为,如果:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(); // now what?
String testStr = test.returnWhat(0); // no warning...
JPanel p = test.returnWhat(0); // goes through without warning, real nice...
test.returnWhat(0); // returns Object
Test test2 = new Test(arrList);
test2.addElement(new Object()); // boom, inserted object into list of string.
String nono = test2.returnWhat(1); // the universe goes down. assign an object to string without warning. even
// though one COULD think the class is generic.
}
// private List<T> myList = new ArrayList<T>(); compiler error, T is unknown
private List myList = new ArrayList();
public Test() {
myList.add(new Object());
}
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat(int index) {
return (T) myList.get(index);
}
public <T> void addElement(T el) {
myList.add(el);
}
}
当myList变为通用时,第二个不编译。编译器如何确定&lt; T&gt;的类型。在使用默认构造函数的情况下?
此外,这可能会导致集合中的对象出现严重问题,这些问题依赖于仅插入某些类型的事实。
这将产生以下异常:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Object cannot be cast to java.lang.String at
Test.main(Test.java:27)
我能说服你吗?
真正的好问题,顺便说一下。我不得不考虑这个问题。
答案 1 :(得分:2)
当你说你希望编译器“从构造函数推断传入对象到方法的返回类型而没有警告和转换并且失去类型安全性”时,你似乎在说它应该推断它的结果来自构造函数输入的getType()
。如果两者都发生在同一个函数中,它可以。问题是对象可能不存在于一个函数中,因此需要额外的类型信息(泛型类型)来在函数之间传递这种对象。
例如,如果我想编写一个带有MyClass
对象的函数,我需要知道getType()
将返回什么,所以我可以使用返回的值。通过添加通用类型MyClass
,我们将对其所包含的内容进行描述。
另一种看待它的方法是MyClass
是一个容器。通过添加泛型,我们说它是特定类型事物的容器,因此我们可以更容易地预测我们将从中获得什么。
答案 2 :(得分:1)
编译器无法在运行时知道您的arraylist是什么类型。我真的没有看到问题使用的东西:
public class MyClass<TYPE> {
private ArrayList<TYPE> incoming;
public MyClass(ArrayList<TYPE> incoming) {
this.incoming = incoming;
}
public TYPE getType() {
return incoming.get(0);
}
}
这样你就可以:
ArrayList<Integer> numbers = createListOfNumbers();
MyClass<Integer> myClass = new MyClass<>(numbers);
Integer number = myClass.getType();
或者我是否误解了这个问题而你想在运行时知道这个类?
答案 3 :(得分:0)
不,如果您想要一个可以保存参数化类型列表的类。
是,如果您想要一个可以容纳一种类型列表的类。您可以在字段,构造函数和访问器中明确声明该类型。
答案 4 :(得分:0)
您忘记的是,并非编译器都可以看到您可能遇到的所有代码!可以在运行时添加,删除,替换Jars,编译器从未见过。您可以针对仅仅的接口进行编译:
public interface MyClassFactory {
MyClass getInstance();
}
然后在运行时,您将向JVM提供一个实现。因此,编译器从未看到创建将要使用的MyClass的实际代码,因此无法执行这样的编译时推断。您必须使该类具有通用性或接受不存在类型安全性。