This question already has answers here:
Why does this Java method appear to have two return types?
(3 answers)
Closed 8 years ago.
In FindBugs source code, I found this method:
package edu.umd.cs.findbugs.ba;
....
public class ClassContext {
....
private <Analysis> Analysis getMethodAnalysisNoException(Class<Analysis> analysisClass, Method method) {
try {
return getMethodAnalysis(analysisClass, method);
} catch (CheckedAnalysisException e) {
IllegalStateException ise = new IllegalStateException("should not happen");
ise.initCause(e);
throw ise;
}
}
....
}
What is the meaning of first <Analysis> in the method declaration?
It is a Generic type. They were introduced in Java 1.5 and allow you to specify additional compile time information which is meant to reduce bugs. It is important to note type erasure when you talk about Java Generics, because it is a compile time feature that information is erased at runtime, and it is an Object (that happens to be of type Analysis).
Here is some info I wrote about generics in this post: What does generic type mean?
In Java, "Generics" are parameters for types. This may sound confusing but here is a simple explanation. If you were making a class that many other classes will inherit from, you want to make it broad and flexible. So you would use a "Generic" type to create instance variables.
Generic types can be implemented as: (Note the diamond brackets "<>")
public class TestClass<T>
Creating Instances With Generics This may a little more in depth than your question, but I thought I would mention how to create an instance of a generic class.
Note the argument that goes in the diamond braces has to be an object. For primitive types, you can just use Int, Double, Float (with capital first letters) and Java will "auto-box" the objects into primitive types.
ClassName<String> obj = new ClassName<>();
As per my knowledge its a Bytecode Analysis Framework. Definitely Analysis is a class.
You can find few code sample here.
What is the meaning of first <Analysis> in the method declaration?
This type is a generic type of declaration of method.
Hope it will help you.
The < Analysis > is a very poorly named type variable. That means the method getMethodAnalysisNoException can be called with a parameter of Class<T> for any type T and will return an instance of the type T if it doesn't throw an unchecked exception. Usually we don't use type variable names that look like regular class names because it is confusing, as evidenced by the wrong answers several folks have given here.
Related
Could you please help me to understand the generic concept here.
// Can't create an instance of T.
class Gen<T> {
T ob;
Gen() {
ob = new T(); // Illegal!!!
}
public static void main() {
Gen<Integer> genobj = new Gen<Integer>(); //Error
}
}
When your Java code is compiled, all generic type
information is removed (erased). This means replacing type parameters with their bound
type, which is Object if no explicit bound is specified, and then applying the appropriate
casts (as determined by the type arguments) to maintain type compatibility with the types
specified by the type arguments. The compiler also enforces this type compatibility.
My question:-Why java complier is throwing error here ?
Bevause after complitaion .
Thanks
There are a few ways that may work out here:
From a logical POV:
It's not even guaranteed that whatever template-parameter T you use has a default-constructor. Which obviously offers the problem of how to handle the absence of a default-constructor. Possible solutions would be to produce a runtime-error, compile-time error or disallow any T that doesn't provide a default-constructor. The latter would obviously break the template-definition, which allows any T. And the runtime-error would complicate things quite a bit and yield the same problem as mentioned above. Remains preventing this behavior in the first place and throwing a compile-time error.
From a internal view:
Let's assume we could use the provided code. Then how would it work? Due to erasure, new T() would produce an Object. But what if T is Integer? Well, we're screwed. An Object is not an Integer, so we'll get a plain class-cast exception.
So in summary: allowing the above to compile wouldn't work from a practical POV and in addition break the current definition of generics in java.
I was surprised today when this code compiled:
class GenericClass<T> {
public void emptyMethod(T instance) {
// ..
}
public void print(T instance) {
System.out.println(instance);
}
}
public class Main {
public static void main(String[] args) {
GenericClass first = new GenericClass();
System.out.println("Wow");
first.emptyMethod(10);
first.print(16);
}
}
The compiler emits a warning (Type safety: The method emptyMethod(Object) belongs to the raw type GenericList. References to generic type GenericList should be parameterized), but anyway it does not cause a compiler error and it runs 'fine' (at least the provided print method). As I'm understanding, the compiler is using object as the type argument, but I find it counter-intuitive. Why would the compiler do such thing? Why it doesn't require me to specify the type parameter?
You're using a raw class, basically.
Think back to when generics were first introduced in Java: there was a load of code which already used List, ArrayList etc. In order to avoid breaking all of that code, but still reusing the existing classes, raw types were introduced - it's basically using a generic type as if it weren't one.
As you can see, you get a warning - so it's worth avoiding - but that's the primary reason for it being allowed at all.
See section 4.8 of the JLS for more information, which includes:
Raw types are closely related to wildcards. Both are based on existential types. Raw types can be thought of as wildcards whose type rules are deliberately unsound, to accommodate interaction with legacy code. Historically, raw types preceded wildcards; they were first introduced in GJ, and described in the paper Making the future safe for the past: Adding Genericity to the Java Programming Language by Gilad Bracha, Martin Odersky, David Stoutamire, and Philip Wadler, in Proceedings of the ACM Conference on Object-Oriented Programming, Systems, Languages and Applications (OOPSLA 98), October 1998.
You have to know how generics are implemented in Java. They are far from perfect.
You have to remember that during run time everything is an Object. There are no types during run time.
Generics were added for added security in places, where you need it, but if you don't want to use it, you can ignore warnings and use unparametrized instances.
However, if you'd like java compiler to help you with type safety, then you parametrize generic class instances. Once you create a GenericClass for example, compiler will not allow you to use it with an integer parameter (first.emptyMethod(10) will not compile). You can still make it work with integer parameter if you do explicit type casting though.
So consider it a good practice for added security, which only works if you follow the rules.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
Java Generics — Assigning a list of subclass to a list of superclass
With raw types you can easily say something like this.
[...] // MyClass is generic with upper bound of Object
MyClass c = new MyClass<Double>();
[...]
But this isn't allowed
MyClass<Number> c = new MyClass<Double>()
I don't understand why this is. My book tells me why the second doesn't work, because you can't add a Integer to a MyClass<Double>. What it doesn't explains is why MyClass<Double> is a subclass of MyClass<Object> (or the equivalent raw type form), since double is subclass of object.
So why is the first allowed if the second form isn't. Please realize I am new to this.
Edit: Taking it a step further what would happen in the first example if Number was the upper bound?
You can see here the effects of type erasure
class Untitled {
public static void main(String[] args) {
}
public static<T> void c(T t)
{
t.SubClassMethod();// this won't work because class Object has no such method. But if I change the upperbound to SubClass it will.
t.toString() // this will because class Object has such a method
}
}
My point is that why should it matter what the Generic is declared as if it ultimately becomes treated as the upper bound anyway?
Try this:
MyClass<? extends Number> c = new MyClass<Double>();
The first thing to eliminate your confusion is to understand that the Raw Type is not part of the generics system at all. It is in no way equivalent to Something<Object>. Basically, the reason the Raw Type exists at all is just for backward compatibility. When Generics were introduced in Java 5, some existing classes and interfaces were retroactively made generic. In order for old code that didn't have generic declarations to compile in the Java 5 or later compiler, the Raw Declarations are legal.
Any comparison between the way the Raw Type behaves and the way the Parameterized type behaves is in a way a bit fundamentally spurious. The intent of the design is not that the Raw Type be considered an 'alternative' to declaring a parameter. New code that uses the Raw Type is incorrect code. It's legal to compile it so that old code still works.
My point is that why should it matter what the Generic is declared as
if it ultimately becomes treated as the upper bound anyway?
Because the entire point of the generics is to prevent ClassCastException. It will be treated as the actual declared type when someone, for example, someone takes the object back out of the list and assigns it to the specific type they're expecting. The compiler is making a promise that it guarantees this will succeed, so it has to restrict what goes in and out.
Suppose that MyClass is like this:
public class MyClass<T>{
T value;
public void foo(T arg){
value = arg;
}
}
and then those two other classes:
class A{ }
class B extends A { }
now imagine what happens if you do:
MyClass<A> container = new MyClass<B>();
container.foo(new A());
you'd try to put an A into a field of type B. The restriction you are facing is thought to prevent such things. C# has a nifty solution in terms of in and out parameters to generics...
Any MyClass<XXX> is a MyClass, but contrary to what you are saying, MyClass<Double> is not a subclass of MyClass<Object>.
You can find more about it if you search for erasure, like here.
I'm looking to access the generic type of a declared field during runtime. I was previously under the impression that this was not possible due to the Java type erasure. However, this must not be the case because some well known frameworks leverage the generic type through reflection during runtime.
As an example, Guice will implement a Provider based upon the generic type you provide:
public class Injectable{
#Inject
private Provider<SomeType> someTypeProvider;
}
How does one access the 'SomeType' generic attribute of a field or any such type/method/etc through the reflection API?
Additionally it would be helpful to also know how to access these generic type attributes through the Java 6 Annotation Processor API.
Thanks.
Edit:
Thank you all for your great pointers. I found a way to do this using haylem's links, specifically the one to Prenkov's article Java Reflection: Generics.
Here's the answer I was looking for:
/**
* #author John Ericksen
*/
public class TypeReflectionExample {
public class SomeType{}
public class Injectable{
#Inject private Provider<SomeType> someTypeProvider;
}
public static void main(String[] args){
try {
Field providerField = Injectable.class.getDeclaredField("someTypeProvider");
Type genericFieldType = providerField.getGenericType();
if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
for(Type fieldArgType : fieldArgTypes){
Class fieldArgClass = (Class) fieldArgType;
System.out.println("fieldArgClass = " + fieldArgClass);
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
results in:
fieldArgClass = class test.TypeReflectionExample$SomeType
The same can be done for Methods, Constructors, Superclass extensions/implements, etc
I'm awarding haylem, as his post led me to this solution, even if it didn't directly answer my question.
It is true that generics aren't generally known at runtime in Java, because they are implemented with Type Erasure.
Reflecting Generics?
However, you can stil extract some valuable information about the declared types (NOT the runtime objects' types), as presented in Ian Roberston's article Reflecting Generics and Prenkov's article Java Reflection: Generics.
Background on Generics and Type Erasure
Generics where introduced while conserving backwards compatibility at the source qnd binary level, hence some of their limitation, like:
the impossibility to have a short-hand form without at least some indicator for generics support (here, the so-called diamond operator <>),
the impossibility to inspect generic-types at runtime, because they had to be implemented with Type Erasure.
Further Reading
From The Java Tutorial:
section on Generic Types
section on Type Inference and Instantiation of Generic Classes
From the Java Language Specifications (JLS):
Java SE 5's JLS section on Types, Values and Variables
Java SE 7's JLS section on Types, Values and Variables
From good StackOverflow questions:
Java Raw Type and generics interaction
Others:
IBM Developer Series: Java Theory and Practice: Generics Gotchas (especially the sections The Road Not Taken, Generifying Existing Classes and Implications of Erasure).
Well, why don't you look at what guice does? The source is publicly available.
Guice does these things at multiple levels. One that particular sticks out are type literals.
The key point here is that while types are compiled using type erasure (so there is only one class for each type), there still exist multiple Type objects, that do know the generics used. However, the code is optimized independently of that (as it was compiled per class, and not per type).
Have a look at the Java API of ParameterizedType.
So while it is correct that Java Generics are implemented by "type erasure" on a class level, this doesn't completely hold on a Type level. Unfortunately, handling Types is much more tricky than classes. Plus, this also implies that Java cannot optimize generics in the same way that C++ does, in particular for primitive types. An ArrayList<Integer> will by design be an ArrayList<?> containing objects, and not backed by a native int[] array when possible.
Note that this is, however, rather close to keeping track of these things yourself. Say, very naively (it will not work with nested generics), you could just extend ArrayList<T> with a class, that has a field Class<T> contentClass, then you will be able to find out this information at runtime. (A TypeLiteral may be the better choice instead of a Class here, though!) Plus, the JRE will actually not ensure that the list remains consistent. Just like you could cast a ArrayList<Integer> into an untyped ArrayList and add a String object.
I've used this a year or so ago. It could help you out
Type typeOfSrc = type(YourClass.class, clazz);
// type(C, A1,...,An) => C<A1,...,An>
static ParameterizedType type(final Class raw, final Type... args)
{
return new ParameterizedType()
{
public Type getRawType(){ return raw; }
public Type[] getActualTypeArguments(){ return args; }
public Type getOwnerType(){ return null; }
};
}
This allows you to access the Generic type at run time. Basically what you're doing here is storing the Generic information in another class, and using that class for retrieving that information at run time.
I believe guice uses TypeLiteral to encapsulate generic information in a separate object.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Method has the same erasure as another method in type
In one of my classes I wanted to define these two methods:
private void add(List<ChangeSet> changeSetList) {
for (ChangeSet changeSet : changeSetList) {
add(changeSet);
}
}
private void add(List<Change> changeList) {
for (Change change : changeList) {
add(change);
}
}
Then I get the following error:
Method add(List<Change>) has the same erasure add(List<E>) as another method in type DataRetriever
Why isn´t this allowed? What is the problem with method definitions like that? And what should I do to avoid it? I don´t want to rename one of the methods.
That's just how the type system of Java "works". The generics List<Change> and List<ChangeSet> aren't actually different types. The generic parameters are just hints for the compiler to perform certain checks and certain casts. As far as the JVM and the type system is concerned, though, both types are actually "erased" to List<Object> (or just List if you will), and the two types are really the same, with no internal differences. Therefore, you cannot actually overload on different generics parameters, since as far as overload resolution is concerned, the two types are identical.
This limitation is part of the language syntax, not the Java runtime itself. Essentially, this rule is intended to avoid conflicts in legacy code that still uses raw types.
A compiler like javac will reject this type of overloading, but if you create a class through other means (writing your own compiler, or using a byte-code engineering library like ASM) with signatures that differ only by type parameters, the javac compiler will resolve calls the correct method in your class.
Here's an illustration of why this was not allowed, drawn from the JLS. Suppose, before generics were introduced to Java, I wrote some code like this:
class CollectionConverter {
List toList(Collection c) {...}
}
You extend my class, like this:
class Overrider extends CollectionConverter{
List toList(Collection c) {...}
}
After the introduction of generics, I decided to update my library.
class CollectionConverter {
<T> List<T> toList(Collection<T> c) {...}
}
You aren't ready to make any updates, so you leave your Overrider class alone. In order to correctly override the toList() method, the language designers decided that a raw type was "override-equivalent" to any generified type. This means that although your method signature is no longer formally equal to my superclass' signature, your method still overrides.
Now, time passes and you decide you are ready to update your class. But you screw up a little, and instead of editing the existing, raw toList() method, you add a new method like this:
class Overrider extends CollectionConverter {
#Override
List toList(Collection c) {...}
#Override
<T> List<T> toList(Collection<T> c) {...}
}
Because of the override equivalence of raw types, both methods are in a valid form to override the toList(Collection<T>) method. But of course, the compiler needs to resolve a single method. To eliminate this ambiguity, classes are not allowed to have multiple methods that are override-equivalent—that is, multiple methods with the same parameter types after erasure.
The key is that this is a language rule designed to permit continued use of raw types, not a limitation arising from the erasure of type parameters.
If you eliminate legacy code (for example, by using your own, not-strictly-Java language), this type of overload functions perfectly. Because method resolution occurs at compile-time, before erasure, type reification is not required to make this work.
in addition to the answers by adarshr and Kerrek, why not just make it generic like below:
private <T> void add(List<T> changeList) {
for (T change : changeList) {
add(change);
}
}
that should work for both cases...
Because generics are only a compile time aid to you. After compilation, there will be no generics related information stored in the bytecode.
Take a look at this:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
After type-erasure both methods will have a signature of private void add(List), which isn't allowed.
You need to either rename the methods or pass another argument like the class of the list values.