Question

I have this class, just for the purpose of learning:

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

Is there any way to infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness, but most of all WITHOUT making the whole class GENERIC (seems redundant to me)? If not, why should I think this is not feasible for the compiler?

This is a reformulated question I already did, but it was my first one and I learned how to expose it clear because nobody understood. I tried to edit later the original question but everything was buried. I changed and simplified the example and try to put it easy. Original question: Java Generics Silly Thing (Why cant I infer the type?).

If there is any problem just tell it to me and I will remove it.

Was it helpful?

Solution

No, there is not. How would the compiler know what type to return? The generic type of ArrayList in the constructor will not be known during compile time. You either have to make the whole class generic or take another approach.

Consider this:

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
    }
}

This works but gives you warnings on the marked lines. So, really there is no way to achieve what you are describing without making the whole class generic. Because, what if:

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

The second one doesn't compile when myList is made generic. How could the compiler determine the type of <T> in the case where the default constructor is used?

Further, this could lead to serious problems with Objects in collections that rely on the fact that only certain types are inserted.

This will generate the following exception:

Exception in thread "main" java.lang.ClassCastException:
java.lang.Object cannot be cast to java.lang.String     at
Test.main(Test.java:27)

Did I manage to convince you?

Real nice question, btw. I had to think about this one quite a bit.

OTHER TIPS

When you say that you want the compiler to "infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness", it seems that you are saying that it should infer the result of getType() from the input of the constructor. If both happen in the same function, it could. The problem is that the object may not exist in only one function, and so the extra type information (the generic type) is needed to pass this kind of object between functions.

For example, if I want to write a function that takes a MyClass object, I need to know what getType() will return so I can use the returned value. By adding a generic type of MyClass we are giving a description to what it holds.

Another way to look at it is that MyClass is a container. By adding generics, we are saying it is a container of a specific type of thing, and so we can more easily predict what we will get out of it.

There is no way for the compiler to know at runtime what type your arraylist is. I really dont see the problem using something along the lines of this:

 public class MyClass<TYPE> {
     private ArrayList<TYPE> incoming;

     public MyClass(ArrayList<TYPE> incoming) {
         this.incoming = incoming;
     }

     public TYPE getType() {
         return incoming.get(0);
     }
 }

This way you can do:

ArrayList<Integer> numbers = createListOfNumbers();
MyClass<Integer> myClass = new MyClass<>(numbers);
Integer number = myClass.getType();

Or am i misinterpreting the question and you want to know the class at runtime?

No, if you want a class that can hold a list of a parameterized type.

Yes, if you want a class that can hold a list of exactly one type. You can declare that type explicitly in the field, constructor and accessor.

What you're forgetting is that not all code that you may run against is visible to the compiler! Jars can be added, removed, substituted at run time, that the compiler never saw. You may compile against an interface that is just:

public interface MyClassFactory {
  MyClass getInstance();
}

Then at runtime you supply into the JVM an implementation. So the compiler never saw the actual code creating the MyClass that you will be using, so there is no way to perform such a compile time inference. You must either make the class generic or accept that there will not be type safety.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top