Suppose we have the following:
public class Parent{
public void setXXX(String XXX);
public String getXXX();
}
public class Children extends Parent{
....
}
Now I want to create a method called clone List like the following:
public List<Something> cloneList(List<Something> original){
List<Something> newList=new ArrayList<>();
for(Something e:original){
Something newE=new Something();
newE.setXXX(e.getXXX());
newList.add(newE);
}
return newList;
}
The thing is we want cloneList can be applied to both List<Parent> and List<Children>, so is there anyway that applicable for "Something"?
Something cannot be "? extends Parent" or "Parent" due to the Java Collection<Parent> incompatible with Collection<Children>
Assumption:
1. Don't want to use any serialization approach or reflection.
We are unable to modify the Parent and Children class. This is predefined in 3rd party Jar.
SuperParent class is not possible because we cannot modify Parent as stated in 2.
That is not possible in Java. Take a look at Generic syntax for extends or equal to.
You could change your method as follows and make your Parent class extend SuperParent.
public static <T extends SuperParent> List<T> cloneList(List<T> original, Class<T> type) throws IllegalAccessException, InstantiationException {
List<T> newList=new ArrayList<>();
for(T e : original){
T x = type.newInstance();
x.setXXX(e.getXXX());
newList.add(x);
}
return newList;
}
Also, you could choose another cloning approach. For example, using Apache Commons' SerializationUtils:
List<Children> result = (List<Children>) SerializationUtils.clone(originalList);
You cannot use generics this way, only reflection.
For a type variable T, you cannot use new T(). That's because generics are a compile-time mechanism, and new is used in run-time to create a specific-type object, and the compiler cannot create the appropriate reference to the type at compile time. So while this:
new ArrayList<T>();
is legal, because the compiler actually compiles it into the code for creating the raw ArrayList type, this:
new T();
is not, because the compiler does not even know what the actual class will be (even if it was just defined as T extends Parents it could be a class that has not even been written when the program compiled, like Grandchildren or something), and does not even know if it has a parameterless constructor.
In a general sense, you should be able to use a method having this signature:
public <T extends Parent> List<T> cloneList(List<T> original)
That's not your biggest problem, however. THAT would be obtaining copies of the list elements. Your code cannot use
T newE = new T(); // doesn't work
because the existence of a nullary constructor for type argument T cannot be guaranteed. Instead, you need a method that will return a correctly-typed copy. You cannot do this with complete type safety, but you can come close. You can implement these methods:
public Parent Parent.copy();
public Children Children.copy();
... in whatever way is appropriate, and then write your method like so:
public <T extends Parent> List<T> cloneList(List<T> original) {
List<T> newList = new ArrayList<>();
for (T originalItem : original) {
newList.add(original.getClass().cast(original.copy()));
}
return newList;
}
(Note that although the documented return type of Object.getClass() is Class<?>, which would not work for this purpose, the method documentation says that the return type is actually a bit more specific than that, enough so to make this work.)
Change the signature of cloneList to:
public <X extends Parent> List<X> cloneList(final List<X> original)
Then it will work, at least for the method signature. You can internally construct a List<Parent> and then cast it to List<X> and ignore the warnings if you need to; there's no way to find out the runtime type of "X".
Related
Can anyone please explain me below code
public <T extends Emp> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
I am trying to understand how Generics will apply on void return type.
Note: i have changed the code now it is not giving any error.
I am trying to understand how generics will apply on void return type.
This is only a syntax. Generics do not apply to void return type, they apply to the method as a whole.
The name and restrictions on the generic parameter need to go somewhere in the text of your program. In a class declaration they follow the class name in angular brackets. In a generic method declaration they follow the accessibility designator public, and precedes the return type void.
One could easily imagine an alternative placement of generic types, such as
public void foo<T extends Emp>(ArrayList<T> list) // Imaginary syntax
or even
public void foo(ArrayList<T> list) <T extends Emp> // Imaginary syntax
but Java designers decided on the placement before the return type designator.
Generics won't be applied to void.
If you say that the type is <T extends Emp>, you are saying, that any subtype of Emp can be applied in place of T.
In your code, You can use <T> instead of <T extends Emp> as you aren't doing anything with Emp
public <T> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
Regarding how it'll work, the type will be provided by you when you use this method and at compile time, java will place required casts automatically. So, if you are using this:
ArrayList<String> list = new ArrayList<>();
// Add some items into list
foo(list);
in that case, your foo() method will find out that type <T> is String and so, will behave something like:
public void foo(ArrayList<String> list) {
list.add((String)(list.remove(0)));
}
As a follow up to Java generics compile in Eclipse, but not in javac, I post another snippet which compiles and runs fine in Eclipse, but raises a compilation error in javac. (This prevents the project the snippet is extracted from, from being build with Maven.)
The self-contained snippet:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Foo<?>> setOfFoos = new HashSet<Foo<?>>();
List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
}
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c) {
List<T> list = new ArrayList<T>(c);
java.util.Collections.sort(list);
return list;
}
public static class Foo<T> implements Comparable<Foo<T>> {
#Override
public int compareTo(Foo<T> o) {
return 0;
}
}
}
Compilation in javac returns:
Main.java:11: <T>asSortedList(java.util.Collection<T>) in Main cannot be applied to (java.util.Set<Main.Foo<?>>)
List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
^
On substitution of Foo<?> with Foo<String> the above snippet will compile in javac, which means the problem is related to the used wildcard. As the Eclipse compiler is supposed to be more tolerant, is it possible the snippet is no valid Java?
(I use javac 1.6.0_37 and Eclipse Indigo with compiler compliance level 1.6)
(EDIT1: Included another example which got removed in EDIT2.)
EDIT2: Hinted by irreputable, that comparing Foo<A> and Foo<B> may be conceptually wrong, and inspired by the answer of seh, a working asSortedFooList can be written as follows:
public static <T extends Foo<?>> List<T> asSortedFooList(Collection<T> c) {
List<T> list = new ArrayList<T>(c);
java.util.Collections.sort(list);
return list;
}
(Simple substitution of Comparable<T> with Foo<?> in the method definition above.)
So it seems to be safe for javac and imho conceptually right to compare any Foo<A> and Foo<B>. But it is still not possible to write a generic method asSortedList which returns a sorted list representation for a generic collection, if its type argument is parametrized with a wildcard. I tried to "trick" javac by substituting Foo<?> by S extends Comparable<S> in asSortedFooList, but this didn't work.
EDIT3: Later Rafaelle pointed out, that there is a flaw in the design, since implementing Comparable<Foo<T>> is not necessary, and implementing Comparable<Foo<?>> provides the same functionality, solving the initial problem by refined design.
(The initial reason and benefit was, that a Foo<T> may not care in some purposes about its concrete type but still use an instance of a concrete type T, it is instantiated with, for other purposes. That instance does not have to be used for determining the order among other Foos, as it may be used in other parts of the API.
Concrete example: Assume each Foo is instantiated with a different type argument for T. Every instance of Foo<T> has an incrementing id of type int which is used in the implementation of the compareTo-method. We can now sort a list of these differently typed Foo and don't care about the concrete type T (expressing it with Foo<?>) and still have an instance of a concrete type T accessible for later processing.)
To me this is another javac bug. When you try to send a Collection<Foo<?>> to a method with the signature:
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c)
the compiler notes that the formal parameter T has an upper bound, so checks if the constrained is honored by the caller. The type argument is a (wildcard) instantiation of the parameterized type Foo<T>, so the test will pass if Foo<?> is-a Comparable<Foo<?>>. Based upon the generic definition:
class Foo<T> implements Comparable<Foo<T>>
I'd say that it's true, so again Eclipse is right and javac has a bug. This Angelika Langer's entry is never linked enough. Also see the relevant JLS.
You asked if it is type-safe or not. My answer is that it is type safe, and it shows you have a flaw in your design. Consider your fictitious implementation of the Comparable<T> interface, where I added two more fields:
public static class Foo<T> implements Comparable<Foo<T>> {
private T pState;
private String state;
#Override
public int compareTo(Foo<T> other) {
return 0;
}
}
You always return 0, so the problem is not spotted. But when you try to make it useful, you have two options:
Comparing on the String field
Comparing on the T member
The String field is always a String, so you don't really benefit from the type variable T. On the other hand, T has no other type information available, so in compareTo() you can only deal with a plain object, and again the type parameter is useless. You can achieve the same exact functionality by implementing Comparable<Foo<?>>
In this case, javac is correct. Conceptually, your code can't work, since the set may contain Foo<A> and Foo<B>, which can't be compared to each other.
You probably want the set to be a Set<Foo<X>> for some type variable X; unfortunately we can't introduce type variable inside method body; only in method signature
<X> void test(){
Set<Foo<X>> setOfFoos = new HashSet<Foo<X>>();
List<Foo<X>> sortedListOfFoos = asSortedList(setOfFoos);
}
You may make it work by something like
<T extends Comparable<? super T>> List<T> asSortedList(Collection<T> c)
class Foo<T> implements Comparable<Foo<?>>
I don't know if this is a question, but here is a (not very nice) answer:
If you sacrifice some type safety you can write
#SuppressWarnings({ "unchecked", "rawtypes" })
public static <T extends Comparable> List<T> asSortedList(Collection<T> c) {
List<T> list = new ArrayList<T>(c);
java.util.Collections.sort(list);
return list;
}
And it works in both eclipse and javac. The only risk that I'm aware of is that if someone creates a class Foo extends Comparable<Bazz> you won't detect that in compile time.
But if someone creates Foo extends Comparable<Bazz>, just kill him/her.
I found a solution that compiles with javac, though I am not happy that I am unable to explain exactly why it works. It requires introducing an intermediary function:
public final class Main {
public static class Foo<T> implements Comparable<Foo<T>> {
#Override
public int compareTo(Foo<T> o) {
return 0;
}
}
public static <T extends Comparable<? super T>>
List<T> asSortedList(Collection<T> c) {
final List<T> list = new ArrayList<T>(c);
java.util.Collections.sort(list);
return list;
}
private static <T extends Foo<?>> List<T> asSortedFooList(Collection<T> c) {
return asSortedList(c);
}
public static void main(String[] args) {
final Set<Foo<?>> setOfFoos = new HashSet<Foo<?>>();
final List<Foo<?>> listOfFoos = asSortedFooList(setOfFoos);
}
}
I think that this works by virtue of taking the wildcard resolution step-by-step; asSortedFooList() captures one type known to be a Foo, irrespective of Foo's type parameter. With that type parameter bound in asSortedFooList(), we can then call on your original asSortedList() (well, with one modification—note the lower bound on the type parameter for Comparable) requiring binding Foo as a type descended from Comparable.
Again, that's a weak, haphazard explanation. My main point in answering here is just to provide one more way to get to your destination.
If you can replace your wildcard usage with an exact type (which may be a super-type) your code will work. Replace
List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
with
List<Foo<String>> sortedListOfFoos = Main.<Foo<String>>asSortedList(setOfFoos);
I'm using several interfaces with generics types. While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
Suppose I have the following interface:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is
(and must be) unaware of the concrete type of generics.
Suppose I have the following class:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
First Question :
Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:
MyCollectionInterface is a raw type. References to generic type
LatticeInterface should be parameterized
Second Question :
Why method foo doesn't compile?
Third question:
It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?
Last questions:
Am I doing something weird with this generic interfaces and I should refactor my code?
Do I really have to care about all these warnings?
How can I use safety a generic interface from a class where I don't know its concrete type?
Ok, I played a bit with your code and reached a conclusion.
The problem is that your ConcreteCollection (and its interface MyCollectionInterface) declare the method updateObject as receiving an argument of type MyObjectInterface<T> (where T extends Number) - note that the type is a concrete one (not a wildcard).
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?> but the instance that is passed to ClientClass' constructor will be of a concrete type, for instance:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject of that instance would only accept an argument of type MyCollectionInterface<Integer>.
Then, in method foo you are trying to pass a MyObjectInterface<?> to updateObject, but since the compiler doesn't know which generic type your collection accepts (it could be Integer like in my example but it could also be Double or any other type that extends Number), it won't allow any object to be passed.
Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:
1) Pick a concrete type and stick with it:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or:
2) Modify your interface to accept a wildcard type:
public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject method unless you declare your list something like this (with ArrayList for example):
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number> from MyCollectionInterface and ConcreteCollection since T isn't used anymore.
#Your last questions:
1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.
Sorry for the long answer, hope this helps.
My goal is to develop a class that can output an object of a specified class.
public class GetMe<T> {
public T get() {
Object obj = generateObject();
return (T) obj;
}
}
Now, I know this isn't possible due to erasure. So, we can pass in a class instance and use that to cast.
public class GetMe<T> {
public GetMe<T>(Class<T> clazz) {
this.clazz = clazz;
}
public T get() {
Object obj = generateObject();
return clazz.cast(obj);
}
}
This works great! As long as the class isn't parameterized. If it is, then I've got a problem.
I'm not allowed to use List<String>.class. If I pass in a ParameterizedType (which in itself is difficult to generate), there's no cast method to use.
Is there a way out of this quagmire?
I think super type tokens may solve this problem for you.
The problem with List<String> is that, because of erasure, it would at runtime indistinguishable from any other List<?>. The easiest way around this is to create a new class or interface which has the generic part "fixed", like
public interface StringList extends List<String> {
/* nothing to see here */
}
This way you have a type token (the StringList.class object) which you can pass around at runtime and specifies exactly what you want, but without the need for generics at runtime.
Here is just a small idea. I'm not really sure if it will fit in your context but nevertheless:
public class GetMe<T>
{
public List<T> getList() {
#SuppressWarnings("unchecked")
List<T> result = (List<T>) new LinkedList();
return result;
}
}
Cheers!
The first problem is how you plan to instantiate a List object. If you disclose more of what you are trying to build, we may be able to help you better.
You may want to use Type instead of Class. Type can represent all generic types, although it's not pleasant to work with.
abstract public class GetMe<T>
{
Type type;
public GetMe<T>(Type type)
{
this.type = type;
}
}
Another problem is how to create a generic type like List<String>. The "super type token" looks neat in syntax, in reality it's basically
static class XX extends TypeReference<List<String>>{}
....
Type typeListString = Util.extract(XX.class);
I would much prefer this way
List<String> f;
Type typeListString = getDeclaredField("f").getGenericType();
Actually, many of these frameworks that do fancy runtime generic magics are working on instance fields only.
I think the confusion comes from the fact that you're trying to create an object from List<> which in face it an interface, not an object.
So no matter what you'd try, you just can't create an instance of List<> , (interfaces aren't actual classes, and don't have constructors)
Try using a constraint to avoid having interfaces put in the declaration:
public class GetMe<T extends Object>
This will guarantee that T is an actual class and not an interface.
we have a method more or less like the following.
however we currently return List
which in function bla() would return List<Bar> at runtime.
I'm looking for a way to make both
List<Interface> = troubleFuction(foo, bar.getCLass());;
and
List<Bar> = troubleFuction(foo, bar.getCLass());;
possible.
basicaly i want it to return List which would be compatible with interface
however this gives the following error
*Type mismatch: cannot convert from List<capture#3-of ? extends Bar> to List<Interface>*
is there any way to make this return type possible or does runtime erasure make this impossible
public <T1 extends Interface, T2 extends Interface> List<"problem"> troubleFunction( T1 in, Class<T2> clazz) {
return in.doStuffWhichGeneratesAlistOF(clazz)
}
public void bla() {
Foo foo = new Foo(); // implements interface
Bar bar = new Bar(); // implements interface
List<Interface> ifaces = toubleFuction(foo, bar.getCLass());
List<Bar> mustAlsoWork = toubleFuction(foo, bar.getCLass());
}
edit:
in a lot of the existing code base the method is called like
List<Bar> result = troubleFunction(List<Interface> list, Bar.class);
thus this return type must stay compatible (rewrite/re-factor is not an option)
essentially i want the method to return List<? super Bar> if called as
troublefunction(foo, Bar.class);
and
List<? super Foo> when called as
troublefunction(foo, Bar.class);
Generally speaking in situations like this, you need to explicitly pass a Class object in (generically parameterised) which is used for the return value.
However it looks like you've done this already in your case, so would it not work for troubleFunction to be declared to return List<T2>? Alternatively, if you want to keep it general then have it return List<? extends Interface>.
You're not giving us enough information to really tell what you need to do. For example, you didn't give us the type signature of doStuffWhichGeneratesAlistOF() or tell us what it does. And you didn't tell us what the type of the "in" argument has to do with all of this.
Sure, it's possible to have the return type of a method be generic. For example,
public <T extends Interface> List<T> troubleFunction(Interface in, Class<? extends T> clazz) {
List<T> result = new ArrayList<T>();
result.add(clazz.newInstance());
return result;
}
And then you could call the method directly like this and it would work (you don't need to specify the type parameter explicitly because it's inferred from the assignment):
List<Interface> iface = this.troubleFunction(foo, bar.getCLass());
But seeing as how in your code above you return the result of in.doStuffWhichGeneratesAlistOF(clazz), you would probably have to make the return type of that method generic also. But I can't really help you on that because we don't have any information on that method.
As I understand it, the argument types are looked at before the target type to infer the generic arguments. So, I guess you need to explicitly specify the generic arguments, which I think goes something like this:
List<Interface> iface = this.<Interface>troubleFunction(foo, bar.getCLass());
where
public <T extends Interface> List<T> troubleFunction(
T in, Class<? extends T> clazz
) {
i've looked at this again and the problem was that i wanted to use a 'super' return type
the signature i was looking for was more or less:
public <T1 extends interface, T2 super T1> List<T2> getAList(Class<T1> clazz);
which is not possible