This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Java Generics: Cannot cast List<SubClass> to List<SuperClass>?
I want to create function on some base class, that create it inheritance classes.
I have try this:
class BaseFormat
{
// Some variables
public BaseFormat(string txt)
{
// Do something
}
public static <T> ArrayList<T extends BaseFormat> getTextFormat(String[] txt)
{
ArrayList<T> list = new ArrayList<T>();
for (int i = 0; i < txt.length; i++)
{
list.add(new T(txt[i])); // ERROR
}
return list;
}
}
class FooFormat extends BaseFormat
{
// Some variables
public FooFormat (string txt)
{
// Do something
}
}
And this:
class BaseFormat
{
// Some variables
public BaseFormat(string txt)
{
// Do something
}
public static ArrayList<BaseFormat> getTextFormat(String[] txt)
{
ArrayList<T> list = new ArrayList<T>();
for (int i = 0; i < txt.length; i++)
{
list.add(new BaseFormat(txt[i]));
}
return list;
}
}
But when I try to cast the array I receive an error. This is my code:
String[] txts = ...; // Some texts
ArrayList<FooFormat> list = (ArrayList<FooFormat>) BaseFormat.getTextFormat(txts); // Casting ERROR
So how can I do it, but still keep it generic?
You would have to pass the type in as a parameter to the static method, and then probably use reflection to invoke Class.newInstance. Type erasure means you will not have a concrete type T after compilation, so that is why you can't compile new T(...)
try doing
ArrayList<BaseFormat> list = (ArrayList<BaseFormat>) BaseFormat.getTextFormat(txts);
Then on iterating you can down cast the items to FooFormat with check of instanceOf operator
So, you are mixing generics, which allow dynamic typing, with inheritance, which allows overriding methods. What you really want is to separate creating the wrapped string from creating the list.
class BaseFormat
{
// derived classes override this method to provide their own implementations
public abstract BaseFormat wrapText(String[] txt);
public ArrayList<? extends BaseFormat> getTextFormat(String[] txt)
{
ArrayList<? extends BaseFormat> list = new ArrayList<BaseFormat>();
for (int i = 0; i < txt.length; i++)
{
list.add(wrapText(txt);
}
return list;
}
}
Are you trying to do something as follows
class BaseFormat { }
class FooFormat extends BaseFormat { }
class FormatUtils {
public static <T extends BaseFormat> List<T> getTextFormat(String[] txt, Class<T> clazz) {
List<T> list = new ArrayList<T>();
//...
T t = clazz.newInstance(); //create instance using reflection
//...
return list;
}
}
And do
List<FooFormat> list = FormatUtils.getTextFormat(new String[]{}, FooFormat.class);
Related
I have two a conditions in the method:
if(urlSendModel.isHasPhoto()) {
ArrayList<InputMediaPhoto> inputMediaPhotos = new ArrayList<>();
for(String photoUrl : urlSendModel.getPhotos()){
inputMediaPhotos.add(new InputMediaPhoto(photoUrl));
}
SendMediaGroup sendMediaGroup = new SendMediaGroup(message.chat().id(),
inputMediaPhotos.toArray(new InputMediaPhoto[0]));
bot.execute(sendMediaGroup);
}
if(urlSendModel.isHasVideo()){
ArrayList<InputMediaVideo> inputMediaVideos = new ArrayList<>();
for(String videoUrl : urlSendModel.getVideos()){
inputMediaVideos.add(new InputMediaVideo(videoUrl));
}
SendMediaGroup sendMediaGroup = new SendMediaGroup(message.chat().id(),
inputMediaVideos.toArray(new InputMediaVideo[0]));
bot.execute(sendMediaGroup);
}
How can I create something like this or solve the problem in another way.
private <T extends InputMedia<T>> void sendMedia(Message message, ArrayList<String> urls) {
ArrayList<T> inputMedia = new ArrayList<>();
for(String url : urls){
inputMedia.add(new T(url));
}
SendMediaGroup sendMediaGroup = new SendMediaGroup(message.chat().id(),
inputMedia.toArray(new T[0]));
bot.execute(sendMediaGroup);
}
I will be glad to any proposed solution.
Both of the requirements here can be gotten around by passing the class into the method. I'll skip the additional details of what your method does, but, for instance:
<T> void doSomething(final Class<T> klass, final int length) {
// Replace 'new T[10]'
final T[] array = Array.newInstance(klass, length);
final Constructor<T> constructor = klass.getConstructor();
for (int i = 0; i < length; i++) {
// Replace 'new T()'
array[i] = constructor.newInstance();
}
}
Note 1: The replacement for new T() was provided by #Vince Emigh.
Note 2: Exception handling is not considered here, so this will not compile as-is.
Note 3: If you need to use a different constructor to the one with no arguments, then it may well be simpler to accept a Function<Object[], T> which will convert the arguments you provide to an instance of the type.
You can do something like creating the generic class first :
public class ClassList<T extends Object>{ private ArrayList<T> list; .... }
// or
public class ClassList<T extends InputMedia>{ private ArrayList<T> list; .... }
and then you cas use constructor or setter to affect a value to your attribute list of T
I have a problem with Java's Generic System.
In my program is a wrapper for lists, that should have a method to return it's inner list:
public class Wrapper<T, S extends List<T>> {
private S list;
public Wrapper(S list) {
this.list = list;
}
public S get() {
return list;
}
}
Then there is a Context that holds a Map with different Wrappers and a method that returns the list of the wrapper associated with the id:
public class Context {
private Map<String, Wrapper> map;
public Wrappers() {
map.put("a", new Wrapper(ArrayList<String>());
map.put("b", new Wrapper(LinkedList<Integer>());
}
public <T, S extends List<T>> S getList(String id) {
return map.get(id).get();
}
}
Now when I call getList() I want to have a compiler warning or at least a way to realise an error before a ClassCastException gets thrown.
public class Receiver {
public doSomething() {
Context c = new Context();
c.createWrappers();
// Ok
ArrayList<String> list1 = c.getList("a");
LinkedList<Integer> list2 = c.getList("b");
// Compiler error or some way do check in getList().
ArrayList<Integer> list3 = c.getList("a");
LinkedList<String> list4 = c.getList("b");
}
}
I've actually tried a lot of things like changing the Wrapper definition to:
public class Wrapper<T, S extends List>
But when I want to implement the get() function I run into a problem I can either define the function like this:
public List<T> get() {
return list;
}
or like this
public S get() {
return list;
}
In the first example it would still be possible to do this.
public doSomething() {
//...
LinkedList<String> list = c.getList("a");
}
and in the second example it would be possible to do this.
public doSomething() {
//...
ArrayList<Integer> list = c.getList("a");
}
Is there any way to define the get method in a way like this?
public S<T> get() {
return list;
}
It seems to me like there is no way to check both the type of the list and the type of the elements at the same time.
The compiler has no way of knowing what return type is associated with the particular string you passed (strings cannot be made type-safe).
However, you could replace strings with type-safe marker objects:
class ListId<T> {
public ListId(string name) { ... }
public static final ListId<ArrayList<String>> A = new ListId<>("a");
public static final ListId<LinkedList<Integer>> B = new ListId<>("b");
}
public T getList<T>(ListId<T> id)
If I have the following code:
public class DummyClass<T> {
public List<T> getList() {
return new ArrayList<T>();
}
public Set<List<T>> getListSet() {
return new HashSet<List<T>>();
}
}
and I have a DummyClass<?> dummy,
I can do
List<?> list = dummy.getList();
without any errors.
However,
Set<List<?>> listSet = dummy.getListSet();
gives the compile error:
Type mismatch: cannot convert from Set<List<capture#1-of ?>> to Set<List<?>>
for the line assigning dummy.getListSet().
Why can't I assign dummy.getListSet() to a Set<List<?>>?
However you can do following:
Set<? extends List<?>> listSet = listSet = dummyClass.getListSet();
See the excellent article Generics gotchas.
First is important to know, that the compiler replace ? operator with Object class. So when you write this:
DummyClass<?> dummy
your class definition will look like this:
public class DummyClass<Object>
and methods like this:
public List<Object> getList() {
return new ArrayList<Object>();
}
public Set<List<Object>> getListSet() {
return new HashSet<List<Object>>();
}
You can write
List<?> list = new List<Object>();
but not
Set<List<?>> set = new HashSet<List<Object>>();
At first glance, I would have expected to be able to cast
ArrayList<Class<? extends Interface1>>
to
ArrayList<Class<?>>
since the second is clearly a less restrictive version of the first. However, the following code does not compile:
import java.util.ArrayList;
public class TypeInvocationConversionTest
{
private static ArrayList<Class<? extends Interface1>> classList;
private static ArrayList<Class<?>> lessRestrictiveClassList;
public static void main(String[] args)
{
classList = new ArrayList<Class<? extends Interface1>>();
lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
}
private interface Interface1 {}
}
but produces the error
TypeInvocationConversionTest.java:12: inconvertible types
found : java.util.ArrayList<java.lang.Class<? extends TypeInvocationConversionTest.Interface1>>
required: java.util.ArrayList<java.lang.Class<?>>
lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
^
I don't think it's unreasonable to want to convert these two types: for motivation, here's a short program that's closer to what I'm actually dealing with (this code does not compile):
import java.util.ArrayList;
public class Mammal
{
public void produceMilk() {}
}
public class Reptile
{
public void layEggs() {}
}
public interface Species
{
String getSpeciesName();
}
public class Dog extends Mammal
implements Species
{
#Override
public String getSpeciesName()
{
return "Canis lupus familiaris";
}
}
public class Cat extends Mammal
implements Species
{
#Override
public String getSpeciesName()
{
return "Feles catus";
}
}
public class Boa extends Reptile
implements Species
{
#Override
public String getSpeciesName()
{
return "Boa constrictor";
}
}
public class Panel3 extends Reptile
implements Species
{
#Override
public String getSpeciesName()
{
return "Dromiceiomimus brevitertius";
}
}
public class AnimalFunTime
{
public static void main(String[] args)
{
ArrayList<Class<? extends Mammal>> listOfMammals;
ArrayList<Class<? extends Reptile>> listOfReptiles;
ArrayList<ArrayList<Class<?>>> matrixOfAnimals;
listOfMammals.add(Dog.class);
listOfMammals.add(Cat.class);
listOfReptiles.add(Boa.class);
listOfReptiles.add(Panel3.class);
///////////////////////////////////////////////////////////////////////////
// The following two lines cause an error. //
///////////////////////////////////////////////////////////////////////////
matrixOfAnimals.add( (ArrayList<Class<?>>) listOfMammals);
matrixOfAnimals.add( (ArrayList<Class<?>>) listOfReptiles);
// Get milk.
for (int i = 0 ; i < listOfMammals.size() ; i++) {
listOfMammals.get(i).produceMilk();
}
// Get eggs.
for (int i = 0 ; i < listOfReptiles.size() ; i++) {
listOfReptiles.get(i).layEggs();
}
// Display all the animals' names.
for (int j = 0 ; j < matrixOfAnimals.size() ; j++) {
ArrayList<Class<?>> currentFamily = matrixOfAnimals.get(j);
for (int i = 0 ; i < currentFamily.size() ; i++) {
Class<?> currentAnimal = currentFamily.get(i);
if (Species.isAssignableFrom(currentAnimal) {
System.out.println(currentAnimal.getSpeciesName());
}
else
{
throw new SpeciesNotImplementedException("Please tell us the animal's name!");
}
}
}
}
}
As the comment says, this code doesn't compile because I am unable to make a list that contains both ArrayList<Class<? extends Mammal>> and ArrayList<Class<? extends reptile>> objects. If I could cast those both to ArrayList<Class<?>>s, then that would be fine. Is there a way to do the cast so this sort of thing works?
One of the reasons this doesn't (and shouldn't) work is that lessRestrictiveClassList would reference the same list object as classList. So, if you add an object of type Class<?> (where ? does not extend Interface1) to that list, suddenly the contract of classList is broken:
ArrayList<Class<? extends Interface1>> classList = new ArrayList<>();
// assume this is allowed:
ArrayList<Class<?>> lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
// now add an element to the less restrictive list
lessRestrictiveClassList.add(String.class);
// and obtain it from the original list
// this code will crash, because String does not implement Interface1
Class<? extends Interface1> cls = classList.get(0);
The last line will get you in big problems, because it can lead to unexpected failure of code.
Instead of referencing the array list twice, you should make a copy to the less restrictive list:
ArrayList<Class<? extends Interface1>> classList = new ArrayList<>();
ArrayList<Class<?>> lessRestrictiveClassList = new ArrayList<>();
lessRestrictiveClassList.addAll(classList);
Forget the generics and cast to raw type ArrayList.
ArrayList<ArrayList> matrixOfAnimals = new ArrayList<>();
matrixOfAnimals.add(listOfMammals);
since the second is clearly a less restrictive version of the first.
It is not. List<A> is not a subtype of List<B> even if A is a subtype of B. Heuster demonstrated why it's unsafe.
If you don't need to add elements using the second list reference, you should use ArrayList<? extends Class<?>> instead. You can convert ArrayList<Class<? extends Interface1>> to that.
You can do the cast you want by doing two cast in a row:
lessRestrictiveClassList = (ArrayList<Class<?>>) (ArrayList<?>) classList;
This compiles.
So heres my problem. I have two classes...SingularEntity and a ListEntity. As the name suggests, SingularEntity represents an Entity and a ListEntity represents a List of Singular Entities....the list obviously has more common properties than the SingularEntity itself. So I have an AuthorizationEntity which extends the SingularEntity class
public class SingularEntity{
}
public class AuthorizationEntity extends SingularEntity{
}
Now I have a single ListEntity which represents a List of any SingularEntities
public class ListEntity{
public List<? extends SingularEntity> data;
public ListEntity(List<? extends SingularEntity> data){
this.data = data;
}
}
Now, I want to use reflection to populate a list always....and I always run into an error in the results.add method. Says that method List.add(CAP#1) is not applicable. Any help is gladly appreciated
public List<? extends SingularEntity> build() {
List<? extends SingularEntity> results = new ArrayList<SingularEntity>();
try {
Constructor javaBeanClassConstructor =
(Constructor) DTOClass.getDeclaredConstructors()[0];
Class<?>[] constructorParameterTypes =
javaBeanClassConstructor.getParameterTypes();
for (Object[] columns : lstInput) {
Object[] constructorArgs = new Object[constructorParameterTypes.length];
for (int j = 0; j < columns.length; j++) {
Object columnValue = columns[j];
Class<?> parameterType = constructorParameterTypes[j];
// convert the column value to the correct type--if possible
constructorArgs[j] = ConversionManager.getDefaultManager()
.convertObject(columnValue, parameterType);
}
*results.add(javaBeanClassConstructor.newInstance(constructorArgs));*
}
}catch(Exception ex){
}
return results;
}
You should parameterize your ListEntity class
public class ListEntity<T extends SingularEntity>{
public List<T> data;
public ListEntity(List<T> data){
this.data = data;
}
}
The problem here is that you've defined a List<? extends SingularEntity>, so you cannot add to this List. Why not? Because to the compiler, this List could be of anything that extends SingularEntity, say a new MultipleEntity class. Java cannot allow you to add any arbitrary SingularEntity to any List of any possible subclass of SingularEntity.
To add to the List, just use a List<SingularEntity>.