I have a bunch of classes in java that all implement an interface called IdObject (specifying a getId() method). Moreover, they also all implement Comparable<> with themselves as type parameter, so they are all comparable to themselves.
What I'd like to do is declare a list of such objects, fill it, then sort it and call getId() on them. So my code looks like this:
List<? extends IdObject & Comparable<?>> objectList = null;
if (foo) {
objectList = new ArrayList<TypeA>();
...
} else if (bar) {
objectList = new ArrayList<TypeB>();
...
}
if (objectList != null) {
Collections.sort(objectList);
for (IdObject o : objectList) {
System.out.println(o.getId());
}
}
Basically my problem lies in the first line -- I want to specify two "constraints" for the type because I need the first one to make sure I can print the ID in the loop and the second one to make sure I can use Collections.sort() on the list.
The first line does not compile.
Is there a way to make this work without specifying a generic type without type parameters and using unchecked operations? I could also not find an example of this on the internet.
Greetings
List<? extends IdObject & Comparable<?>>
This type of multiple bounded type parameters is only possible in class and method signatures, I'm afraid.
So I guess the closest you can get is to define an interface:
public interface MyInterface extends IdObject, Comparable<MyInterface>
And declare your list like this:
List<? extends MyInterface> objectList = null;
How about creating antoher type ;
public CompIdObject extends IdObject implements Comparable {
...
}
and use this type for your generics ?
List<? extends CompIdObject<?>> objectList = null;
I've wanted to do similar things before on fields as well, but it can't be done (perhaps someone could elaborate on whether this is a technical restriction or a design choice, I'm not sure.)
The way forward would be to design an interface that extends the IdObject and Comparable, then use that in your generic list definition.
Related
Hello I try pass to interface as parameter Enum object, and after this parse him to List<Enum> in body default function interface. So my interface looks like below
public interface SpecificObject<T extends Enum<T>>{
default List<Enum> asMyList(){
List<Enum> list = Arrays.asList(T.values()); // not works
return list;
}
}
After this I have a plane use in this way
class SomeObject implements SpecificObject<MyEnum>{
public SomeObject()
// dont' must Overwrite because I use as default
}
And somewhere in code usage, just as below
SpecificObject specificObject = new someObject SomeObject();
List<Enum> list = someObject.asMyList();
Is it possible in JAVA 8?
Step-by-step:
public static <T extends Enum<T>> List<T> getEnumConstants(T object) {
assert object != null;
Class<T> type = object.getClass();
T[] constants = type.getEnumConstants();
return Arrays.asList(constants);
}
Not tested, but this looks workable. The List is however as inflexible as the original T[].
Packing the function in an interface as default method will not bring any advantage.
Note Class.getEnumConstants is not typed for Enum, and will yield null for non-enums.
(When staying in one specific Enum, EnumSet (a kind of bitset) and EnumMap (a kind of array) is often quite efficient and fast.)
I can't believe I cannot capture P without typing the class to a redundant 2-type class:
public class MyClass<T extends List<P>> {
T getList(/**/){}
P getRandomElement(){ /**/ }
}
Do I need, really, to define and instantiate MyClass as MyClass<String,ArrayList<String>>, couldn't it be inferred someway?
EDIT: What I mean is I see redundant having to define MyClass<P,T extends List<P>> because then I need to instantiate it always as MyClass<String,ArrayList<String>>, and carry String everywhere. It would be nice if the language allowed something like MyClass<L extends List<P>> or similar. That way, MyClass<ArrayList<String>> would return an ArrayList<String> when executing getList() and an String when executing getRandomElement(), nicely.
If you really must have the exact type of List returned from getList, then you need the type parameter T as well as P.
public class MyClass<P, T extends List<P>> {
This way you can have a MyClass<String, ArrayList<String>> whose getList method returns an ArrayList<String> and a getRandomElement method that returns a String.
However, it is usually unnecessary to know the exact type of List. Usually, if you have a List, then it doesn't matter to the user of this class which kind of List is really is. In this case, you don't need the type parameter T, only P. You can change your class to this:
public class MyClass<P> {
List<P> getList(/**/){}
P getRandomElement(){ /**/ }
}
Then you can have a MyClass<String> whose getList method returns an List<String> and a getRandomElement method that returns a String.
I have this problem
a method which is cutting unwanted details from one class and returning collection of objects with wanted ones. the matter is I want this metod to be able to work with different classes ( which are based on one abstract, though), so I use generic type. the problem is that in one point I need to create an instance of , which is impossible. I looked for some way out, but it doesn't seem to work for my case.
So, code is following
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates ) {
List<T> restMandates = new ArrayList<>(mandates == null ? 0
: mandates.size());
if (mandates != null) {
for (CardMandate mandate : mandates) {
restMandates.add(new T(mandate));
}
}
return restMandates;
}
RestMandate is base class, CardMandate were I take the info. Any ideas?
Since the generic type arguments are erased at runtime, there is no way you can refer to it like you are trying to do. The only way out is a type tag argument + reflective instantiation.
A better choice is to redesign your solution to solve this without relying on generics and type tags. Leverage dynamic method dispatch instead: add a method to RestMandate which will return the object converted to the desired type.
Because of Type Erasure, T becomes Object at runtime. You don't know its real type anymore.
You can still instantiate the object by reflection if you have its class. In order to do that, you must give the class to your method:
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates, Class<T> clazz ) {
...
for (CardMandate mandate : mandates) {
/*
* I get the constructor which needs one CardMandate and call it.
* Note : I do not recommend this solution (no check at compile-time!).
* Like Marko Topolnik, I advise to redesign the solution.
*/
restMandates.add(clazz.getConstructor(CardMandate.class).newInstance(mandate));
}
...
}
To create an instance you require Class<T> object too
private <T extends RestMandate> List<T> toRestMandate(List<CardMandate> mandates, Class<T> clazz) {
//....
T newInst = clazz.newInstance();
//....
}
I have a group of classes that all implement a validation interface which has the method isValid(). I want to put a group of objects--all of different classes--into an ArrayList, loop through them and call isValid() on each.
Here's my code
Email email = new email();
Address address = new Address();
ArrayList<? extends Validation> myValidationObjects = new ArrayList();
But when I try to do:
myValidationObjects.add(email);
I get:
The method add(capture#2-of ? extends Validation) in the type ArrayList
is not applicable for the arguments (Email)
Both Email and Address implement Validation.
According to this document, I should be able to use extends for both interfaces and subclasses.
List<? extends Validation> myValidationObjects
Incorrect reading
"myValidationObjects is list of objects that extend Validation."
Correct reading
"myValidationObjects can be a list of any type that extends Validation. For example, it could be a List<RangeValidation> or a List<RegexValidation>."
Since there is no object you can legitimately add to both a List<RangeValidation> and a List<RegexValidation>, Java prevents you to call add on a variable of such type.
Your case is in fact the simpler one: you need the definite type List<Validation>.
You can use:
List<Validation> myValidationObjects = new ArrayList<>(); // Java 7
List<Validation> myValidationObjects = new ArrayList<Validation>(); // pre Java 7
Now you can add any instance of a class that implements Validation to that list.
The declaration ArrayList<? extends Validation> means a list of an unknown class that extends Validation. Email is not compatible with this unknown class.
You can use ArrayList<Validation> for your list.
If a generic class's T is <? extends Foo>, then the only thing you can pass to a method that takes T is null -- not any subclass that extends Foo.
The reason is that List<? extends Validation> doesn't mean "a list of things that extend Validation". You can get that with just List<Validation>. Instead, it means "a list of some type, such that that type extends Validation."
It's a subtle distinction, but basically the idea is that List<? extends T> is a subtype of List<T>, and you therefore don't want to be able to insert anything into it. Think of this case:
List<FooValidation> foos = new ArrayList<>();
List<? extends Validation> validations = foos; // this is allowed
validations.add(new BarValidation()); // not allowed! this is your question
FooValidation foo = foos.get(0);
If the third line were allowed, then the last line would throw a ClassCastException.
I took a look on questions q1, q2, q3, but they don't cover exactly my question.
Note that ArrayList<A> and ArrayList<? extends A> are to be used for declaring a variable or a parameter (not for creating a new generic class).
Are both expressions equivalent when declaring an object attribute (case 1)?:
class Foo {
private ArrayList<A> aList; // == ArrayList<? extends A> aList;
}
EDIT: Are both expressions equivalent from the point of view of what
kind of objects are allowed to be added to aList?, but different
in the same sense as the following case?
but they are different when used in a parameter declaration (case 2)?:
void methodFoo(ArrayList<A> al) != void methodFoo(ArrayList<? extends A> al)
because the first one only allows to be passed ArrayList objects
while the second would be like "more permissive" allowing to be sent
ArrayList<A1> and ArrayList<A2> (as long as A1 and A2 extends A)?
If this is right, is there any other scenario where the two expressions are
effectively different?
Thanks,
Let's have a look at some practical examples. Say, you have:
List<Number> list;
This means that whatever is assigned to this variable or field takes Number and outputs Number, so you always know what to expect. Integer can be added to this list since Integer extends Number. However, you can't assign, say, ArrayList<Long> to this list.
But consider this case:
List<? extends Number> list;
This one says: hey, that's a list of something that extends Number, but no one knows what exacty. What does this mean? This means that you can assign, for example, ArrayList<Long> to this list, which you couldn't in the first case. You still know that whatever this list outputs will be a Number, but you can't put an Integer in it anymore.
There is also an opposite case:
List<? super Number> list;
By printing that you say: that's a list of Number or its superclasses. This is where everything becomes vice-versa. The list can now refer to ArrayList<Object> and ArrayList<Number>. Now we don't know what this list will output. Will it be a Number? Will it be an Object? But now we know that we could put a Number in this list as well as any subclass of Number like Integer or Long.
There is a rule, by the way, which says producer extends, consumer super (PECS for short). If you need the list to output the values, it is a producer, this is the second case. If you need the list to accept values, it is a consumer, this is the third case. If you need both, don't use wildcards (that's the first case).
I hope this clears up matters.
This will explain the difference:
public class GenericsTest {
private ArrayList<A> la;
private ArrayList<? extends A> lexta;
void doListA(ArrayList<A> la) {}
void doListExtA(ArrayList<? extends A> lexta) {}
void tester() {
la = new ArrayList<SubA>(); // Compiler error: Type mismatch
doListA(new ArrayList<SubA>()); // Compiler error: Type mismatch
lexta = new ArrayList<SubA>();
doListExtA(new ArrayList<SubA>());
}
static class A {}
static class SubA extends A {}
}
As you see, calling a method and assigning a variable/instance field have the same rules. Look at the method call as an assignment of your argument to its declared parameter.
ArrayList<A> means a specific class A, where as ArrayList<? extends A> means class A or any class which extands A (Sub class of A) this make it more generic
Using private ArrayList<A> aList; as a variable declaration is not really equivalent to using the wildcard private ArrayList<? extends A> aList;
The wildcarded version will allow you to assign any ArrayLists of types that extend A and A itself but will refuse to add elements to the list as it cannot decide if it is type safe. With ArrayList<A> on the other hand you can only assign ArrayLists (or extensions of ArrayList) of type A and you can then add A elements and any elements extending A to it.
FYI: you should prefer using a more abstract type for declaring your variables/parameters like List<A> or Collection<A>.
The main difference is that if the generic form is used as an argument or return type in a method in a base class (or interface), it allows a greater range of type signatures to count as overriding instead of overloading.
Function override-overload in Java
For example, the following code is legal (in Java 7):
interface A
{
List<? extends Number> getSomeNumbers();
}
class B implements A
{
#Override
public ArrayList<Integer> getSomeNumbers()
{
return new ArrayList<>();
}
}
Difference between Enumeration<? extends ZipEntry> and Enumeration<ZipEntry>?
All of this means that sometimes you can write come code that requires less casts when someone else is using it. Which should not only reducing the amout of typing they have to do, but also eliminate possible failures.
Of course, the problem with Java generics is that they were introduced in a way that was constrained by backwards compatibility. So not everything works that you might think should, and the details get pretty hairy as to what exactly works and what doesn't.
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ812
It is hard to grasp at first, but inheritance doesn't apply with generics, ie if B extends A, List<B> is not a "subclass" of (can not be assigned to) List<A>. Further, List<? extends A> is not a "subclass" of (can not be assigned to) List<A>.