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.
Related
Initial Question
I have the following code:
public static void main(String[] args) throws Exception {
test(new LinkedList());
}
public static void test(Queue qeueue){
System.out.println("Queue");
}
public static void test(List list){
System.out.println("List");
}
InteliJ is not letting me run the project.
Is there any way to work around this issue?
Which of the two would the JVM use if both are equal in specificity? Is it random?
I have read related SO q/a but no one gives an answer how to compile around it.
They just list the reason, e.g. Ambiguous method call intelliJ 15
Update
An even more nasty example is:
test(null);
I have been reading the article that is quite interesting: http://javabypatel.blogspot.be/2016/05/ambiguous-method-overloading.html
A LinkedList both a List and a Deque, which in turn is a Queue.
The test method invocation is therefore ambiguous to the compiler, as there is no way to figure which overload to invoke.
Either merge the methods to accept a unique object (e.g. a Collection), or explicitly cast to either target type (or, have different method names altogether).
Also remember: it is discouraged to use raw types, you probably want to parametrize your generic collections.
With method overloading, it's the compiler who decides which method to use. To the JVM, your two methods are completely distinct, as if they had completely different names. With method overriding, that's different, then the run-time class of the "object before the dot" decides, and that's the JVM's job.
So, you have to deal with the compiler and help him to choose the correct method. The compiler's static type analysis must clearly exclude one of the two cases.
In your code, the compiler sees test(new LinkedList()); and deduces a static type of LinkedList. Knowing that that class implements both List and Queue, he can't select one method.
You don't want to cast like in test((List) new LinkedList());. Then the only variant that you might be willing to accept is to introduce a local variable of an unambiguous type, e.g.
List arg = new LinkedList();
test(arg);
Then the compiler no longer knows about the LinkedList type, but only about List, can no longer see that the run-time instance also is a Queue and selects the List method.
But effectively, it's casting as well.
And of course, you can (and maybe should) avoid the whole mess by giving different names to methods with overlapping parameter types.
Not possible without casting as you said. Since LinkedList implements both interfaces, compiler does not which one to link and thus gives an ambiguous call error. Once you cast it, compiler gets to know the intention and links a call accordingly.
I am an experienced C++ developer learning Java abstract concepts.
I was looking if I can do type inference in java and the answer is usually no and that I need to pass the Class type when calling a generic function. like so:
<T> void test(T t, Class<T> clazz);
I though this is redundant and that the compiler should be able to infer the type (C++ does it why can't Java :p) but then when I understood how generics are implemented under the hood I realized that T is essentially Object at runtime.
But then I realized that I can still call Object member functions on an instance of T. So I'm able to do something like this:
<T> void test(T t) {
if (t.getClass() == Integer.class ) {
// T is of type Integer.
}
}
1- Is there an advantage of either techniques over the other (i.e. passing Class<T> over checking Class type using getClass)?
2- Is there anything wrong with the second approach? The reason I am asking is that I have seen people go to the extend of using reflection and some obscure techniques before following what I've written above. Ideas?
There are a few issues here:
In general, you shouldn't really be inspecting the types of things at runtime. It's not wrong, per se, but if you feel the need to do it, then you're probably taking the wrong approach. For generics, for example, the whole point of a generic method is that it works regardless of the type argument.
Unlike C++, Java doesn't have any concept of template specialization; and Java programmers are comfortable with this restriction. Idiomatic Java code does not try to circumvent it.
There's no guarantee that t.getClass() is the same as the type T; t could be an instance of a subtype of T, for example. (Whereas a Class<T> is guaranteed to be the type T, unless it's null, or unless the program has "polluted the heap" by circumventing the generic type system.)
If you're going to do this, I'd suggest writing if (t instanceof Integer) instead of doing anything with getClass().
Is there anything wrong in the above approach?
Absolutely! If you have to "unmask" the generic type parameter T to do something special, you might as well do it in a separate piece of code, and either pass it on the side the way the class is passed, or require T implement a specific interface that provides the "special" functionality.
Is there an advantage of either techniques above over the other (i.e. passing Class<T> over checking Class type using getClass)?
Passing Class<T> technique has a specific reason behind it - letting you construct objects when you have none to begin with. In other words, it is applicable when you have no object on which to call getClass(), but you want to return an instance of T instead.
I'm trying to understand the benefit of a programming language being statically typed, and through that, I'm wondering why we need to include type in declaration? Does it serve any purpose rather than to make type explicit? If this is the case, I don't see the point. I understand that static typing allows for type checking at compile-time, but if we leave out the explicit type declaration, can't Java still infer type during compile-time?
For example, let's say we have in Java:
myClass test = new myClass();
Isn't the type declaration unnecessary here? If I'm not mistaken, this is static binding, and Java should know test is of type myClass without explicit declaration of type even at compile-time.
Response to possible duplicate: this is not a question regarding static vs. dynamic type, but rather about type inference in statically typed languages, as explained in the accepted answer.
There are statically typed languages that allow you to omit the type declaration. This is called type inference. The downsides are that it's tougher to design (for the language designers), tougher to implement (for the compiler writers), and can be tougher to understand when something goes wrong (for programmers). The problem with the last one of those is that if many (or all) of your types are inferred, the compiler can't really tell you much more than "the types aren't all consistent" — often via a cryptic message.
In a trivial case like the one you cite, yes, it's easy. But as you get farther from the trivial case, the system quickly grows in complexity.
Java does actually do a bit of type inference, in very limited forms. For instance, in this snippet:
List<String> emptyStrings = Collections.emptyList();
... the compiler has inferred that the method call emptyList returns a List<String>, and not just a List<T> where the type T is unspecified. The non-inferred version of that line (which is also valid Java) is:
List<String> emptyStrings = Collections.<String> emptyList();
It is necessary. You can have inheritance, where types are necessary.
For example:
Building build1 = new House();
Building build2 = new SkyScraper();
It is the same in polymorphism.
You can then collect all Buildings to array for example. If there will be one House and one SkyScraper you can't do this.
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.
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.