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.
Related
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].
I am currently studying Java and have recently been stumped by angle brackets(<>). What exactly do they mean?
public class Pool<T>{
public interface PoolFactory<T>{
public T createObject();
}
this.freeObjects = new ArrayList<T>(maxsize)
}
What does the <T> mean? Does it means that I can create an object of type T?
<T> is a generic and can usually be read as "of type T". It depends on the type to the left of the <> what it actually means.
I don't know what a Pool or PoolFactory is, but you also mention ArrayList<T>, which is a standard Java class, so I'll talk to that.
Usually, you won't see "T" in there, you'll see another type. So if you see ArrayList<Integer> for example, that means "An ArrayList of Integers." Many classes use generics to constrain the type of the elements in a container, for example. Another example is HashMap<String, Integer>, which means "a map with String keys and Integer values."
Your Pool example is a bit different, because there you are defining a class. So in that case, you are creating a class that somebody else could instantiate with a particular type in place of T. For example, I could create an object of type Pool<String> using your class definition. That would mean two things:
My Pool<String> would have an interface PoolFactory<String> with a createObject method that returns Strings.
Internally, the Pool<String> would contain an ArrayList of Strings.
This is great news, because at another time, I could come along and create a Pool<Integer> which would use the same code, but have Integer wherever you see T in the source.
It's really simple. It's a new feature introduced in J2SE 5. Specifying angular brackets after the class name means you are creating a temporary data type which can hold any type of data.
Example:
class A<T>{
T obj;
void add(T obj){
this.obj=obj;
}
T get(){
return obj;
}
}
public class generics {
static<E> void print(E[] elements){
for(E element:elements){
System.out.println(element);
}
}
public static void main(String[] args) {
A<String> obj=new A<String>();
A<Integer> obj1=new A<Integer>();
obj.add("hello");
obj1.add(6);
System.out.println(obj.get());
System.out.println(obj1.get());
Integer[] arr={1,3,5,7};
print(arr);
}
}
Instead of <T>, you can actually write anything and it will work the same way. Try writing <ABC> in place of <T>.
This is just for convenience:
<T> is referred to as any type
<E> as element type
<N> as number type
<V> as value
<K> as key
But you can name it anything you want, it doesn't really matter.
Moreover, Integer, String, Boolean etc are wrapper classes of Java which help in checking of types during compilation. For example, in the above code, obj is of type String, so you can't add any other type to it (try obj.add(1), it will cast an error). Similarly, obj1 is of the Integer type, you can't add any other type to it (try obj1.add("hello"), error will be there).
It is related to generics in java. If I mentioned ArrayList<String> that means I can add only String type object to that ArrayList.
The two major benefits of generics in Java are:
Reducing the number of casts in your program, thus reducing the number of potential bugs in your program.
Improving code clarity
is called a generic type. You can instantiate an object Pool like this:
PoolFactory<Integer> pool = new Pool<Integer>();
The generic parameter can only be a reference type. So you can't use primitive types like int or double or char or other primitive types.
<> is used to indicate generics in Java.
T is a type parameter in this example. And no: instantiating is one of the few things that you can't do with T.
Apart from the tutorial linked above Angelika Langers Generics FAQ is a great resource on the topic.
Generic classes are a type of class that takes in a data type as a parameter when it's created. This type parameter is specified using angle brackets and the type can change each time a new instance of the class is instantiated. For instance, let's create an ArrayList for Employee objects and another for Company objects
ArrayList<Employee> employees = new ArrayList<Employee>();
ArrayList<Company> companies = new ArrayList<Company>();
You'll notice that we're using the same ArrayList class to create both lists and we pass in the Employee or Company type using angle brackets. Having one generic class be able to handle multiple types of data cuts down on having a lot of classes that perform similar tasks.
Generics also help to cut down on bugs by giving everything a strong type which helps the compiler point out errors. By specifying a type for ArrayList, the compiler will throw an error if you try to add an Employee to the Company list or vice versa.
In the code below, if I instantiate Generic as:
Generic gen=new Generic(1,2);
that is without type argument,then when i do this:
int a=gen.get_a();
it does not work and gives
required:int Found:Java.Lang.Object
but ob.print() works.
So when I do this instead:
int a=(Integer)gen.get_a();
then it works. So does the erasure replace T with Object type since T cannot be primitive, when no type argument is passed?
public class Generic<T>
{
T a;
Generic(T a)
{
this.a=a;
}
void print()
{
System.out.print(a);
}
T get_a()
{
return a;
}
}
Here, as Jon Skeet said, you are using a raw type in your variable declaration.
Generic gen=new Generic(1,2);
int a=gen.get_a();
it does not work and gives
required:int Found:Java.Lang.Object
The compiler cannot guess the type if you don't specify it when you declare the variable.
So does the erasure replace T with Object type since T cannot be
primitive, when no type argument is passed?
Using types demands specifying class in the declaration. And a primitive is not a class.
Generic<int> gen = new Generic<>(1); will not compile
So, you have to specify the wrapper object of int primitive if you want to type your instance with an integer value :
Generic<Integer> gen = new Generic<>(1);
You must have done noticed it when you declare a collection variable with generics relying on numeric types.
Object is the root class in Java and as in your caseT doesn't extend any explicit class, T derives from Object implicitly.
So, it you use a raw type in your variable, you manipulate objects.
I suppose that the compiler considers that the returned type of unspecified T is the most specific and compatible type for T and in your case it is Object.
You have the same behavior with a collection : at compile-time, a raw java.util.List manipulates Object when T is encountered.
Edit :
Here, I will give you another example to illustrate that with raw types, instead of declare type, the Object class is not necessarily used by the compiler if the type declared in the class extends another class. Contrary to what you may think.
If the Generic class was declared like that :
public class Generic<T extends MyClass>{
...
}
Even by using a raw type in the declaration of the variable, get_a() would return a MyClass object since the most specific and compatible type for T is not Object but MyClass.
Generic gen = new Generic(1);
MyClass myClass = gen.get_a(new MyClass());
I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E, which is the type definition from List interface.
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
For example if you did this:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:
Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.
Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
The javadoc will tell you what you are doing.
Class#getGenericSuperclass() states
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code. [...]
The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type object returned by it, you will see
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments() which states
Returns an array of Type objects representing the actual type
arguments to this type.
will return the Type
E
since E is the actual type argument used in the ArrayList class definition.
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
If you are creating instances on the fly it won't work:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you)
(It's called Type Erasure)
I am currently studying Java and have recently been stumped by angle brackets(<>). What exactly do they mean?
public class Pool<T>{
public interface PoolFactory<T>{
public T createObject();
}
this.freeObjects = new ArrayList<T>(maxsize)
}
What does the <T> mean? Does it means that I can create an object of type T?
<T> is a generic and can usually be read as "of type T". It depends on the type to the left of the <> what it actually means.
I don't know what a Pool or PoolFactory is, but you also mention ArrayList<T>, which is a standard Java class, so I'll talk to that.
Usually, you won't see "T" in there, you'll see another type. So if you see ArrayList<Integer> for example, that means "An ArrayList of Integers." Many classes use generics to constrain the type of the elements in a container, for example. Another example is HashMap<String, Integer>, which means "a map with String keys and Integer values."
Your Pool example is a bit different, because there you are defining a class. So in that case, you are creating a class that somebody else could instantiate with a particular type in place of T. For example, I could create an object of type Pool<String> using your class definition. That would mean two things:
My Pool<String> would have an interface PoolFactory<String> with a createObject method that returns Strings.
Internally, the Pool<String> would contain an ArrayList of Strings.
This is great news, because at another time, I could come along and create a Pool<Integer> which would use the same code, but have Integer wherever you see T in the source.
It's really simple. It's a new feature introduced in J2SE 5. Specifying angular brackets after the class name means you are creating a temporary data type which can hold any type of data.
Example:
class A<T>{
T obj;
void add(T obj){
this.obj=obj;
}
T get(){
return obj;
}
}
public class generics {
static<E> void print(E[] elements){
for(E element:elements){
System.out.println(element);
}
}
public static void main(String[] args) {
A<String> obj=new A<String>();
A<Integer> obj1=new A<Integer>();
obj.add("hello");
obj1.add(6);
System.out.println(obj.get());
System.out.println(obj1.get());
Integer[] arr={1,3,5,7};
print(arr);
}
}
Instead of <T>, you can actually write anything and it will work the same way. Try writing <ABC> in place of <T>.
This is just for convenience:
<T> is referred to as any type
<E> as element type
<N> as number type
<V> as value
<K> as key
But you can name it anything you want, it doesn't really matter.
Moreover, Integer, String, Boolean etc are wrapper classes of Java which help in checking of types during compilation. For example, in the above code, obj is of type String, so you can't add any other type to it (try obj.add(1), it will cast an error). Similarly, obj1 is of the Integer type, you can't add any other type to it (try obj1.add("hello"), error will be there).
It is related to generics in java. If I mentioned ArrayList<String> that means I can add only String type object to that ArrayList.
The two major benefits of generics in Java are:
Reducing the number of casts in your program, thus reducing the number of potential bugs in your program.
Improving code clarity
is called a generic type. You can instantiate an object Pool like this:
PoolFactory<Integer> pool = new Pool<Integer>();
The generic parameter can only be a reference type. So you can't use primitive types like int or double or char or other primitive types.
<> is used to indicate generics in Java.
T is a type parameter in this example. And no: instantiating is one of the few things that you can't do with T.
Apart from the tutorial linked above Angelika Langers Generics FAQ is a great resource on the topic.
Generic classes are a type of class that takes in a data type as a parameter when it's created. This type parameter is specified using angle brackets and the type can change each time a new instance of the class is instantiated. For instance, let's create an ArrayList for Employee objects and another for Company objects
ArrayList<Employee> employees = new ArrayList<Employee>();
ArrayList<Company> companies = new ArrayList<Company>();
You'll notice that we're using the same ArrayList class to create both lists and we pass in the Employee or Company type using angle brackets. Having one generic class be able to handle multiple types of data cuts down on having a lot of classes that perform similar tasks.
Generics also help to cut down on bugs by giving everything a strong type which helps the compiler point out errors. By specifying a type for ArrayList, the compiler will throw an error if you try to add an Employee to the Company list or vice versa.