Java generics: is-A relation to Object - java

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?

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>.

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.

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!

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

Related

Is the return Object of getConstructors() method not array of parameterized type?

in this Link, it is declared that we can not create an array of parameterzide type.
Create an Array of Arraylists
but in java reflect, we can call getConstructors() method and save it's returned objects as below.
Constructor<?>[] constructors = MyClass.class.getConstructors();
so the question is, isn't it also a parameterized type object ?
Constructor<?>[]
if yes, then why does it work here ?
Good question. You can surely define an array of parameterized type bye breaking type safety like,
ArrayList<Individual> [] group = new ArrayList()[4] //unchecked warning
Arrays are covariant subtypes, which means Strings [] is a subtype of Object [] and are implemented in way that the elements we are adding is checked at runtime for there types like,
String [] stArr = new String[10]
Object [] objects = strings;
objects[0] = new Integer(); // Runtime ArrayStoreException will be thrown
To prevent wrong assignments, compiler does runtime checks of every array assignment.
while generics are compile time only. So Java would not be able to identify generic type once aliased to subtype, like,
ArrayList<Integer> [] lstArr = new ArrayList[10];
Object [] objArr= lstArr;
ArrayList<String> strList = new ArrayList<String>();
objArr[0] = strList; // No runtime exception here
Unbounded wildcard type is only way as while putting the elements, no real type check is required for unbounded wildcard type.
ArrayList<?>[] lstArr = new ArrayList<?>[10];
lstArr[0] = new ArrayList<Integer>();
Hope this answers your question.
First, declaring the return type as Constructor<?>[] does not imply creating an array of Constructor<?>, does it? It's just saying "this method returns this type". Just saying that does not create an array, so no errors there.
But getConstructors is going to create a Constructor<?>[] somewhere in its implementation, right? How does that work?
Well, after tracing the source code of getConstructors, I found this line where an array is created:
Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
This line (creating an empty array) is executed if the Class is an interface. (If the Class is not an interface, then a native method gets called.) Why can a Constructor<?>[] be created?
The Oracle documentation in this case is not 100% accurate (this is not to say you should not trust it anymore), because Constructor<?> is a parameterised type, but new Constructor<?>[0] is valid.
Let's have a look at what a more authoritative document - the Java Language Specification - says about creating arrays of generic types:
15.10.1. Array Creation Expressions
[...]
It is a compile-time error if the ClassOrInterfaceType does not denote
a reifiable type (§4.7). Otherwise, the ClassOrInterfaceType may name
any named reference type, even an abstract class type (§8.1.1.1) or an
interface type.
A reifiable type is defined as:
4.7 Reifiable Types
A type is reifiable if and only if one of the following holds:
It refers to a non-generic class or interface type declaration.
It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).
[...]
The second bullet point applies to Constructor<?>. This is why you could create a new Constructor<?>[10].

Instantiate a Java type parameter/ generic using a Class object [duplicate]

This question already has answers here:
How to set the generic type of an ArrayList at runtime in java?
(4 answers)
Closed 5 years ago.
How do you instantiate a Java generics Object that takes type parameters given only a Class or Class<?> object?
For example:
Normally one can instantiate an ArrayList of Integer objects using the following syntax:
ArrayList<Integer> foo = new ArrayList<Integer>();
However, given a Class<?> object such as Integer.class, how could one create a similar ArrayList? For example, how would I do something like this (incorrect syntax):
ArrayList<Integer.class> foo = new ArrayList<Integer.class>();
I need this for something very unusual I am doing with Java (Creating an open-source tool for visualizing user-supplied instances of data structure/ generic classes they write). Here is an example of how I would be using this code which illustrates the information I would be given:
import java.util.ArrayList;
import java.util.List;
public class ArrayListFromClass {
// obviously this code does not work
public static void main(String[] args) {
Object givenObject = new Integer(4);
// I would not know it is Integer.class, a Class<?> object would be supplied by the user/ as a generic
Class<?> cls = givenObject.getClass();
List<cls> bar = new ArrayList<cls>();
// Where args[0] is "Integer.class"
List<args[0]> foo = new ArrayList<args[0]>();
// then I would be able to add to foo or bar with one or both of these techniques:
// printing givenObject.getClass() gives you java.lang.Integer, don't worry about the casting not working.
bar.add(cls.cast(givenObject));
Integer y = 6;
bar.add(y);
}
}
Java is statically typed. The reason you would want to instantiate an ArrayList like so:
ArrayList<Integer> foo = new ArrayList<>();
is to let your IDE/compiler know that whenever something other than Integer is put into the list, show an error. Other than that the internals will ignore this initialization, in fact even erase the type.
So when you get your Class<?> object at runtime, you only know the type of the class when your code actually runs. So the IDE/Compiler wouldn't be able to warn you before runtime whether there is something wrong in your code.
So a List<Object> will do just fine in your case. If you want type safety you will have to check on your own like so:
String sampleString = "String";
Class<?> clazz = sampleString.getClass();
...
if (clazz.isInstance(sampleString)) {
list.add(sampleString);
}
.isInstance(Object obj) is the equivalent of instanceof when you actually have a Class<?> at hand.
You don't need to worry about the generic parameter.
Turns out that generic parameters are actually erased at runtime (see type erasure).
So you will just need to make it List<Object>.
This may seem like a problem, but it rarely matters. You will just need to keep track of the type that you put in and make sure that you remove and cast properly. Most of the time when using reflection the concrete types of your Objects don't really matter since you invoke methods, and access fields indirectly.

Generics Vs. Arraylist?

I am a little confused regarding ArrayLists and generics, for instance, in the program below when I declared, Gen<Integer>iOb=new Gen<Integer>(88); it declared a generic type of Integer correct? However, if I declare an arraylist in the same fashion? In the case of an arraylist, it is the type that is in angle brackets, however, researching generics, it says that the type in the angle brackets is the generic type? How do I know if its an arraylist of a class type or a generic?
//A simple generic class
//Here, T is a type parameter that
///will be replaced by a real type
//when an object of type gen is created
class Gen<T> {
T ob;//declare an object of type T
//Pass the constructor a refernce to
//an object of type T
Gen(T o) {
ob = o;
}
//return ob
T getob() {
return ob;
}
//show type of t
void showType() {
System.out.println("Type of T is " + ob.getClass().getName());
}
}
class GenDemo {
public static void main(String[] args) {
//create a gen reference for integers
Gen<Integer> iOb;
//Create a Gen<Integer>Object and assign its
//reference to iob, notice the use of autoboxing
//to encapsulate the value 88 within an integer object
iOb = new Gen<Integer>(88);
//show the type off data used by iob
iOb.showType();
//get the value in Iob notice that no cast is needed
int v = iOb.getob();
System.out.println("Value: " + v);
System.out.println();
//create a gen object for strings
Gen<String> strOb = new Gen<String>("Generic Test");
//show the type of data
strOb.showType();
//get the value of strOb, again notice that no cast is needed
String str = strOb.getob();
System.out.println("Value :" + str);
}
}
You seem to be confusing the concepts of a generic type and a type parameter.
Given your class:
class Gen<T> {
// ...
}
Gen is a generic class (a specific kind of generic type) because it is declared to have at least one type parameter, in this case T. When you instantiate Gen, and sometimes in other cases, you provide a type expression that is bound to T:
Gen<?> gen = new Gen<String>();
The type expressions given (? and String) are typically also called "type parameters", just like the T in class Gen's definition. Specific type parameters may be formed from generic classes (example: List<String> in Gen<List<String>>), but "generic class" is not a synonym for "type parameter".
ArrayList is just the same. It is a generic class with one type parameter. Specific declarations provide type expressions to serve as the values of those type parameters:
List<Integer> list = new ArrayList<Integer>();
There, List<E> and ArrayList<E> are generic types; the latter is specifically a generic class. The Integer on both sides is the type parameter applying to the declaration of list and the instantiation of ArrayList; it is not referred to as a "generic class" in this context or any other.
When I declared, Gen<Integer> iOb = new Gen(88); it declared a generic type of Integer correct?
This is incorrect. You are declaring/creating an Gen object, which holds a T extends Object. Inside Gen code, you can only use functions that are allowed to be used on an Object, such as getClass().
The Java Compiler remembers that iOb will reference a Gen object that must hold an Integer object, and will generate automatic type casting on the return value of getob() ...
int v=iOb.getob();
Is interpreted by the compiler as if the following was written:
int v = (Integer) iObj.getob();
Where getob() is considered to just return an Object. Note that this is a compile-time transformation as a convenience for the programmer.
However, if I declare an arraylist in the same fashion? In the case of an arraylist, it is the type that is in angle brackets, however, researching generics, it says that the type in the angle brackets is the generic type? How do I know if its an arraylist of a class type or a generic???
class SomeClass<T> { ... } declares a generic type. The part between the angle brackets is the "type argument(s)" for the generic class.
When the generic class used as a type for a variable, it is considered a specialization of the the generic class, and type argument(s) could be a concrete class, an interface, or another generic class.
Your question is worded kind of strange, but I'll give it a shot. Generics are used for type safety, ESPECIALLY for collections. If you were to declare an ArrayList like this:
ArrayList a= new ArrayList();
then you could put any kind of object you wanted in to the ArrayList. That's very dangerous since when you're retrieving objects from the list you'll need to know what kind of object you will be retrieving from the list. You wouldn't want to pull a cat object into a person reference! Cats aren't people! That's where generics come in. Declaring your ArrayList like this:
ArrayList<People> p= new ArrayList<People>();
allows you to have type safety. No more problems with those pesky Cat objects getting in to your people array!
As for this:
//get the value in Iob notice that no cast is needed
int v = iOb.getob();
You seem to be getting confused with unboxing. It has nothing to do with Generics. I recommend you look up autboxing and unboxing.
finally:
//get the value of strOb, again notice that no cast is needed
String str = strOb.getob();
I don't see what you don't understand here. Strings are objects. You put a String object in and you pulled a String object out.
I also recommend creating a simple java object, say a person, so you can create a generic with your Gen class, say String, and attempt to put a Person object in. See what errors it gives.
First, we should clear up some terms. From https://docs.oracle.com/javase/tutorial/java/generics/why.html
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.
So when you did Gen<Integer>iOb=new Gen<Integer>(88);, a Gen class was made of type Gen but with generic type parameter Integer. Gen is a generic class because the class header contains a generic type parameter <T>. However, Arraylists are also generic classes because they are not restricted to one type as you can tell from the declaration. When declaring a Arraylist, you can do a type declaration the same way you do so for your Gen class. Ex: Arraylist<String> list = new ArrayList<String>();
Arraylists do have a raw type implementation which does require not a type parameter in the declaration. Ex: Arraylist list = new Arraylist(); But this is not recommended and Java will actually give you a warning if you declare arraylists this way, advising you to parameterize the arraylist.
In conclusion, a generic type is a generic class or interface that is parameterized over types (https://docs.oracle.com/javase/tutorial/java/generics/types.html). So your Gen class and the built-in Arraylist class of Java are both generic types.

Type safety: The method.. belongs to the raw type.. refs to generics should be parameterized

Eclipse gives me the warning (in the title) using just the following code in a working project with nothing in it but a dummy class and a main method:
List a = new ArrayList();
List<Integer> b = new ArrayList<Integer>();
int x = 19;
a.add(x);
The last line triggers the warning. I'm not sure what I am doing wrong here, or really, what I am even doing. I am a Java student following a dubious tutorial and I am attempting to understand generics. Supposedly, variable x doesn't illustrate type safety. I tried casting it to the Object type (which I think does nothing because it already is) and it didn't work.
How might I resolve this warning?
You have declared List a without the type parameter. This is why eclipse is complaining about type safety, as you could add objects of any type to that list.
If you look at the ArrayList api and take a look at the class declaration, you see it is declared like this:
public class ArrayList<E>
Substitute E with any class you wish.
With List<Integer> b you have explicitly told the compiler that the list is to hold instances of Integer objects only, and the compiler can verify this, thus giving you type safety.

Instantiating a Generic Class of Type <?>

I'm studying for the SCJP/OCPJP and I came across a sample question that seams strange to me.
The sample code instantiated two generic collections:
List<?> list = new ArrayList<?>();
List<? extends Object> list2 = new ArrayList<? extends Object>();
The "correct" answer to the question was that this code would compile but adding to either collection would produce a runtime error.
When I try to compile code like this I just get errors. The Java tutorial does not even show this type of code, it instead usually uses wildcards as a part of an upcast.
Collection<?> c = new ArrayList<String>();
Are the two generic collections above even legitimate code? The second by my logic would only disallow interfaces. The first one looks completely useless. Why use a generic that makes no attempt at control?
Check out the excellent Java generics tutorial PDF. More specifically the section about wildcards contains the answer to your question, and I quote
Collection<?> c = new ArrayList<String>();
c.add( new Object() );
Since we don’t know what the element type of c stands for, we cannot
add objects to it. The add() method takes arguments of type E, the
element type of the collection. When the actual type parameter is ?,
it stands for some unknown type. Any parameter we pass to add would
have to be a subtype of this unknown type. Since we don’t know what
type that is, we cannot pass anything in. The sole exception is null,
which is a member of every type.
If you want to declare Type at runtime, you can do something like this:
public class Clazz1<T> {
private final List<T> list = new ArrayList<T>();
private List<T> getList() {
return list;
}
/**
* #param args
*/
public static void main(String[] args) {
Clazz1<Integer> clazzInt = new Clazz1<Integer>();
clazzInt.getList().add(2);
System.out.println(clazzInt.getList());
Clazz1<String> clazzString = new Clazz1<String>();
clazzString.getList().add("test");
System.out.println(clazzString.getList());
}
}
I answered this somewhat before in this answer. ? cannot be used in the instantiation. I'm not sure why it says the code would compile, none of the java compilers I have used would allow that. You could do what is shown above by the following:
List<?> list = new ArrayList();
That would compile and run, but you couldn't do:
list.add("hello world"); //This wouldn't compile
new produces a concrete instance of an object. The concrete instance can have only one type, including any generics. Knowing this, wildcards cannot work with new.

Categories

Resources