Help me understand these general method warnings

Folks, I have a base class, say:

public class BaseType { private String id; ... }

and then three subclasses:

public class TypeA extends BaseType { ... }
public class TypeB extends BaseType { ... }
public class TypeC extends BaseType { ... }

I have a container class that supports lists of objects of these types:

public class Container
{
    private List<TypeA> aList;
    private List<TypeB> bList;
    private List<TypeC> cList;

    // finder method goes here
}

And now I want to add the finder method to a container that will find an object from one of the lists. The search method is written as follows:

public <T extends BaseType> T find( String id, Class<T> clazz )
{
    final List<T> collection;
    if( clazz == TypeA.class )
    {
        collection = (List<T>)aList;
    }
    else if( clazz == TypeB.class )
    {
        collection = (List<T>)bList;
    }
    else if( clazz == TypeC.class )
    {
        collection = (List<T>)cList;
    }
    else return null;

    for( final BaseType value : collection )
    {
        if( value.getId().equals( id ) )
        {
            return (T)value;
        }
    }

    return null;

}

My question is this: if I don’t add all the casts to T in my finder above, I get compilation errors. I think that compilation should be able to infer types based on the parameterization of a common method (). Can anyone explain this?

Thank.

-Raj

+3
source share
5 answers

, . , :

collection = (List<T>)aList;

, T, TypeC. , List<TypeA> List<TypeC>, - , - , .

+3

, , .

, ,

if( clazz == TypeA.class )   

Class<T> clazz

, if T TypeA.

, , , , Java , .

, check

if (a instanceof Something){
    ((Something)a).someMethod();
}

, , ( , ) , , .

+3
private List<TypeA> aList;
private List<TypeB> bList;

public <T extends BaseType> T find(String id, Class<T> clazz) {
    final List<? extends BaseType> collection;
    if (clazz == TypeA.class) {
        collection = aList;
    } else if (clazz == TypeB.class) {
        collection = bList;
    }

    for (final BaseType value : collection) {
        if (value.getId().equals(id)) {
            return clazz.cast(value);
        }
    }
}
+2

, ( T) :

for (final T value : collection) {
  if (value.getId().equals(id)) {
    return value;
  }
}

, , T, , TypeA TypeB. :

TypeA find("id", TypeA.class);

BaseType, . , , TypeA BaseType, BaseType TypeA.

java- , BaseType . , T . , BaseType T , , javac.

. List<T> collection - , , - , List<TypeA> . , ( ).

0

I suggest reflecting reflection artifacts and using a standard strategy. Unfortunately, they cannot have generic enumerations (although they can implement generic types that provide actual generic arguments).

private List<TypeA> aList;
private List<TypeB> bList;
private List<TypeC> cList;

public abstract class ListType<T extends BaseType> {
    /*private*/ abstract T get(Container container); // private isn't virtual.
    // Add extras to taste.
}
public static final ListType<TypeA> LIST_A = bew ListType<TypeA>() {
    /*private*/ ListType<TypeA> get(Container container) { return container.aList; }
};
public static final ListType<TypeB> LIST_B = bew ListType<TypeB>() {
    /*private*/ ListType<TypeB> get(Container container) { return container.bList; }
};
public static final ListType<TypeC> LIST_C = bew ListType<TypeC>() {
    /*private*/ ListType<TypeC> get(Container container) { return container.cList; }
};


public <T extends BaseType> T find(String id, ListType<T> type) {
    final List<T> collection = type.get(this);

    for (final T value : collection) {
        if (value.getId().equals(id)) {
            return value;
        }
    }

    return null;

}
0
source

Source: https://habr.com/ru/post/1781769/


All Articles