Java Generics Class Parameter Type Inference - java

Given the interface:
public interface BasedOnOther<T, U extends BasedList<T>> {
public T getOther();
public void staticStatisfied(final U list);
}
The BasedOnOther<T, U extends BasedList<T>> looks very ugly in my use-cases. It is because the T type parameter is already defined in the BasedList<T> part, so the "uglyness" comes from that T needs to be typed twice.
Problem: is it possible to let the Java compiler infer the generic T type from BasedList<T> in a generic class/interface definition?
Ultimately, I'd like to use the interface like:
class X implements BasedOnOther<Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
} // Does not compile, due to invalid parameter count.
Where Y extends BasedList<SomeType>.
Instead:
class X implements BasedOnOther<SomeType, Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
}
Where Y extends BasedList<SomeType>.
Update: ColinD suggested
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
It is impossible to create an implementation such as:
public class X implements BasedOnOther<SomeType> {
public SomeType getOther() { ... }
public void staticStatisfied(MemoryModel list);
} // Does not compile, as it does not implement the interface.
Where MemoryModel extends BasedList<SomeType>, which is needed (as it provides other methods).

It looks as if you don't actually need the type parameter U extends BasedList<T>, if you don't actually need to do anything in the class that requires some specific subclass/implementation of BasedList<T>. The interface could just be:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
Edit: Based on your update, I don't think there's any way you can do this. I think you'll have to either just go with your original declaration or make some intermediate type that specifies T, like:
public interface BasedOnSomeType<U extends BasedList<SomeType>>
extends BasedOnOther<SomeType, U>
{
}
public class X implements BasedOnSomeType<MemoryModel> { ... }
That seems like kind of a waste though, and I don't really think the original declaration looks that bad.

What about this?
public interface BasedOnOther<T> {
public T getOther();
public <U extends BasedList<T>> void staticStatisfied(final U list);
}

ColinD is almost correct. What you probably want is this:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<? extends T> list);
}
That's because method arguments are covariant but the generics are invariant. Look at this example:
public test() {
Number n1;
Integer n2; //Integer extends Number. Integer is a more-specific type of Number.
n1 = n2; //no problem
n2 = n1; //Type mismatch because the cast might fail.
List<Number> l1;
List<Integer> l2;
List<? extends Number> l3;
l1 = l3; //No problem.
l1 = l2; //Type mismatch because the cast might fail.
}
Why:
Trying to put an Integer where a Number belongs is covariance and it's usually correct for function arguments.
Trying to put a Number where an Integer belongs is the opposite, contravariance, and it's usually correct for function return values. For example, if you defined a function to return a Number, it could return an Integer. If you defined it to return an Integer, however, you couldn't return a Number because that might be a floating-point, for example.
When you're dealing with generics, the compiler can't tell if the generic parameter (in your case, T) is going to be covariant or contravariant. In your code, for example, T is once a return value and once part of an argument. For that reason, generic parameters are invariant by default.
If you want covariance, use <? extends T>. For contravariance, use <? super T>. As a rule of thumb, you probably always want to specify the covariance/contravariance on all public functions. For private functions it doesn't matter as much because you usually already know the types.
This isn't specific to java, other object-oreiented languages have similar issue.

I recently had a very similar problem.
I would suggest, if you are do not need to specifically refer to MemoryModel, i.e. if U extends BasedList<T> is enough, then I would definitely do what Pepe answered.
However, if you must type check for at least two methods that both methods must use MemoryModel specifically and the type inferencing in Pepe's answer is not enough, then the only way to make the use of the clumsy/verbose parameterized constructor more simplistic, is to exploit the generic method parameter inferencing. You would need to create generic static factory methods for each constructor, where the factory methods do the type inferencing (constructors can't type inference in Java).
How to do this is covered in
Effective Java, by Joshua Block; Item 27: Favor generic methods
I also explained this and quoted the solution (with code) here.

Related

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){ }

Generics- am I missing something or what is the point?

I have the following code:
public class AClass<X extends AnInterface> implements AnotherInterface {
public AClass(X x){
}
}
Why would I use X as the constructor parameter type, when I could just replace this with AnInterface?? Surely they mean the same thing, anything which is a subtype of AnInterface?
I am trying to keep all my parameter types as generic and only mention Interface names in the generic parametric declarations eg "X extends AnInterface" but running into problems because it is saying the value I pass in, which is of type AnInterface, is not equal to type X.
EDITED:
public void<X extends AnInterface> myMethod(){
AnInterface b = new ADiffClass();
AnotherInterface a = new AClass(b);
}
public class ADiffClass<X extends AnInterface> implements AnInterface {
public ADiffClass(){
}
}
This is where I am having problems, I get a compile error saying that the type of b is AnInterface and the type required in the constructor of AClass is X.
If you declare a variable like this:
private AClass<Foo> a;
the following will be valid:
a = new AClass<Foo>(new Foo());
but the following wwon't:
a = new AClass<Foo>(new Bar());
(assuming Foo and Bar are two implementations of AnInterface).
That's the point of generics in that case: restrict the type to a specific type that implements (or extends) AnInterface.
Suppose you have this situation:
public class AClass<X extends AnInterface>{
public AClass(X x){
...
}
public X getIt() {
...
}
}
The one who is creating the object will have an interface accordingly to it, in this situation it would be useful.
For instance:
// supposing DefaultAnInstance is an implementation of AnInstance interface
DefaultAnInterface obj = new DefaultAnInterface();
AClass<DefaultAnInterface> instance = new AClass<DefaultAnInterface>(obj);
...
// for the user getIt will return an objecct of type DefaultAnInterface
DefaultAnInterface obj = instance.getIt(); // there is no need to cast it to DefaultAnInterface
Why are you trying to extend an interface? Do you mean to implement it? I think the problem is that you are using a class where you should be using an interface. If you want to be able to pass in something of multiple classes, that is precisely what an interface is for.
Given your AClass, you may want it to be less general than your average generic - it can't handle any type, like a generic such as LinkedList can, but you want it to be able to handle a lot of classes.
For example, let's say you've got a class SelfSortingList, which is generic. All of its objects need to be comparable for it to be sortable. But you don't want to allow Widgets and Levers, which both implement Comparable, to be in the same list; that wouldn't make sense, and their particular implementations of Comparable probably reflect that.
So what you do is you say, "I want my SelfSortingList to be able to hold Objects of the same type, but they must be comparable." That's why you have both a type parameter (X) and a limitation on what X can be (extends Comparable) in the class header SelfSortingList.
There's no reason you couldn't. However, this would probably break the rest of your generic class:
public class AClass<X extends AnInterface> {
private X anInterface;
public AClass(AnInterface anInterface) {
// Not legal. You'd have to narrow cast to X
this.anInterface = anInterface;
}
}
So, you could always change the declaration of "anInterface" to AnInterface instead of X. However, generics are not giving you anything, since you're not referring to X anymore
public class AClass<X extends AnInterface> {
private AnInterface anInterface;
public AClass(AnInterface anInterface) {
// Not legal. You'd have to narrow cast to X
this.anInterface = anInterface;
}
}
Where's the use of X? You'd be inserting a generic parameter which isn't used.
Then there's the also the constructor typesafety issues some mentioned in another answer.
And these two constructors DO NOT MEAN THE SAME THING:
public AClass(AnInterface anInterface) { ... }
public AClass(X anInterface) { ... }
The first means you can have ANY class that is assignment compatible with AnInterface (ie. implements or extends it). The second means that you can have any class which is assignment compatible with the supplied generic parameter, which may be MORE SPECIFIC than just AnInterface. Someone used this example above:
public class Int1 implements AnInterface { ... }
public class Int2 implements AnInterface { ... }
public class Int3 extends Int1 { ... }
So if you have:
AClass<Int1> --> it could accept either Int1 or Int3, but not Int2 in the constructor
AClass<Int2> --> it could accept only Int2 in the constructor

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.

Is there a way to say "method returns this" in Java?

Is there a way to say "this method returns this" using Generics?
Of course, I want to override this method in subclasses, so the declaration should work well with #Override.
Here is an example:
class Base {
public Base copyTo (Base dest) {
... copy all fields to dest ...
return this;
}
}
class X extends Base {
#Override
public X copyTo (X dest) {
super.copyTo (dest);
... copy all fields to dest ...
return this;
}
}
public <T extends Base> T copyTo (Base dest) doesn't work at all: I get "Type mismatch: Can't convert from Base to T". If I force it with a cast, the override fails.
You can do something very clever (and akin to what they have done in Scala with the 2.8 collection framework). Declare some interface method that should return "itself" (Note: This is a type parameter, not a keyword!)
public interface Addable<T, This extends Addable<T, This>> {
public This add(T t);
}
Now declare a level of indirection - a "template" class
public interface ListTemplate<A, This extends ListTemplate<A, This>>
extends Addable<A, This>{
}
public interface List<A> extends ListTemplate<A, List<A>> {
}
Then an implementation of List has to return a List from the add method (I'll let you fill in the impl details)
public class ListImpl<A> implements List<A> {
public List<A> add(A a) {
return ...
}
}
Similarly you could have declard a SetTemplate and a Set to extend the Addable interface - the add method of which would have returned a Set. Cool, huh?
No, there's no way of expressing that. Just declare the method to return the type of the class. Java has covariant return types, so you can override a method to return a more specific type anyway.
If you wanted to have some marker for this, you could always introduce your own annotation - but don't expect any other tools to take any particular notice of it.
EDIT: the answer from oxbow_lakes does indeed give something which will work in most cases, but I believe there are ways of fooling it such that you're actually dealing with a different type. (From memories of experimentation, anyway.) Note that this is similar to how Java enums work.
using covariant types should be simple as:
abstract class Foo<T> {
Foo<T> get() {
return this.getClass().cast(this);
}
}
class Bar extends Foo {
#Override
Bar get() {
return (Bar) super.get();
}
}

Categories

Resources