What does this work without a type?
ArrayList l = new ArrayList();
Does it just default to type object if you don't specify a type, and that cast everything to object?
And what does it mean in the api when it says ClassType (won't display) a question mark within less than greater than signs.
That's called a raw type. Avoid raw types where possible, as they reduce type safety.
Basically they're there for backward compatibility, so that when generics were introduced, existing code still compiled. As ever, see the Java Generics FAQ for more details.
Note that using a raw type is not the same as using a type with a type argument of Object, as raw types have all traces of generics removed from their effective API - even generic methods using other type parameters. That's part of what makes them dangerous.
Does it just default to type object if you don't specify a type, and that cast everything to object?
Yes. That's almost* right.
A generic type (such as ArrayList) which is not provided with type parameters is called a raw type. Raw types are covered in the official trail Type Erasure:
For instance, Box<String> 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.
[...]
Type erasure exists so that new code may continue to interface with legacy code. Using a raw type for any other reason is considered bad programming practice and should be avoided whenever possible.
*) You can put any Object into an ArrayList, but as #newacct points out in the comments, ArrayList is not to be considered the same as ArrayList<Object>, since ArrayList (and ArrayList<?> btw) are both supertypes of ArrayList<WhatEver>, while ArrayList<Object> is not.
Yes.
This is how Java used to work before generics were introduced. And in fact, this is still how it works, under the hood. The compiler performs basic type-checking, and then performs type erasure, so the bytecode that you're left with will be identical to that of the above.
You'll find a zip file in the root of the directory where you installed your JDK. In there, there is an src.zip.
I use eclipse as an IDE. In that you can attach the source so when you push CTRL+SHIFT+T and type ArrayList you'll be able to see it's source yourself ;)
Actually it is also a good way to see how more expert ppl write source-code :)
Related
Since the introduction of generic type parameters (or type arguments) in Java, writing the following line in Eclipse IDE will show a yellow squiggly line on the type Class:
Class myClass;
The warning shown on a mouseover is the following, with the two options (among others):
Class is a raw type. References to the generic type Class<T> should be parameterized.
Add type arguments to 'Class'
Add #SuppressWarnings 'rawtypes' to 'myClass'
The first option produces this code:
Class<?> myClass;
The second one produces this:
#SuppressWarnings("rawtypes")
Class myClass;
Both of the above options are equally adequate in taking care of the warning.
Assuming neither we nor Eclipse can infer generic type arguments*; what is the better approach to take, in what situations, and why?
* (despite having the option to try to do so)
A general rule every programmer should adhere to: never suppress warnings for no good reason. If you suppress a warning, you should know why the warning occurs and why it does not present a problem in your case.
In this case the reason to suppress a rawtype warning would be to support legacy code that was written in a time when genericity did not exist in Java (See the Java Language Specification 4.8):
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.
So it does not apply to your case, you should not suppress this warning.
As to the Wildcard ?, this should only be used if you want to assign various types to that variable.
For example a List<?> mylist lets you store any type in the list, while List<? extends Collection> lets you store any type that inherits from Collection to be stored in the list. A general rule is to be as specific about allowed types as possible. This way the compiler can notify you sonner if you accidentally add an object into a List that is not meant for it.
So the best way to go here is to think about how you want to use your myClass variable and if you can make a statement about which type of objects it will hold, replace the Wildcard with that type.
I noticed that it's possible to define a variable like this, without specifying it's generic type.
While this seems to compile, I noticed some strange issues when I did it to more complicated classes, such as no longer picking up method signatures properly. These problems went away when I used a insted of just leaving off the generic type.
Is there any practical purpose to the below code, and what is the difference between it and using ArrayList<?> instead?
Class Example {
private ArrayList list;
}
The raw typed collections are maintained for compatibility reasons with pre-generics Java versions (i.e. < 5).
Their usage is discouraged unless there is compatibility issue.
A non-generic ArrayList is like an ArrayList<Object> without any type safety.
Due to type erasure, method signatures do not retain parametrized generic types, so this is usually a source of confusion when overloading methods.
This is allowed for backwards compatibility, prior to Java 5 generics didn't exist and when they added them they didn't want to break existing code.
Most compilers/IDEs will give you a warning but conceptually it's the same as doing ArrayList<Object>
A generic class can have multiple type parameters
look here for more info and examples...
http://docs.oracle.com/javase/tutorial/java/generics/types.html
Lets say I have the class :
class Box<T>{}
Now what is the difference between :
public myMethod(Box box){};
and
public myMethod(Box<?> box){};
Update:
I'm asking because I want to see the effect on the variable box, Is the variable identical in both cases or not.
Collection<?> (pronounced "collection of unknown"), that is, a
collection whose element type matches anything.
I am not sure about your Box class definition so it is hard to describe it from that. But if you use any collection such as List, Map, Set. Then you can define the type of objects it may contain using generics. So if the type is not defined then it means you are allowing the raw types in your colection as mentioned here
Collection c;
But if you want this collection to store only a particular type then you can specify it using generfic. For examlple a collection of String:
Collection<String> c;
But if you want to allow any type of object to be stored then you use collection of unknown, as defined here:
Collection<?> c;
Using generics, allow you to find problems during compile time.
Read more here: http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Generics have been introduced into Java to help you catch a wide range of bugs in compile-time, instead of just encountering ClassCastException at runtime.
When you use <?> (a wildcard) you are saying to the compiler that you don't know (or don't care about) the generic type. For example: if you just want to count the number of elements of an Iterable<?>, you simply don't care about the types of the elements, so you could create a method with the signature int countElements(Iterable<?> iterable), that would simply retrieve an Iterator<?> from the iterable (note the wildcard type again), and then just call hasNext() and next(), while incrementing a counter.
You could do the same without the <?>, which is what is called a raw type.
You should almost never use raw types. Raw types are allowed since Java tries to be as backwards compatible as possible. If they didn't allow you to use raw types, almost all Java code from versions before 1.5 (when Generics have been introduced) would have to be rewritten; the raw types allows the compiler to compile that code -- although it will issue warnings.
I've thought java erasure wipes generic types out in compile time however when i test it by myself i realized there are some information about generic types in Bytecode.
here is my test :
i wrote 2 classes:
import java.util.*;
public class Test {
List integerList;
}
and
import java.util.*;
public class Test {
List<Integer> integerList;
}
i compiled both classes and somewhere in generic class i saw this line
integerList{blah blah}Ljava/util/List;{blah blah}
Signature{blah blah}%Ljava/util/List<Ljava/lang/Integer;>;{blah blah}<init>
in non generic class :
integerList{blah blah}Ljava/util/List;{blah blah}<init>
so obviously i have generic information inside bytecode so what is this erasure thing ??
what is this erasure thing ??
Erasure is a mapping from generic to raw types. The common phrase "because of erasure" is essentially meaningless. What is significant are the specifications that use the mapping.
There are two interesting uses.
It's used to map method signatures from using generics to raw types. It is the raw-type signatures that used for overloading. This causes the vast majority of the problems with "erasure". For instance, you can't have two methods add(List<String>) and add(List<Integer>) in the same type. Overloading probably isn't a great idea, and there's not a great willingness to add this feature.
The type available for an instance of an object at runtime is the type it was created with erased. So if you cast to, say, (String) that will be checked at runtime, but if you cast to List<String> only the erasure of that type (List) will be checked. You can have the variables of type List<String> and List<Integer> point to exactly the same instance. In practice, you shouldn't be using casts (of reference types) in 1.5 and later.
Where practical, generic information is kept in class files and made available through reflection. So you'll find it on class definitions, supertypes, fields, methods, constructors, etc.
Some Generic type information is stored in Signature attributes . Refer JLS 4.8 and 4.6 and JVM spec 4.3.4. Read here:
Probably the most common complaint about generics in Java is that they are not reified - there is not a way to know at runtime that a List<String> is any different from a List<Long>. I've gotten so used to this that I was quite surprised to run across Neil Gafter's work on Super Type Tokens. It turns out that while the JVM will not track the actual type arguments for instances of a generic class, it does track the actual type arguments for subclasses of generic classes. In other words, while a new ArrayList<String>() is really just a new ArrayList() at runtime, if a class extends ArrayList<String>, then the JVM knows that String is the actual type argument for List's type parameter.
and Neal Gafter's blog.
This is one instance where accurate use of terminology actually matters: Bytecode is the instruction set of the Java Virtual Machine. A class file contains bytecode, but also information used for linking (field signatures, method signatures, ...), for the bytecode verifier, for the debugger, ...
Type erasure means that generic type informations is not translated into byte code; more specifically, all instances of a generic type share the same representation in byte code. Likewise, the dynamic type of an object the runtime keeps track of (as used by the cast and instanceof operators, and available through getClass()) is the same for all instances of a generic class, irrespective of any type parameters supplied in the source code.
Your experiment proves that generic type information is retained in the class file, more specifically, in the types of method and field signatures. That's unsurprising, because the signatures are actually used at compile time. The might also be used at link time, and are even accessible through the reflection api. The crucial difference is that they are the declared types of fields or methods, not the runtime types of actual objects.
That is, since Java 1.5 we must distinguish between a variable's declared type, and the runtime type of the object it refers to. The former supports generics, the latter does not. And yes, this means there isn't a one-to-one correspondence between compile time and runtime types.
Type info will be erased from here
integerList = new ArrayList<Integer>();
in the bytecode it will be equivalent to
integerList = new ArrayList();
and there is no chance to know in runtime from integerList object what was its compile time type.
Erasure means that generic typing is not incorporated in the byte code (when the list is created or used).
The signature you see is used just to indicate that the field is generic.
How can you determine what type of object a generic is using at runtime ?
Due to type erasure, you cannot determine the actual type parameter(s) of a generic object instance. The best you can do is set things up so you can pass a class object to code that needs to know the actual type. For example, this is what java.util.EnumMap does in one of its constructor.
If you mean the T in List<T> (for instance), you can't, because Java uses type erasure. At runtime, a List<T> just looks like a List. This is true except in the edge case of anonymous classes, where it's possible if you jump through hoops to find the parameter type. But in the general case, you cannot. You usually have to communicate that information separately.
First we explain What is Generic
Generic in Java is one of important feature added in Java 5,
From Oracle's documentation:
Generics were introduced to the Java language to provide tighter type
checks at compile time and to support generic programming. To
implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or
Object if the type parameters are unbounded. The produced bytecode,
therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized
types; consequently, generics incur no runtime overhead.
Now how to make possible to get the generic type on runtime, with the help of this link
read: http://www.west-wind.com/weblog/posts/2011/Nov/11/Dynamically-creating-a-Generic-Type-at-Runtime
It is not possible to get the object type of "Generics" at run time. If we use object.getclass(), so we can get object of any class with the class name.