Array of <? extends T> in Java - java

Is it possible to declare an array of something that extends some class?
I can do:
Map[] foo;
T[] foo; //(in generic class)
Map... foo; //(as argument declaration for "implicit" array)
T... foo; //(as argument declaration in generic class for "implicit" array)
But I need something like:
<? extends Map>[] foo;
<? extends T>[] foo; //(in generic class)
<? extends Map>... foo; //(as argument declaration for "implicit" array)
<? extends T>... foo; //(as argument declaration in generic class for "implicit" array)
It could be used some List<? extends T> instead but it's not quite an array. For Example, if you want to use it in a like this:
public class MyClass<T> {
public void foo(int someOtherStuff, <? extends T>... optionalArray){
//some code
}
}
Maybe "implicit" array isn't correct, please tell me how they're called correctly.

Objects in Java are polymorphic: You can simply declare an array of a common base type and have objects of all kinds of derived classes in it.
To go with Radiodef's example, this is valid code:
Number[] foo = {new Integer(0), new Double(1), new Long(2), ...};
What Java does not have is a mechanism that defines an array restricted to one particular derived type of some known base class, where the particular derived type is only known at runtime.
So, if you mean public void foo(int someOtherStuff, <? extends T>... optionalArray) to check whether the objects in optionalArray are all of the same derived type, then the answer is that this can not be done automatically. You can however use
public void foo(int someOtherStuff, T... optionalArray)
to get the guarantee that all objects in the array are derived of the same class T. They may be of different derived types, though.

By the way.. I found the answer to the initial question, maybe somebody needs it one day:
public class MyClass<T> {
public <R extends T> void foo(int someOtherStuff, R... optionalArray){
//some code
}
}
Found it by mistake by looking at the implementation of Arrays.asList(T[] a). In knew I've seen that syntax somewhere just didn't remember where.

You're completely right Radiodef and Felix
Thanks a lot for your detailed explaination!
I just thought I have to declare it like that because something didn't work and I thought that was the problem. But something different was really the problem. Just want to mention it quickly:
I have following generic class:
public class MyClass<T> {
public void foo1(List<Object> someList){ //wrong
//some code
}
public void foo1(Object... someArray){
//some code
}
public void foo2(List<? extends T> someList){
foo1(someList);
//some code
}
}
I wanted that foo2 would invoke foo1(List<Object> someList) but instead it invoked foo1(Object... someArray) even though T will always extend Object (or not?)
However, to make that work, foo1(List<Object> someList) needs to be declared like this:
public void foo1(List<? extends Object> someList){ //correct
//some code
}
then foo2 will invoke this rather than foo1(Object... someArray).

Related

Why I must declare type parameter before return type in Java?

Without any introduction to generics, I will post my question straight away. Why is this correct:
static<T extends Object> void m1(List<T> list){
//some code
}
And this is not (doesn't compile):
static void m2 (List<T extends Object> list){
//some code
}
Remember that we could use wildcards in the same approach, which would compile just fine:
static void m2 (List<? extends Object> list){
//some code
}
To sum up, why can we use wildcards declaration in parameters, while using type parameter we must declare it before return type?
There are two main points.
First off, as #akuzminykh said in the comments to the question, the ? wildcard is basically just a way to tell the compiler "I don't know what this is gonna be, just assume it could be anything that derives from this class/interface, kthxbye". It doesn't declare any parameter that you could make use of within the method, no identifier you can call upon, nothing. However, type parameters do exactly that, and if you declare a new one, it's a different story than just "calling" the wildcard which you don't have to declare.
Secondly, think of how you would declare a type parameter for a generic class. Do you think this would be enough?
public class Foo {
public T extends CharSequence getBar() {...}
}
public class Foo {
public <T extends CharSequence> getBar() {...}
}
No, none of these two options would work. In order to use a generic type parameter within a class, you have to declare it along with the type itself, not along with the methods/fields that use them. Like this:
public class Foo<T extends CharSequence> {
public T getBar() {...}
}
And in order to use a generic type parameter within a method, you have to declare it along with the method itself or the type that contains the method, not along with the method parameters that use them.

Java generics Enum subtyping Interface

Given the following setup:
public class TestType {
public static void main(String[] args) {
List<Constants> list = new ArrayList<>();
accept(list); //Does not compile
}
static void accept(Iterable<MyInterface> values) {
for (MyInterface value : values) {
value.doStuff();
}
}
}
interface MyInterface<T> {
T doStuff();
}
enum Constants implements MyInterface<Integer> {
ONE, TWO, THREE;
#Override
public Integer doStuff() {
return ordinal();
}
}
Why won't the compiler accept the list as parameter to accept()?
List extends Iterable via Collection so that isn't the problem.
On the other hand, the compiler tells me that
incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>
But Constants IS a MyInterface... isn't it?
The problem is with how Generics work. Specifically, Generics are non-reified... meaning that the compiler will not see an Iterable<enum.Constants> as an Iterable<enum.MyInterface> even if Constants is a sub-class of MyInterface.
However, there is a way to get around it: Generic wildcards.
If you change static void accept(Iterable<MyInterface> values) to static void accept(Iterable<? extends MyInterface> values), it should work.
You need to use Iterable<? extends MyInterface> instead of Iterable<MyInterface> because even though Constants is a subtype of MyInterface, Iterable<Constants> is not a subtype of Iterable<MyInterface> - and I'll show you why:
If it was so (let's use List instead of Iterable for the next example), I would be able to do this:
List<Constant> constantsList = new ArrayList<Constants>(); // list of constants
List<MyInterface> ifaceList = constantsList; // you said this would be OK ...
// assume MyOtherImplementation is another implmentation of MyInterface
ifaceList.add(new MyOtherImplementation()); // OK, MyOtherImplementation implements MyInterface
Constant myConst = constantsList.get(0); // Oops! I just got an instance of MyOtherImplementation from List<Constant> - not cool.
Generic types do not inherit this way, although it may seem counter-intuitive at first glance. Using Iterable<? extends MyInterface> will allow you to use any Iterable (e.g., a List) of a type that extends MyInterface (e.g. Constants).

An interface has two type parameters. Can I implement the interface with the two types being the same, such that they are then compatible?

This is an existing interface:
public interface MyInterface<T, U> {
public T foo(U u);
}
I want to implement this interface under the assumption that T and U are the same type. I thought maybe I could leave the type parameters in as they are, and then as long as I only ever instantiate this particular implementation with two of the same type, that it might work:
public class MyOuterClass<A> {
public class MyClass<T, U> implements MyInterface<T, U> {
#Override
public T foo(U u) {
return u; //error here
}
//even though in the only instantiation of MyClass, T and U are the same
private MyClass<A, A> myInstance = new MyClass<A, A>();
}
But, perhaps unsurprisingly, this doesn't work, as types T and U are incompatible.
So then I thought maybe I could change MyClass to specify that its types would always be the same, by changing it to something like MyClass<A, A> implements MyInterface<A, A> or similar, but I get errors saying that T is already defined.
Is there a way to implement MyClass so that its two types will be the same?
(I'm more of a C++ guy than Java, so sorry if I'm missing something fundamental about Java's generic's here.)
Your myclass needs to look like this:
public class MyClass<T> implements MyInterface<T, T> {
#Override
public T foo(T in) {
return in;
}
}
Let's review what your suggested class definition does:
public class MyClass<T, U> implements MyInterface<T, U>
In this code, T and U do two things each:
in the first occurance they define a type variable of your MyClass class
in the second occurance they specify the concrete type of the MyInterface class
Since inside the body of your class T and U are unbounded type variables (i.e. nothing is known about the actual types), they are assumed to be incompatible.
By having only a single type variable in your MyClass you make your assumption explicit: there's only a single type, and I'm using it for both types of the interface.
Last but not least: remember that the compilation of a type is complete once the source is fully handled. In other words: contrary to what C++ does, "instantiation" of a generic type ("template type" or similar in C++; Sorry for my rusty terminology) does not handle. MyClass<Foo> and MyClass<Bar> are the same type, as far as the JVM is concerned (only the compiler actually distinguishes them).
Define a single type parameter for MyClass:
class MyOuterClass<A> {
public class MyClass<T> implements MyInterface<T, T> {
public T foo(T u) {
return u;
}
}
// Need only one 'A' here.
private MyClass<A> myInstance = new MyClass<A>();
}
When you say
public class MyClass<T> implements MyInterface<T, T> {
... you are defining one generic variable for MyClass and you are saying that it fulfills both the roles T and U in MyInterface.

Java Generics insertion on wildcards

Java is not allowing me to add a subclass of the Type declaration in this class
public class Exam<T> {
public void set(Holder<? super T> hold){
}
public T get(Holder<? extends T> holder){ return holder.get();}
public static void main (String[] args){
Exam<Question> eq = new Exam<Question>();
eq.set(new Holder<Identification>());
}
}
Where Identification is a subclass of Question.
and this how my holder class looks like
public class Holder<T> {
T item;
public void set(T item){ this.item = item; }
public T get(){return item;}
}
ERROR
The method set(Holder<? super Question>) in the type Exam<Question> is not applicable for the arguments (Holder<Identification>)
The error looks pretty self-explanatory to me - the set method expects a Holder<? super Question> and you're trying to give it a Holder of something that is a subclass of Question. As written, Exam.set could take a Holder<Object>, for example, but not a Holder<Identification>.
A good way to think about extends and super in generics is in terms of assignment: T extends Foo will accept any type T that you could use on the right hand side of an assignment to Foo without casting, i.e.
Foo something = new T();
(treat this as pseudocode - I know you're not really allowed to new a type varaible). Conversely, T super Foo accepts any T you could use on the left hand side of an assignment without casting:
T myThing = new Foo();
In your specific example, Identification i = new Question() isn't legal without a cast, so a Holder<? super Question> parameter can't accept a Holder<Identification> value.
Exam<T> expects a Holder<T> that can hold any subclass of T. That's what the super does. You are passing a Holder<Identification> but Identification is neither T nor a superclass of it.
change set method of class Enum to
public void set(Holder<? extends T> hold){
}
Generic is invariant. That could be an answer for you. Invariant means that Type2 is a subclass of Type1 so it doesn't mean that List is a List.
It works (but has a different meaning, of course) if you write
public void set(Holder<? extends T> hold){ }

Java generic programming with unknown generic type of interface

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.

Categories

Resources