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

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

Related

How to set type parameter of interface's implementing class?

I want to know if is it possible to set a paramenter's type that is the type of the class that implements a given interface. Seeing some code the question will become more clear:
interface A {
A sum (???? another);
}
class AClass implements A {
private int internalStuff;
A public sum (???? another) {
// I want to access another.internalStuff in a type safe fashion
}
}
Of course I can substitute ???? with A type, and inside AClass.sum, cast it to AClass but that is ugly. Can "????" be replaced with some meaningful type declaration?
There is no self-type in Java, so you have to do a little trick to achieve this.
You can add a type parameter with a recursive type bound to the interface. The implementing class sets this parameter to its own type. Like this:
interface A<T extends A<T>> {
A sum (T another);
}
class AClass implements A<AClass> {
private int internalStuff;
public A sum(AClass another) {
// ....
}
}
There is nothing stopping AClass from doing implements A<SomeOtherAClass> though. You have to trust the implementing class to provide the correct type parameter.

Java generics seem to work differently for classes than for methods

I'm following this:
http://rickyclarkson.blogspot.com/2006/07/duck-typing-in-java-and-no-reflection.html
And I'm trying to adapt this:
<T extends CanQuack & CanWalk> void doDucklikeThings(T t)
{
t.quack();
t.walk();
}
To this:
public class Activate<D extends CanQuack & CanWalk> {
D d = new MyWaterFowl(); //Type mismatch
}
Even though MyWaterFowl implements those interfaces.
I'd like a solution that never mentions MyWaterFowl in the <>'s since I'm going to eventually just be injecting it (or anything else that implements those interfaces).
If your answer is basically "You can't do that, what type would it even be?". Please explain why it's working for the method doDucklikeThings and conclusively state if it is impossible to do the same with a class or, if it is possible, how to do it.
The T in doDucklikeThings must be something valid since it's working. If I passed that into a class what would I be passing in?
As requested here's the MyWaterFowl code:
package singleResponsibilityPrinciple;
interface CanWalk { public void walk(); }
interface CanQuack { public void quack(); }
interface CanSwim { public void swim(); }
public class MyWaterFowl implements CanWalk, CanQuack, CanSwim {
public void walk() { System.out.println("I'm walkin` here!"); }
public void quack() { System.out.println("Quack!"); }
public void swim() { System.out.println("Stroke! Stroke! Stroke!"); }
}
Remember I've confirmed that doDucklikeThings works. I need the syntax that will let me inject anything that implements the required interfaces.
This does not work, because the class/method is generic and the caller of your class/method can set D to MyAmericanEagle.
Activate<MyAmericanEagle> active = new Activate<>();
Then your code would result in
MyAmericanEagle d = new MyWaterFowl();
Since that makes no sense (would result in ClassCastException) the compiler rejects it.
// Type mismatch
Even though MyWaterFowl implements those interfaces.
It's not about the type D implementing those interfaces (and/or extending a class). A generic type variable is bound to a specific type argument. That type might be completely different than MyWaterFowl so you cannot use them interchangeably.
To answer your edit, you are doing two completely different things in your two snippets. The type variable is declared with some bounds. It is therefore guaranteed to be a type that implements some interface (or extends some class), but you don't know which type that is, in either case.
I want to clarify the two things you did, ie. what you expect in your question and the solution you gave in your answer.
Generics are a compile time feature where the server code, for example
class Activate<D extends CanWalk & CanQuack> {
D instance;
public Activate(D d) {
this.instance = d;
}
public D getInstance() {
return instance ;
}
}
declares a type variable. This is a variable. Within its declaration context, you don't know its exact type at compile time.
The client code, for example,
new Activate<>(new MyWaterFowl());
binds the type MyWaterFowl to the type variable declared in Activate. So the client code knows what D is at compile time.
If the following
public D getInstance() {
D someRef = new MyWaterFowl();
return someRef;
}
was allowed in the server code, this would fail
Activate<SomeOtherBird> activate = new Activate<>(new SomeOtherBird());
SomeOtherBird reference = activate.getInstance();
Generics guarantee that getInstance() is type safe because it is declared as returning whatever type is bound to the type variable D. In this case, that is SomeOtherBird. If the getInstance() code above was allowed, type safety would be broken as getInstance() would return something other than what was bound to it.
This doesn't change the fact that within your server code (the generic class), you do know the bounds of D, ie. it is both a CanQuack and a CanWalk. Therefore, anything an object of those types can do, so can an object referenced by a D variable do.
It actually can be done.
The generic code between <>'s is fine. It's not different for methods and classes. Just needed to finish doing the dependency injection:
public class Activate<D extends CanQuack & CanWalk> {
private D d;
Activate(D d) {
this.d = d;
}
void doDuckLikeThings() {
d.quack();
d.walk();
//d.swim(); //Doesn't work
//And shouldn't since that was the whole point of ISP.
}
}
public class MainClass {
public static void main(String[] args) {
Activate<MyWaterFowl> a = new Activate<>(new MyWaterFowl());
a.doDuckLikeThings();
}
}
Thought I'd provide an answer that says what to do to fix it.
Type of class which extends Object is different with type of Object. This means you cannot instantiate super class for its extenders.
When you compile this:
1 public class Sample<T extends Object> {
2 public Sample() {
3 T t = new Object();
4 }
5 }
you got incompatible types error.
Sample.java:3: error: incompatible types
T t = new Object();
^
required: T
found: Object
where T is a type-variable:
T extends Object declared in class Sample
1 error
Its same as when you do it in non generic form:
1 public class Sample{
2 public Sample() {
3 }
4 }
5
6 class SampleExtends extends Sample {
7 public SampleExtends() {
8
9 }
10 }
11
12 class User {
13 public User() {
14 SampleExtends se = new Sample();
15 }
16 }
you get this error from compiler: incompatible types
Sample.java:14: error: incompatible types
SampleExtends se = new Sample();
^
required: SampleExtends
found: Sample
1 error
What do you expect the actual type of D to be in the second code snippet?
Let's say something does this:
Activate<Daffy> myActivate = Activate<Daffy>();
What should happen then? This means D needs to be of type Daffy but you are trying to set d to an instance of MyWaterFowl.
Generics works just the same for classes as for methods.
You seem to misunderstand Generics a bit. A type parameter <T extends CanQuack & CanWalk> is not a definition of a new type alias valid for the scope of method or class, it is a placeholder for some type, which is later filled by someone else.
For a generic method like your example
<T extends CanQuack & CanWalk> void doDucklikeThings(T t)
{
t.quack();
t.walk();
}
the caller of the method decides which type to substitute for T (within the limits stated by the bounds).
So one can use
doDuckLikeThings(myWaterfowl);
and the compiler guesses what type parameter you want here (likely the type of the myWaterfowl variable).
For a generic class, it is the code which creates an instance of the class who decides the actual type parameter.
So I can say
Activate<Duck> duckActivator = new Activate<Duck>();
After this, the duckActivator instance is an instance of Activate<Duck>, and inside it, D is now bound to Duck.
Now obviously your variable declaration says
Duck d = new MyWaterfowl();
and this doesn't work.
It wouldn't work in a generic method, either – this one is invalid just as well:
<T extends CanQuack & CanWalk> void doDucklikeThings()
{
T t = new MyWaterfowl();
}
I'd like a solution that never mentions MyWaterFowl in the <>'s since I'm going to eventually
just be injecting it (or anything else that implements those interfaces).
Then don't mention its constructor either.
Whoever is injecting your duck like object also has to decide the actual type parameter – i.e. this should be the one who creates the Activate instance. And this can't change after construction of your Activate object.
A candidate solution to the actual problem
If this restriction doesn't fit for you (e.g. because the same instance of Activate will need to be able to work with different types of duck like objects one after another), maybe a type parameter is not for you.
Maybe a generic wrapper with a wildcard type parameter for a variable helps instead.
Take this generic wrapper (or something similar):
public class Holder<T> {
private final T t;
public T get() { return t; }
public Holder(T t) { this.t = t; }
}
Then your Activate class doesn't need the type parameter, but just holds a holder variable with a wildcard type parameter. (Note that the actual Holder instantiation has a non-wildcard type argument.)
public class Activate {
private Holder<? extends CanQuack & CanWalk> holder;
public <D extends CanQuack & CanWalk> void setDuckLike(D d) {
this.holder = new Holder<D>(d);
}
public Activate() {}
public void doDucklikeThings() {
holder.get().quack();
holder.get().walk();
}
}
Now you do something like this:
Activate a = new Activate();
a.setDuckLike(new Duck());
a.doDucklikeThings();
a.setDuckLike(new MyWaterfowl());
a.doDucklikeThings();

what could this generic class declaration could mean?

I know this isn't a good question to ask and I might get cursed to ask it but I cannot find any place to get help on this question
Below is a Generic class that appeared in my interview question (which I have already failed). The question was to tell what this Class declaration is doing and in what circumstances this could be used for ?
I have very limited understanding of Generic programming but I understand that 'T' is Type and 'extends' here means that the Type should have inherited 'SimpleGenericClass' but I do not understand the '?' at the end and in what circumstances this Class could be potentially used for
public abstract class SimpleGenericClass<T extends SimpleGenericClass<?>> {
}
First, because the class SimpleGenericClass is abstract, it is meant to be subclassed.
Second, it is a generic class which means that inside the class somewhere you will almost assuredly be using the generic parameter T as the type of a field.
public abstract class SimpleGenericClass<T...> {
T x;
}
Now the first interesting thing here is that T is bounded. Because it is declared as T extends SimpleGenericClass<?> it can only be SimpleGenericClass<?> or some subclass of SimpleGenericClass<?>. You also asked about thr ?. That's known as a wildcard and there is a pretty good explanation of it at the Java Tutorial on Wildcards. In your case we would say this is a "SimpleGenericClass of unknown." It is needed in Java because SimpleGenericClass<Object> is NOT the superclass of SimpleGenericClass<String>, for example.
The second interesting thing though is that since T is a SimpleGenericClass of some sort, your class is more than likely defining recursive structures. What comes to my mind are trees (think of expression trees) where SimpleGenericClass is the (abstract) node type, designed to be subclassed with all kinds of specialized node types.
UPDATE This SO question on self-bounded generics might be helpful to you.
UPDATE 2
I went ahead and put together some code that illustrates how this can be used. The app doesn't do anything but it does compile and it shows you how the generic bounds can supply some possibly-meaningful constraints.
public abstract class Node<T extends Node<?>> {
public abstract T[] getChildren();
}
class NumberNode extends Node {
int data;
public Node[] getChildren() {return new Node[]{};}
}
class IdentifierNode extends Node {
int data;
public Node[] getChildren() {return new Node[]{};}
}
class PlusNode extends Node {
NumberNode left;
NumberNode right;
public NumberNode[] getChildren() {return new NumberNode[]{};}
}
The nice thing here is that NumberNode[] is a valid return type for PlusNode.getChildren! Does that matter in practice? No idea, but it is pretty cool. :)
It's not the greatest example, but the question was rather open ended ("what might such a thing be used for?"). There are other ways to define trees, of course.
This really only means that you allow the user of class SimpleGenericClass to parametrize instances of the class with the type T. However, T cannot be any type, but must be a subtype of SampleGenericClass (or SampleGenericClass itself).
In the remainder of the code of class SimpleGenericClass you may use type T in method signatures.
Let's assume for a second that SimpleGenericClass is not abstract. When using it, you could then write:
new SimpleGenericClass<SampleGenericClass<String>>();
I.e. you parametrize SimpleGenericClass with SampleGenericClass and SampleGenericClass with String.
This basically sais: in this class you have a Type placeholder called T, and a restriction on that placeholder, it must be of type SimpleGenericClass or something that extends it. Once you obey that rule you can create instances of your class and give an actual type to T, that later on can be used in methods of that class, something like this:
public class C <T extends Number>{
public void doSomething(T t) {
}
public static void main(String... args) {
//works:
C<Number> c = new C<Number>();
c.doSomething(new Number() {
//Aonimous implementation of number
});
//won't work
//C<Object> c = new C<Object>();
C<Integer> c2 = new C<Integer>();
c2.doSomething(new Integer(1));
//won't work
//c2.doSomething(new Number() {
//Aonimous implementation of number
//});
}
}
The SimpleGenericClass<?> is pretty redundant at this point. If another generic type is needed on this class, you can have more than one (SimpleGenericClass<T extends SimpleGenericClass, T2 extends Whatever>)
By definition it says that the SimpleGenericClass can work on a type <T> which is subclass of SimpleGenericClass.
So I assume there will be some operations which will work on <T>.
Now to see why one would define a template like this - (not much I can think of , really ) may be a scenario where the SimpleGenericClass is an abstract class (just realized it is as per OP :P) and expects that it can work on any concrete classes ?
Guys what do you think ?
I guess you have got the question in this form (T instead of ?):
public abstract class SimpleGenericClass<T extends SimpleGenericClass<T>>
Take a look at this code:
abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>
{
/** subclasses are forced to return themselves from this method */
public abstract SubClassOfFoo subclassAwareDeepCopy();
}
class Bar extends Foo<Bar> {
public Bar subclassAwareDeepCopy() {
Bar b = new Bar();
// ...
return b;
}
}
Bar b = new Bar();
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();
Bar b3 = f.subclassAwareDeepCopy(); // no need to cast, return type is Bar
The trick going on with Foo<SubClassOfFoo extends Foo<SubClassOfFoo>> is:
Any subclass of Foo must supply a type argument to Foo.
That type argument must actually be a subclass of Foo.
Subclasses of Foo (like Bar) follow the idiom that the type
argument they supply to Foo is themselves.
Foo has a method that returns SubClassOfFoo. Combined
with the above idiom, this allows Foo to formulate a contract that
says “any subclass of me must implement subclassAwareDeepCopy() and
they must declare that it returns that actual subclass“.
To say that another way: this idiom allows a superclass (such as an Abstract Factory) to define methods whose argument types and return types are in terms of the subclass type, not the superclass type.
The trick is done for example in Enum JDK class:
public abstract class Enum<E extends Enum<E>>
Refer here for more details.

Java - Overriding return type of extended interface when return type uses generics for own method parameter types

i've stumbled upon a curiosity in the java inheritance, and I wanted you to ask for better ideas on that:
Assume two interfaces A and A1
Interface A1 extends A
Interface A has a method which returns a generic type.
The generic type would be like GenericType<T>.
A basic idea is now to change this generic return type from
GenericType<Object> in Interface A into
GenericType<String> in Interface A1
Well seems to be easy at first (bad things will come later on)
We declare Interface A like
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
and Interface A1 like
public interface InterfaceA1 extends InterfaceA
{
#Override
public GenericType<String> getAGenericType();
}
As you see we are forced to write GenericType<? extends Object> in Interface A itself to allow overriding it with generic based "subclasses".
(In fact the generic parameter of the generictype is subclassed not the generic type itself)
Now assume the GenericType has its own method looking like:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Now trying to instantiate A1 works great.
Rather trying to instantiate A will suck. To see why look at this "use the interface" class:
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<? extends Object> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith( something );
}
}
You ask: "And now?"
It does not work on the last lines. In fact the parameter "something" is not even from type "Object" it is from Type "? extends Object". So you cannot pass the declared "Object" type. You can't pass anything at all.
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
Do you have ideas how to model such a use case, where the subclasses will have to override the return type, while the return type is a generics?
Or how would you go around such a model case?
Or am I just missing a simple point in the generic declaration and my example is possible this way?
----------- (1) edit due to answers -----------
A very good basic idea is making the interface A more abstract! I had exactly the same idea first, but... (this has to come)
Assume doing this:
We introduce a new interface AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Now we will have to extend A and A1 from this new interface:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
That works fine, althought it breaks the path of the original inheritance.
If we want A1 still be extendable from A, we have to change A1 to
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
and there a problem is again. This does not work, since we extend indirectly the same interface with different generic types. This is unfortunately not allowed.
You see the problem?
-
And to point to another circumstance:
If you cast the GenericType<? extends Object> to GenericType<Object> it obviously works.
Example:
public class LookAtTheInstance
{
public static void main( String[] args )
{
InterfaceA a = new InterfaceA()
{
#Override
public GenericType<? extends Object> getAGenericType()
{
return new GenericType<Object>()
{
#Override
public void doSomethingWith( Object something )
{
System.out.println( something );
}
};
}
};
;
#SuppressWarnings("unchecked")
GenericType<Object> aGenericType2 = (GenericType<Object>) a.getAGenericType();
Object something = "test";
aGenericType2.doSomethingWith( something );
}
}
So it seems for me that the resolving of the parameter type of the method
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
is wrong.
If D is unified with "? extends Object" why the parameter type is not forced to be "Object"?
Wouldnt this make more sence?
A basic idea is now to change this generic return type from GenericType in Interface A into GenericType in Interface A1
This is not possible, because Java Generics are invariant. [1]
As you found out, you cannot have an interface declaring a method that returns GenericType<Object> and in a sub interface override the method to return GenericType<String>: The latter return type is not a subtype of the former. And for good reason!
You tried to
extend indirectly the same interface with different generic types. This is unfortunately not allowed.
There is no way this could possibly work: E.g. what should be the type of E in public E set(int index, E element) in a class that implemented both List<String> and List<Object>? Your subclassed interface would have to produce a similar hybrid: The return value of getAGenericType in the sub interface would have to implement both the GenericType<String> and the GenericType<Object> interface. And as we saw, this is impossible.
The compiler does not know what you are going to do with the type parameter in GenericType (although it theoretically could find out, it doesn't). If you had a variable of type GenericType<String> and assigned a GenericType<Object> to it, you may very well end up putting a Long instance where a String is expected, and get a ClassCastException where you won't expect one.
In the doSomethingWith method of your variable GenericType<? extends Object> aGenericType2 you can pass one thing: null. null is the only object reference that has a subtype of ? extends Object. The lower bound type of ? extends Object is the null type, which cannot be expressed in Java, and only implicitly exists as the type of the null reference.
[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java
I don't know if this is what you are expecting, but you can declare your interface something like:
public interface Interface <K extends Object> { ... }
While your class might look like:
public class InterfaceImpl implements Interface<String> { ... }
#Override annotation:
When overriding a method, you might
want to use the #Override annotation
that instructs the compiler that you
intend to override a method in the
superclass. If, for some reason, the
compiler detects that the method does
not exist in one of the superclasses,
it will generate an error.
With this annotation you cannot change return type of function.
If you want to override return type, just make interface A more abstract, add generic to this interface:
public interface InterfaceA<T> {
public GenericType<T> getAGenericType();
}
Sample about overriding a generic method in a generic class.
The trouble is that InterfaceA doesn't know what type it's holding. If you get InterfaceA to take a generic argument then you could do this:
public interface InterfaceA<T>
{
public GenericType<T> getAGenericType();
}
public interface InterfaceA1 extends InterfaceA<String>
{
#Override
public GenericType<String> getAGenericType();
}
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA<String> a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<String> aGenericType2 = a.getAGenericType();
String something = null;
aGenericType2.doSomethingWith( something );
}
}
I'm several years late to the party, but I found this page while searching for a related question and none of the answers really hit on the central issue, which I think is worth clarifying. Let's look at a slightly-more-fleshed-out example:
interface GenericType<D> {
D getAValue();
void doSomethingWith(D value);
}
class StringType implements GenericType<String> {
#Override
public String getAValue() {
return "Hello World";
}
#Override
public void doSomethingWith(final String value) {
System.out.println(value.length());
}
}
interface InterfaceA {
GenericType<? extends Object> getAGenericType();
}
interface InterfaceA1 extends InterfaceA {
#Override
GenericType<String> getAGenericType();
}
class AnActualA1 implements InterfaceA1 {
#Override
public GenericType<String> getAGenericType() {
return new StringType();
}
}
class LookAtTheInstance {
public static void method() {
InterfaceA1 a1 = new AnActualA1();
// 'g1' is a StringType, which implements GenericType<String>; yay!
GenericType<String> g1 = a1.getAGenericType();
// Everything here is fine.
String value = g1.getAValue();
g1.doSomethingWith("Hello World");
// But if we upcast to InterfaceA???
InterfaceA a = (InterfaceA) a1;
// Note: a.getAGenericType() still returns a new StringType instance,
// which is-a GenericType<? extends Object>.
GenricType<? extends Object> g = a.getAGenericType();
// StringType.getAValue() returns a String, which is-an Object; yay!
Object object = g.getAValue();
// StringType.doSomethingWith() method requires a String as the parameter,
// so it is ILLEGAL for us to pass it anything that cannot be cast to a
// String. Java (correctly) prevents you from doing so.
g.doSomethingWith(new Object()); // Compiler error!
}
}
Conceptually, GenericType is NOT a GenericType, since a GenericType can only doSomethingWith() Strings, while a GenericType needs to be able to doSomethingWith() any object. GenericType is a compromise which the compiler allows you to use as a "base class" for any GenericType where D is-an Object, but only allows you to use a reference of that type to call methods that are type-safe for any possible runtime value of '?' (such as getAValue(), whose return value can always be safely cast to an Object since D is-an Object regardless of runtime type).
It's hard to tell what (if anything) the original poster was actually trying to model with this code, and in particular how much of the generic-ness of GenericType was really needed, but perhaps the inheritance should have gone the other way around?
/**
* I can do something with instances of one particular type and one particular
* type only.
*/
interface GenericType<D> {
void doSomethingWith(D value);
}
/**
* I can do something with instances of any type: I am-a GenericType<String>
* because I can totally do something with a String (or any other kind of
* Object).
*/
interface NonGenericType extends GenericType<Object>, GenericType<String> {
#Override
void doSomethingWith(Object value);
}
interface StringHandlerFactory { // nee InterfaceA1
GenericType<String> getAGenericType();
}
/**
* I extend StringHandlerFactory by returning a NonGenericType (which is-a
* GenericType<String>, satisfying the interface contract, but also so much
* more).
*/
interface ObjectHandlerFactory extends StringHandlerFactory { // nee InterfaceA
#Override
NonGenericType getAGenericType();
}
The downside being that there's no good way to express to the java compiler that NonGenericType extends GenericType, even though conceptually it could in this case, since GenericType never uses D as a return value. You have to manually specify each GenericType that you want it to extend. :(
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
I think that the purpose of InterfaceA is not to be instantiated at all, because one of its dependable classes are generic. That's what you meant declaring:
public GenericType<? extends Object> getAGenericType()

Java Generics Class Parameter Type Inference

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.

Categories

Resources