1

I am trying to understand the features of a generic class and its concrete instances, and also the features of a generic collection.

suppose I define a generic class: Stack<T> now I'm trying to use it this way:

Stack<String> ts = new Stack<>(5);
Stack<Object> to = new Stack<>(5);
to = ts // compilation error!

so obviously Stack<String> is not a Stack<Object>.

I got confused when I defined a generic Collection:

Set<E> elemnts = new Hashset<>();

and noticed that I can use elements.toString()! this means that Set<E> elemnts extends Object! so whats really going on here?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
netalie
  • 95
  • 6
  • 2
    Both of your conclusions are correct and don't contradict each other. What are you actually asking? – Eran Jul 11 '15 at 13:52
  • In Java, generics are invariant. – Kachna Jul 11 '15 at 14:01
  • im trying to understand the is-a relationship of generic classes to the Class Object. I was told that this relation dose not work in this case and I want to know what are the implications. – netalie Jul 11 '15 at 14:01
  • see this link : http://stackoverflow.com/questions/8481301/covariance-invariance-and-contravariance-explained-in-plain-english?lq=1 – Kachna Jul 11 '15 at 14:09

4 Answers4

2

The compilation error doesn't mean that String isn't an Object, which isn't true. E.g., the following code works just fine:

String s = "I am String!";
Object o = s;

What the error means is that Stack<String> isn't a Stack<Object>. For example, you could call push(new Object()) on a Stack<Object>, but obviously not on a Stack<String>.

Mureinik
  • 297,002
  • 52
  • 306
  • 350
1

For the following:

Stack<String> ts = new Stack<>(5);
Stack<Object> to = new Stack<>(5);
to = ts // compilation error!

Yes, this compilation fails, because generics are essentially a feature of the compiler enforcing type safety. Their is actually only one Stack class as far as the virtual machine is concerned.

This statement:

Set<E> elemnts = new Hashset<>();

Is equivalent to:

Set<E> elemnts = new Hashset<E>();

The notation was introduced in Java 7 and is sometimes called the 'diamond operator' because of the <>. It is just to remove redundancy.

It is the Set class that is extending Object, just like all classes in Java extend object.

The following holds true for the Class object in your code:

 boolean b = ts.getClass() == to.getClass();  // b is true
yas
  • 3,520
  • 4
  • 25
  • 38
1

String class is implicitly subclass of Object. Since Object class is super class of all the classes in java. Therefore below statement is valid

String x="hello";
Object o= x;

But Stack<String> is not a sub class of Stack<Object>. Therefore code gives compile time error.

Stack<String> ts = new Stack<>(5);
Stack<Object> to = new Stack<>(5);
to = ts // compilation error!
Prateek Kapoor
  • 947
  • 9
  • 18
1

So what are generics in Java exactly? As mentioned by dave, the generic types are compiler enforcements. To be exact, at runtime, the generic types do not exist anymore. They are replaced by Object or the upper bound of a generic type. This process is called Type Erasure. So, generic types only exist at compile-time.

Then why can we not cast an ArrayList<String> into an ArrayList<Object>? Even though the type parameters stand in a relation (String is a Object), the generic classes do not. Let me give a simple example. If

ArrayList<String> strings = new ArrayList<String>();
ArrayList<Object> objects = strings;

would be possible, if one calls

objects.add(new Object());

what should happen? Since strings can only hold Strings, Java cannot "put" an Object into this list. But on the other hand, if you look at the declaration of objects there is nothing hinting, that this should not work. Therefore, Java does not allow conversion between generic classes, even if the generic types stand in a relation.

But generic types are not present at runtime. So what is the hustle? Should ArrayList<String> not really be an ArrayList<Object> at runtime and therefore, all of this should not matter? Well no. Since you know the type at compile-time, you can use certain contracts. For example, when retreiving an element out of an ArrayList<String> one can be sure that this retrieved object has the public char charAt(int) method (since a String has this method). If, for whatever reason, this ArrayList<String> would return an Object instead of a String, one could not call the charAt(int) method.

Community
  • 1
  • 1
Turing85
  • 18,217
  • 7
  • 33
  • 58