EnumMap class constructor needs class as the argument. Most of the times K.class passed as the argument. I am still not getting what is the reason for accepting this as argument instead of deducing from K.
Thanks
-- pkc
Tom's answer is correct, but to address your other point: the reason this information can't just be deduced from the type parameter, K, is due to type erasure.
The implementations of EnumMap needs metainformation about the enum, in particular the number of values. The Class object provides this information (IMO it would have been better to go for a specific enum descriptor type). If you don't have the Class available, you can always use HashMap at some penalty. I guess you could create a growable/uncommitted EnumMap-like Map.
The Map thus knows all possible keys. It's called (internally) the keyUniverse. The comments says:
All of the values comprising K. (Cached for performance)
As others point out generics are a compiler feature. The jvm has no real support for generics itself. This means that the generic information cannot be used at runtime.
For the EnumMap<K extends Enum> this means that you get a EnumMap<Enum> at runtime without any information about the K. This limitation of java generics can be worked around by passing the classes of the Generic arguments to a constructor as the class objects still exist at runtime.
Generics is a compile time feature, however this K class is needed at runtime, something generics won't do in this case.
Related
Long story short:
Why is the following not possible in Java?
public class Test<A<B>> {} // A and B both being generic parameters.
Note: I don't have any specific use case right now, rather I am just trying to understand why this is not allowed.
At first I thought because the compiler cannot assert if A can accept generics parameter because after compiling A, due to type erasure the generics won't be present anymore.
But, if that is the case, then we cannot use generics on any class at all. So I took out the byte code of a generic class and found that there is metadata to say it accepts generics.
public class com.Test<T> {
public com.Test();
Code:
0: aload_0
1: invokespecial #12 // Method java/lang/Object."<init>":()V
4: return
}
And I did a quick search and SO confirmed compiled code will have generics related metadata too
So why does the compiler not allow multilevel generics?
Will there be any problem in allowing it? Is it a limitation? or something else?
Let's assume that this class was actually compiling:
public class Test<A<B>> { .. }
This implies that a proper instantiation of the class would be:
new Test<Class<Integer>>()
//or
new Test<List<String>>()
and the following wouldn't be correct (since the provided type-parameter is not generic):
new Test<String>();
//or
new Test<Object>();
However, a type-parameter should not be restricted for being generic or not - it should just hold some meta information about the type (and as it turns out, this is the type after type-erasure has taken place) with which it would be replaced.
Type-erasure itself can be another possible reason for not allowing such constructions. Let's again consider the above Test class was correctly defined and you had this:
new Test<Class<Integer>>();
When type-erasure happens, <A<B>> should be replaced with Class<Integer>, however, due to the erasure, we'd have only a Class (even though internally it would contain info about the Integer type) - expecting a Class<Integer>, but providing a Class should not be correct.
Thanks for the interesting question!
Scala calls it higher kinded types. So it's definitely a feasible abstraction. Adding it to Java has — to my knowledge — never been seriously considered.
Sadly, I can't find any good introductory text to Scala's higher kinded types. The best I can find is the original paper Generics of a Higher Kind; here's its abstract:
With Java 5 and C# 2.0, first-order parametric polymorphism was introduced in mainstream object-oriented programming languages under the name of generics. Although the first-order variant of generics is very useful, it also imposes some restrictions: it is possible to abstract over a type, but the resulting type constructor cannot be abstracted over. This can lead to code duplication. We removed this restriction in Scala, by allowing type constructors as type parameters and abstract type members. This paper presents the design and implementation of the resulting type constructor polymorphism. Furthermore, we study how this feature interacts with existing object-oriented constructs, and show how it makes the language more expressive.
C# allows for getting the type of generic parameters using the typeof(T)method without the need to instantiating the T parameter. But in Java anytime I have generic T parameter and I want to determine the type I have to create an instance of that parameter,for example by using the Class<T> Type, to figure out what type that is.
In comparison with what C# provides, this approach in Java looks unnecessarily lengthy and complicated.
I would like to know what is best alternative to determine the type of a generic parameter without the need to instantiate that (for example if (T is Integer)).
Generics in Java is a compile-time feature - thus the mismatch between Java and C#. As a result you cannot do anything at run time to determine the type unless you are either passed an object of the type or create one yourself or actually told the class in some other way.
It is generally considered a bad idea to even try to find the type. It generally indicates that you have not designed your class hierarchy properly.
Generics are compile-time true... but you can give the compiler hints of what t really is.
by passing in the actual runtime class of what T really is, you allow the compiler to allow you runtime knowlege of the class T represents.
example:
public <T> boolean isObjectT(Class<T> type, Object object){
return object.getClass().isAssignableFrom(type);
}
The answer on this question kinda spells out the limits of parameterized types:
Java: How do I specify a class of a class method argument?
If you are simply trying to get information from subclasses... you could try the reflection with paramterized types on this question:
How to determine the class of a generic type?
I have had good luck with that for more complex requirements.
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.
For example, instead of doing
ArrayList<ClassName> variableName;
you do
ArrayList variableName;
then later you add an object of type "ClassName"
variableName.add(objectName);
will that automatically set the type of your array as
ArrayList<ClassName>
?
No. Generics are for compile time only. You are just losing the benefit of that check. At runtime all generic information is erased
In other words,
ArrayList<Type>
at runtime is just an ArrayList. The benefit of doing that over just a List is that when you are writing your code, the compiler will check that you dont put anything inappropriate in your list.
when you don't specify, it would be the same as if you specified ArrayList<Object>, meaning that any type of object could be added to the ArrayList. The type checks which are performed when specifying a class happen at compile time, not at runtime, so its not possible for things to work the way you propose (having them more specific class determined at runtime).
The real type is really ArrayList. The ArrayList<ClassName> type only exists for the compiler (this is called erasure), and its purpose is to give type safety at the compiler level. But at the bytecode level you don't have that knowledge of generic types.
For example, I could write either of these:
class example <T>
{
...
public void insert (T data)
{
...
}
}
or
class example
{
...
public void insert (Object o)
{
...
}
}
Is there a signficant difference between the 2 in terms of performance? With generics I could restrict the type of the parameter and with the second approach I guess it wouldn't be necessary to define the type of the object as it is created.
Also, with the second approach I could basically insert anything into the class, right? Whereas with generics every element in the class would be of the same type.
Anything else I'm missing?
The only reason to write the latter is if you must target an earlier JVM. Generics are implemented by type-erasure, so they have no runtime impact - only added compile time checking which will improve your code.
Of course if you need a collection which holds any old object, or a mix of several which don't have a common superclass, you need the plain Object variation (but then your class can still be generic and instantiated with new ...<Object>).
I think you pretty much nailed it. There is no performance difference. Generics are rationalized away (Type Erasure) when the code is compiled, and don't exist anymore at runtime. They just add casts when needed and do type-checking as you stated. Neal Gafter wrote a nice overview of how they work, of the current problems with Generics and how they could be solved in the next version of Java: http://gafter.blogspot.com/2006/11/reified-generics-for-java.html
There shouldn't be a performance difference.
However, Java does not offer parameter variance, so there are situations where you will be overriding pre-generics functions such as equals, compareTo, etc. where you will have to use Objects.
Some of the encounters where I had to use 'Object' instead of Generics were those of compulsion than of a choice. When working with pre-generic code or libraries built around pre-generic api, one has little choice. Dynamic proxies for example, Proxy.newProxy() returns Object type. Passing generic context (where a context can be anything) is another instance. Some of my friends argue that are as good as no-generics. As far as performance is concerned, there shouldn't be any overhead, considering type erasure.
Regarding performance, i agree with the people above.
Regarding this point of yours
"Also, with the second approach I could basically insert anything into the class, right? Whereas with generics every element in the class would be of the same type."
One more advantage of generics is there is a type check for assignment of the example instance itself.
Say for example you had an Example e1 of and another Example e2 of , type safety would be maintained and you would never be able to do e1=e2;
while with the object example, that would be possible.