Raw types and Generics -- Java [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
Java Generics — Assigning a list of subclass to a list of superclass
With raw types you can easily say something like this.
[...] // MyClass is generic with upper bound of Object
MyClass c = new MyClass<Double>();
[...]
But this isn't allowed
MyClass<Number> c = new MyClass<Double>()
I don't understand why this is. My book tells me why the second doesn't work, because you can't add a Integer to a MyClass<Double>. What it doesn't explains is why MyClass<Double> is a subclass of MyClass<Object> (or the equivalent raw type form), since double is subclass of object.
So why is the first allowed if the second form isn't. Please realize I am new to this.
Edit: Taking it a step further what would happen in the first example if Number was the upper bound?
You can see here the effects of type erasure
class Untitled {
public static void main(String[] args) {
}
public static<T> void c(T t)
{
t.SubClassMethod();// this won't work because class Object has no such method. But if I change the upperbound to SubClass it will.
t.toString() // this will because class Object has such a method
}
}
My point is that why should it matter what the Generic is declared as if it ultimately becomes treated as the upper bound anyway?

Try this:
MyClass<? extends Number> c = new MyClass<Double>();

The first thing to eliminate your confusion is to understand that the Raw Type is not part of the generics system at all. It is in no way equivalent to Something<Object>. Basically, the reason the Raw Type exists at all is just for backward compatibility. When Generics were introduced in Java 5, some existing classes and interfaces were retroactively made generic. In order for old code that didn't have generic declarations to compile in the Java 5 or later compiler, the Raw Declarations are legal.
Any comparison between the way the Raw Type behaves and the way the Parameterized type behaves is in a way a bit fundamentally spurious. The intent of the design is not that the Raw Type be considered an 'alternative' to declaring a parameter. New code that uses the Raw Type is incorrect code. It's legal to compile it so that old code still works.
My point is that why should it matter what the Generic is declared as
if it ultimately becomes treated as the upper bound anyway?
Because the entire point of the generics is to prevent ClassCastException. It will be treated as the actual declared type when someone, for example, someone takes the object back out of the list and assigns it to the specific type they're expecting. The compiler is making a promise that it guarantees this will succeed, so it has to restrict what goes in and out.

Suppose that MyClass is like this:
public class MyClass<T>{
T value;
public void foo(T arg){
value = arg;
}
}
and then those two other classes:
class A{ }
class B extends A { }
now imagine what happens if you do:
MyClass<A> container = new MyClass<B>();
container.foo(new A());
you'd try to put an A into a field of type B. The restriction you are facing is thought to prevent such things. C# has a nifty solution in terms of in and out parameters to generics...

Any MyClass<XXX> is a MyClass, but contrary to what you are saying, MyClass<Double> is not a subclass of MyClass<Object>.
You can find more about it if you search for erasure, like here.

Related

casting a Collection of derived Java interfaces (generics) [duplicate]

This question already has answers here:
Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?
(19 answers)
Closed 8 years ago.
Making a API for internal use, I need some Java abstraction and I don't know how to do it.
There is an Interface A with derived interfaces.
Let's say one of the extended interfaces of A is called B.
And let's say there is an class C implementing B.
I have a Factory/Pool class F from which I want to get a list of instances (or set or similar collection).
What I want is basically this:
List<B> instances = F.getAllSuitableInstances(parameters);
Get me all the instances specified by my parameters as a collection of B.
First attempt was with this function signature
public List<A> getAllSuitableInstances(parameters);
but when I try to cast the resulting List to a List for use, I
get told "incompatible types" - even though B is derived from A.
So I tried what the java libraries do:
public <T> List<T> getAllSuitableInstances(parameters, T);
and try calling that with B as second parameter. But that doesn't work
either, since T has to be supplied as an instance for some reason, and
interfaces cannot have instances.
I know I could use <?> with casting but I'd like to make this as typesafe as possible.
So, what is the (best) way to get this done?
even though B is derived from A.
You have to be careful here -- Java's generics are invariant, meaning that Something<Superclass> is not a superclass of Something<Subclass> (e.g. List<Number> is not a superclass of List<Integer>). There are plenty of questions on SO about this, so I won't repeat information that other people can explain much more effectively, like here and here.
As for your second signature, it seems to me that the T in (parameters, T) is unnecessary.
public <T> List<T> getAllSuitableInstance(parameters);
should work, unless I'm misunderstanding your requirements. The disadvantage of this is that T could be anything, so you're somewhat limited in the methods you can invoke on objects of type T, but if you aren't doing that then no concern is warranted.
If the methods in your interfaces are necessary to get your method working (doesn't seem like it, but just in case), you can always add bounds (e.g. public <T extends A> List<T>...) to your generic type, so the compiler knows that all instances of T inside your method are type A or subtypes of A.
If you need to use the type of T in your method (say for instanceof checks), one option is passing in a Class object and using its methods to perform the runtime equivalent of instanceof checks and casting (among other options):
public <T> List<T> getAllSuitableInstance(parameters, Class<? extends T> clazz); // Might be able to use just Class<T> too
Hopefully that helps. Let me know if I got something wrong about what you needed.
This is a common misunderstanding when it comes to programming with generics, but it is an important concept to learn
when we have two concrete types A and B (for example, Number and Integer), MyClass<A> has no relationship to MyClass<B>, regardless of whether or not A and B are related.
The common parent of MyClass<A> and MyClass<B> is Object.
No need to even pass the class as you mentioned in second option
this should work for you
public <T> List<T> getAllSuitableInstances(parameters) {
List<T> list = new ArrayList<>();
//content add to list
return list;
}

Why can't diamond infer types on anonymous inner classes?

In Java 7 and later, diamond can be used to infer types on normally like so without an issue:
List<String> list = new ArrayList<>();
However, it can't for anonymous inner classes like this:
List<String> st = new List<>() { //Doesn't compile
//Implementation here
}
Why is this? Logically in this scenario, I can definitely infer the type as String. Is there a logical reason for this decision where the type cannot actually be inferred on anonymous inner classes, or was it omitted for other reasons?
In the JSR-334:
Using diamond with anonymous inner classes is not supported since
doing so in general would require extensions to the class file
signature attribute to represent non-denotable types, a de facto JVM
change.
What I guess is that as everybody knows, anonymous class leads to a generation of its own class file.
I imagine that generic type doesn't exist within these files and rather replaced by the effective (static) type (thus declared by the explicit type like <String> at declaration object time).
Indeed, file corresponding to an inner class is never shared across multiple different instantiations of it, so why bother with generics into it?! :).
It would be more hardly achievable (and surely useless) for compiler to force an extension (by adding a special attribute for generics) to theses kind of class files.
google yields, after skipping posts from stackoverflow, http://mail.openjdk.java.net/pipermail/coin-dev/2011-June/003283.html
I'm guessing it's like this, usually an anonymous class is a concrete subclass of the apparent type
interface Foo<N extends Number>
{
void foo(N n);
}
Foo<Integer> foo = new Foo<Integer>(){ ... }
is implemented by
class AnonFoo_1 implements Foo<Integer>{ ... }
Foo<Integer> foo = new AnonFoo_1();
Suppose we allow diamond inference on anonymous classes, there can be complicated case like
Foo<? extends Runnable> foo = new Foo<>(){ ... }
The inference rules yield N=Number&Runnable; following the prev implementation trick, we need
class AnonFoo_2 implements Foo<Number&Runnable>{ ... }
That is currently not allowed; the type arg to super type Foo must be a "normal" type.
However, the rationale is not very strong. We can invent other implementation tricks to make it work
class AnonFoo<N extends Number&Runnable> implements Foo<N>
{
#Override public void foo(N n)
{
n.intValue();
n.run();
}
}
Foo<? extends Runnable> foo = new AnonFoo<>();
the compiler ought to be able to do the same trick.
In any case, at least the compiler should allow the majority of use cases that do not involve "undenotable types", like Foo<Integer> foo = new Foo<>(){...} It's a pity that these common/simple cases are unnecessarily forbidden too.
In short, the <> does little to infer types, it turns off the warning you would get without it.
EDIT: As #Natix points out it does some checking.
List<Integer> ints = new ArrayList<>();
List<String> copy = new ArrayList<>(ints);
produces a compilation error
Error:Error:line (42)error: incompatible types
required: List<String>
found: ArrayList<Integer>
As you can see the <> is taking the type of the argument, not inferring the type from the type of copy

Calls to next() on abstract class that implements Iterator<E> returns Object instead of E

I have a class with the following definition:
public abstract class A<T> implements Iterator<B> {}
The following call to next() will return an Object rather than a B:
A a = new SomethingThatExtendsA();
B b = a.next();
I've searched for quite awhile and haven't been able to figure out why this next() call fails to compile. Is anyone able to describe this behavior for me?
Edited original to be templated, as this seems to matter.
Edit for additional clarification: This is a compile-time issue, not a runtime issue. The implementation of SomethingThatExtendsA(); should be irrelevant in this case at compile-time.
So we have this code:
public abstract class A<T> implements Iterator<B> {}
[...]
A a = new SomethingThatExtendsA();
a.next();
A is a generic type, but you have defined a with a raw type. Ignore the right hand side of the =, we are only interested in the static type:
A/*<Something>*/ a = ...;
The compiler should give you warnings here. (At least relatively recent versions of javac will do - rawtypes warning in Oracle javac.) Take notice of your compiler's warnings. (Wasn't it nice when javac didn't give warnings?)
So now we are in a situation that a has a type that is both raw and is a Iterator<B>. This is a really confusing situation with just mind-blowingly difficult implications. We shouldn't even be doing this - we should be avoiding mixing generic and raw types. So the Java Language Specification takes the simple way out and discards the partial generic type information.
So, don't mix raw and generic types. Just use all generics and you should be fine.
public abstract class A implements Iterator<B> {}
class B {}
class SomethingThatExtendsA extends A {
// implement A methods
}
A a = new SomethingThatExtendsA();
a.next();
This code is pretty correct and returns B object. Probably you missed something in SomethingThatExtendsA class.
Test it by calling:
B b1 = new Object(); // compilation error
B b2 = a.next(); // all is OK
UPDATE:
Change signature in SomethingThatExtendsA from
public Object next() { } to public B next() {}
The SomethingThatExtendsA class is a red herring here. You get the same problem with
List<String> list = new ArrayList<String>();
list.add("foo");
Iterator iterator = list.iterator(); // you should get a warning on this line...
String foo = iterator.next(); // ... and a compile error on this line
The issue is that raw types are a horrible ugly hack for backwards compatibility only which cause all the generics around them to stop working. Specifically, Iterator is not the same type as Iterator<String>, Iterator<Object>, or even Iterator<?>. Instead, Iterator means "the Iterator class I would have got if I had compiled with a pre-generics version of Java". Since the pre-generics version of Iterator always returned Object, then that's what you get. And you can't assign a value of type Object to a more specific type (like String, or your type B) without a cast.
The Java Language Specification says this:
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

Can we create an Array of Generic class? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java how to: Generic Array creation
I want to create a Stack which contains 10 elements, I'm trying to do this with Generics.
I started by creating a Stack class of Type T, but I'm getting compilation error when I try to instantiate the array of generic type.
public class Stack<T>{
private T[] stk = new T[10];
}
What I'm doing wrong here?
You can't do this. Not without using some hacky round about code, and even then you have to do an unsafe cast in the end that completely ruins the entire reason for trying to be type safe in the first place.
This is because Java has something called type erasure, the compiler throws away all the generic information and the runtime doesn't know what T is.
Here is the preferred way of doing this:
#SuppressWarnings("unchecked")
static <T> T[] newArray(Class<T> type, int length)
{
return (T[]) java.lang.reflect.Array.newInstance(type, length);
}
This doesn't create the throw about list instance in the naive solution of calling toArray() on a List<T> implementation hack.
For more discussion on this see
Here is an answer to a similar question about creating a type safe array at runtime.
There reason you can't create a Array of a generic type is this:
When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.
For instance, Box is translated to type Box, which is called the raw type — a raw type is a generic class or interface name without any type arguments. This means that you can't find out what type of Object a generic class is using at runtime. The following operations are not possible:
public class MyClass<E> {
public static void myMethod(Object item) {
if (item instanceof E) { //Compiler error
...
}
E item2 = new E(); //Compiler error
E[] iArray = new E[10]; //Compiler error
E obj = (E)new Object(); //Unchecked cast warning
}
}
http://download.oracle.com/javase/tutorial/java/generics/erasure.html
The reason to use generics is that you don't want to typecast.
That said, here are two solutions.
You can use a array of Objects and garantee you'll only push and pop T's by the methods you supply to access the array:
public class MyStack2<T> {
Object[] myStack2;
public MyStack2() {
myStack2 = new Object[10];
}
public void push(T t) {
// do whatever you wanna do to push t, like myStack2[x] = t;
}
public T pop() {
// do whatever you wanna do to pop t like return (T)myStack2[0];
// Here we typecasted, but we can be sure that myStack2 contains only T's
// because we garanteed it at the push method.
}
}
OR
You can use another thing other than array to store your stack.
public class MyStack<T> {
Stack<T> myStack;
public MyStack() {
myStack = new Stack<T>();
}
public void push(T t) {
myStack.push(t);
}
public T pop() {
return myStack.pop();
}
}
As you can see, java already provides a Stack class so you don't have to write one, but if you really want to do it, maybe to understand how it works, you can replace the Stack class in this example by a List. With a List you'll be able to play almost the same you'd do if you were using an array.
The reason that that doesn't work is that when you write a type like String[] in Java, that means that the object knows itself at runtime that its component type is String (or a subclass thereof). Generic type parameters are not available at runtime, hence you cannot do it. We wish there was something like Object[]<T>, i.e. "an array that does not know its component type at runtime, but which has generic type checks at compile time", but such a thing does not exist in the language.
However, it appears that from your code that you intend to use this array internally, and you don't really care if the array knows T at runtime; you just need an array, period. If you don't intend to pass the array out of the class, then there are two options:
Use a variable of type Object[], and create new Object[10]. This requires you to cast to T if you want to return an element from a method, which is an unchecked cast.
Use a variable of type T[], and assign to it using = (T[])new Object[10]. Now people will point out that the subtyping relationship is not technically true, but so long as it's inside the class (inside the scope of T), it doesn't matter, because T is erased. So with this method you have to be extra careful never to pass or return the array reference, because you won't be warned that it's unsafe.
Both methods are the same after type erasure, and both methods will cause unchecked cast warnings, so it's really your personal preference. The second one is more convenient (you can pretend it's a T[] and get things out of it without cast), while the first one is more formally correct and safer (the second requires you to be diligent not to pass it out).

Calling ambiguously overloaded constructor in Java

I just saw this C# question and wondered, if something similar could happen in Java. It can, with
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
the call
new A<Integer>(43);
is ambiguous and I see no way how to resolve it. Is there any?
You can drop the generics during construction (and suppress a warning):
A<Integer> a = new A(42);
or, less preferably use reflection (where again you'd have to suppress warnings)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
Yes, members of a parameterized type JLS3#4.5.2 can end up in conflicts that are precluded in a normal class declaration(#8.4.8). It's pretty easy to come up with many examples of this kind.
And in Java, neither constructor in your example is more specific than the other, because there is no subtyping relation between T and Integer. see also Reference is ambiguous with generics
If method overloading creates this kind of ambiguity, we can usually choose to use distinct method names. But constructors cannot be renamed.
More sophistries:
If <T extends Integer>, then indeed T is a subtype of Integer, then the 2nd constructor is more specific than the 1st one, and the 2nd one would be chosen.
Actually javac wouldn't allow these two constructors to co-exist. There is nothing in the current Java language specification that forbids them, but a limitation in the bytecode forces javac to forbid them. see Type Erasure and Overloading in Java: Why does this work?
Another point: If <T extends Integer>, since Integer is final, T can only be Integer, so Integer must also be a subtype of T, therefore isn't the 2nd constructor also more specific than the 1st?
No. final isn't considered in subtyping relations. It is actually possible to drop final from Integer one day, and Java even specifies that removing final does not break binary compatibility.
Indeed, it is ambiguous, and so doesn't compile if you try new A<Integer>(new Integer(0)).

Categories