I have following code
private static class ParcelableParser<T> {
private ArrayList<T> parse(List<Parcelable> parcelables) {
ArrayList<T> parsedData = new ArrayList<T>();
for(Parcelable parcelable : parcelables) {
parsedData.add((T) parcelable);
}
return parsedData;
}
}
It is called as follows
ParcelableParser<SomeClass> cellParser = new ParcelableParser<SomeClass>();
cellParser.parse(bundle.getParcelableArrayList("some String"));
It gives warning Type safety: Unchecked cast from Parcelable to T.
No matter what I do, I always have some nasty compilation error.
I have read about PECS rule, but I am not able to apply it here.
sample solution (does not compile)
private static class ParcelableParser<T extends Parcelable> {
private ArrayList<T> parse(List<T> parcelables) {
ArrayList<T> parsedData = new ArrayList<T>();
for(T parcelable : parcelables) {
parsedData.add((T) parcelable);
}
return parsedData;
}
}
Using it as
return new ParcelableParser<SomeClass>()
.parse(bundle.getParcelableArrayList("SomeString"));
prodces
The method parse(List<SomeClass>) in the type MyClass.ParcelableParser<SomeClass> is not applicable for the arguments (ArrayList<Parcelable>)
As you know parcelable is of type T why don't you use T instead. Try this:
public static class ParcelableParser<T> {
private ArrayList<T> parse(List<T> parcelables) {
ArrayList<T> parsedData = new ArrayList<T>();
for(T parcelable : parcelables) {
parsedData.add(parcelable);
}
return parsedData;
}
}
Related
I'm trying to resolve this apparently simple generic casting problem :
First, declaring this simple generic object :
public interface GenericObject<T> {}
Second, declaring this working interface :
public interface Generic { // I don't want to do Generic<T>
<T> void setGenericObject(GenericObject<T> obj);
}
Then, let's implements this interface :
public class GenericImpl implements Generic {
private GenericObject<String> genericObject; // This is needed
#Override
public <String> void setGenericObject(GenericObject<String> obj) {
genericObject = obj; // eclipse give me this error :
// Type mismatch: cannot convert from
// interfaces.GenericObject<String> to
// interfaces.GenericObject<java.lang.String>
}
}
How can I solve this error ?
Edit :
Actualy, the only way I have to solve this issue is to do this :
public class GenericImpl implements Generic {
private GenericObject<String> genericObject;
#SuppressWarnings("unchecked") // I don't realy like this
#Override
public <T> void setGenericObject(GenericObject<T> obj) {
genericObject = (GenericObject<String>) obj;
}
}
The real problem is that
public <String> void setGenericObject(GenericObject<String> obj)
where the String has nothing to do with the your intended java.lang.String. Here the String is just a type parameter whose name is String by accident.
Please refer to Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type?.
Case 1:
If T is not used in Generic, then just use a wildcard.
class Generic {
List<?> list;
void set(List<?> list) {
this.list = list;
}
int size() {
return list.size(); // doesn't care about T
}
}
Case 2:
If T is only used as local variables, then declare <T> on the method
class Generic {
<T> void swapFirstAndSecond(List<T> list) {
T first = list.get(0), second = list.get(1);
list.set(1, first);
list.set(0, second);
}
}
Case 3:
If several fields and methods use the same type T, but the exact type of T is not important, then delacre <T> on the class
class Generic<T> {
List<T> list;
void set(List<T> list) {
this.list = list;
}
T getFirst() {
return list.get(0);
}
}
Case 4:
If T must be a specific type, like String, then don't declare type parameter <T>
class Generic {
List<String> list;
void set(List<String> list) {
this.list = list;
}
boolean isFirstContainsSecond() {
String first = list.get(0), second = list.get(1);
// call String.contains here, so T must be String
return first.contains(second);
}
}
what i'm trying to do is as follows:
assume that getClassFromString() and getAllObjectsFromRepositoryByClass() already exist.
why can't i use Class<T extends Named & HasId>.
i tried generifying the class itself, but can't use stuff like T.class etc.
public interface Named { String getDisplayName(); }
public interface HasId { String getId(); }
public class Foo {
public List<PairItem> getPairItems(String typeId) {
Class<T extends Named & HasId> clazz = getClassFromString(typeId);
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
List<PairItem> items = new ArrayList<>();
for (clazz obj : allObjects) {
items.add(obj.getDisplayName(),ibj.getId());
}
return items;
}
You can change you Foo-class in this way:
public class Foo {
public <T extends Named & HasId> List<PairItem> getPairItems(String typeId) {
Class<?> classFromString = getClassFromString(typeId);
// Java 8 seems to be unable to chain asSubclass-calls. These are merely to verify our unchecked cast
classFromString.asSubclass(Named.class);
classFromString.asSubclass(HasId.class);
//noinspection unchecked
return getPairItems((Class<T>) classFromString);
}
public <T extends Named & HasId> List<PairItem> getPairItems(final Class<T> clazz) {
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
List<PairItem> items = new ArrayList<>();
for (T obj : allObjects) {
items.add(new PairItem(obj.getDisplayName(), obj.getId()));
}
return items;
}
}
This fixes your problems with multiple boundaries as they are only allowed for type-parameters per documentation.; also I guess that
If one of the bounds is a class, it must be specified first.
leads to the problem that the asSubclass()-calls can not be chained, otherwise we could remove our unchecked cast.
The second method can profit from the streaming-API like this:
public <T extends Named & HasId> List<PairItem> getPairItems(final Class<T> clazz) {
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
return allObjects.stream()
.map(obj -> new PairItem(obj.getDisplayName(), obj.getId()))
.collect(Collectors.toList());
}
Overall I assumed that you wanted to instantiate PairItem and split the method so there is a unchecked and a fully-checked part.
Is it possible to create a new generic array that implements comparable?
I have something like:
public class MyClass<T extends Comparable<T>> {
...
public T[] myAlgorithm( T[] list1, T[] list2 ) {
T[] newList = (T[]) new Object( ... );
if ( list1[0].compareTo( list2[0] ) < 0 ) {
...
}
return newList;
}
}
But it (obviously) throws the error:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable
I create a new instance of the Object class (the parent of all classes) and cast it to the parameterized type to get the parameterized array. I read from other sources that this is the way to do it. But I want it to use comparable in the way my algo shows in the code, and I don't want to use a collection.
Any way to do something like this?
One way would be as below (untested code):
public class MyClass<T extends Comparable<T>> {
public T[] myAlgorithm( T[] list1, T[] list2 ) {
#SuppressWarnings("unchecked")
T[] newList = (T[])Array.newInstance(list1[0].getClass(), list1.length);
for (T t1 : list1) {
for (T t2 : list2) {
if(t1.compareTo(t2)==0) {
//TODO
}
}
}
return newList;
}
}
I have these classes:
class Parent {
public Parent() {
}
}
class ChildA extends Parent {
public ChildA() {
super();
}
}
class ChildB extends Parent {
public ChildB() {
super();
}
}
public ListClas(List(Parent) list) {
this.list=list;
}
}
And I want to run ListClas constructor as below.
List<ChildA> list_childA = new ArrayList<ChildA>();
List<ChildB> list_childB = new ArrayList<ChildB>();
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
But the compiler throws an error. How do I do this correctly using polymorphism?
If you want a function that accepts List containing subclasses of a superclass you should use syntax.
public ListClas(List<? extends Parent> list){
this.list=list;
}
It will accept both of them.
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
If you change to List<? extends Parent> list (also change ListClas.list field definition) in your ListClas then it will compile and work.
All of them: List<Parent>, List<ChildA> and List<ChildB> are different concrete parameterized type.
You can read more about this here: https://stackoverflow.com/a/20940807/516167
I think you want your ListClas to look something like this:
class ListClas<T>
{
private List<T> list;
public ListClas(List<T> list)
{
this.list = list;
}
}
Then to create them:
ListClas<ChildA> listClasA = new ListClas<ChildA>(list_childA);
ListClas<ChildB> listClasB = new ListClas<ChildB>(list_childB);
The T is a generic type designation. It allows you to use the same class for multiple runtime types. So you can do the above instead of having to write this:
class AListClas
{
private List<ChildA> list;
public AListClas(List<ChildA> list)
{
this.list = list;
}
}
class BListClas
{
private List<ChildB> list;
public BListClas(List<ChildB> list)
{
this.list = list;
}
}
If you don't need quite as much flexibility you could write your ListClas like this:
class ListClas
{
private List<? extends Parent> list;
public ListClas(List<? extends Parent> list)
{
this.list = list;
}
}
and use it like this:
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
I am trying to convert one generic list of enums to another generic list type but always getting the following compile error:
Is not applicable for the arguments
private static <T extends Enum<T>> List<T> enumListFromEnumList(List<Object> sourceEnumsList, Class<T> classObject) {
List<T> enums = new ArrayList<T>();
if(sourceEnumsList != null) {
for(Object enumObject : sourceEnumsList) {
if (enumObject instanceof Enum)
enums.add(Enum.valueOf(classObject, enumObject.toString().toUpperCase()));
}
}
return enums;
}
Even I tried this:
private static <T extends Enum<T>> List<T> enumListFromEnumList(List<T> sourceEnumsList, Class<T> classObject) {
List<T> enums = new ArrayList<T>();
if(sourceEnumsList != null) {
for(T enumObject : sourceEnumsList) {
enums.add(Enum.valueOf(classObject, enumObject.toString().toUpperCase()));
}
}
return enums;
}
This is how I'm consuming the function:
adapterInfo.setResponseTypeList( enumListFromEnumList(info.getResponseTypeList(), CAPInfo.ResponseType.class));
Updates:
It works when I convert to this:
private static <S extends Enum<S>, T> List<S> enumListFromEnumList(List<T> sourceEnumsList, Class<S> classObject) {
List<S> enums = new ArrayList<S>();
if(sourceEnumsList != null) {
for(T enumObject : sourceEnumsList) {
enums.add(Enum.valueOf(classObject, enumObject.toString().toUpperCase()));
}
}
return enums;
}
So now the question is how to translate "<S extends Enum<S>, T> List<S>" part ( I mean how it works)
Here is what you are looking for (I think) :
enum EnumA {
FIRST,
SECOND,
THIRD
}
enum EnumB {
FIRST,
SECOND,
THIRD
}
private static <A extends Enum<A>, B extends Enum<B>> List<B> enumListFromEnumList(List<A> sourceEnumsList, Class<B> classObject) {
List<B> enums = new ArrayList<B>();
if (sourceEnumsList != null) {
for (A enumObject : sourceEnumsList) {
enums.add(Enum.valueOf(classObject, enumObject.toString().toUpperCase()));
}
}
return enums;
}
public static void main(String[] args) {
List<EnumA> listA = new ArrayList<EnumA>();
listA.add(EnumA.FIRST);
listA.add(EnumA.THIRD);
List<EnumB> listB = enumListFromEnumList(listA, EnumB.class);
System.out.println(listB);
}