What does the first part in the following method definition?
<I, O> MyReturnType<I, O> myMethod() { ... }
The second is the method'sreturn type, third is the method name, but what is the first one?
I and O are declared as generic type parameters. They're generic types introduced by the method itself, as said here: https://docs.oracle.com/javase/tutorial/java/generics/methods.html
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
If you don't declare <I, O>, java will look for types called I and O (which won't be there, since they're supposed to be generic).
I think #khelwood put it nicely (see comments on original question): It's saying: "In the following definition, I and O are standing in for some types that depend on the situation when the method is called."
Related
I was reading Effective Java chapter 5 about generics, in particular the items on preferring generic methods. I noticed that sometimes the type parameter(between angle brackets) in the method declaration before the return type is sometimes omitted. There are many cases like that, but for example on page 135 of the second edition:
public void popAll(Collection<E> dst) {
while (!isEmpty())
dst.add(pop());
}
On the other hand, I have seen similar generic methods with the declaration
public <E> void ...
Is the first one a typo? If not when can I omit the brackets from the declaration?
Thanks
E is a type variable -- it stands in for some other type, like String or Integer. So just as you can't understand dst.add(pop()) without knowing where and how dst was defined, you can't understand a method declaration like popAll(Collection<E> dst) without knowing where and how the type variable E is defined. In the case of popAll, the type variable E is defined at the class level: Stack<E>: it's the type of the elements in the stack. You'll often even see it javadoc'd:
/**A Stack of elements
*
*#param E The type of elements in the stack */
public class Stack<E>{
public void popAll(Collection<E> dst){ ... }
}
On the other hand, when you see a method declaration like public <E> void ..., the type variable E is being declared (not referenced from some enclosing scope like the enclosing class). In fact most times when you see a method with its own type variable, it's a static method, so there is no enclosing instance of the class to establish the value of E.
In both cases, what is the E type variable doing? It's telling us how two different types have to relate to each other. In popAll, it's telling us that the element type of the collection you want to put the popped elements into has to match the element type of the stack you're popping them from.
Similarly, take the example from page 136:
public class ListUtils{
public static <E> E reduce(List<E> list, Function<E> f, E initVal);
}
Here, the E type variable tells us that the element type of list has to match the argument type of f and the type of initVal. The surrounding class does not define E for us, it's only meaningful in the scope of the reduce method declaration.
The difference is that in the first case the whole class is declared generic whereas in the second case only the method is generic.
The answer is... it's not. A "generic method" is defined to be one that declares type variables before the return type:
A method is generic if it declares one or more type variables. (JLS 8.4.4)
Therefore, popAll is not a "generic method".
Since the method does not declare the type parameter E, it must be defined in an enclosing scope; almost certainly by the class (a "generic class") that contains the method.
I have come across a very strange compilation error. At first I thought it was a bug in IntelliJ, but now I've tried with Eclipse and see the same thing.
I have the following interface:
public interface PluginDriver<T extends Plugin> {
PluginBuilder<T> getBuilder();
Set<PluginParam> getParams();
Set<String> getStrings();
}
where Plugin is an abstract class:
public abstract class Plugin
and we also have a POJO as follows:
public class PluginParam { ... }
Now I have a DriverManager to return an instance of a PluginDriver, and here I will try to use that:
PluginDriver driver = DriverManager.getDriver(transformer.getPlugin());
PluginBuilder builder = driver.getBuilder();
for (PluginParam o : driver.getParams()) {
//type mismatch - cannot convert from element type Object to PluginParam
}
for (String s : driver.getStrings()) {
//type mismatch: cannot convert from element type Object to String
}
The for loop commands don't compile, for reasons that I don't understand. The interface specifies concrete return types for those methods, not type T.
Now, if I change the following line:
PluginDriver<Plugin> driver = DriverManager.getDriver(transformer.getPlugin());
everything suddenly plays nicely.
Similarly, if I remove the type arguments from the interface, it will work.
I could understand that the getBuilder() method might not work if we hadn't correctly typed the PluginDriver.
But how could it possibly complain about the getStrings() method?
==EDIT
This is not a duplicate of Combining Raw Types and Generic Methods, since that question refers to a method with typed parameters. The method I'm asking about is untyped.
The JLS says,
"The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C."
http://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8
When you declared a variable of the raw interface type, you forced the member methods to have raw types also. That's what screwed up the class cast.
The documentation rules.
Here:
PluginDriver driver = DriverManager.getDriver(transformer.getPlugin());
You are creating a raw type. Bad idea.
Can lead to all sorts of problems - see here.
Thus the answer is simple: never do that! When you are using generic types, then make sure that you have a "generic" on (one/both) sides of your declaration/definition!
I have seen some code like this and unable to understand its significance:
public class ClassA{
public <T> void getContactName(ContactList<T> contactList){
//do something
}
}
Basically I didn't understand this. The class compiles without any error. I thought ClassA should also be made generic with parameter 'T' .
Thanks
The definition
public <T> void getContactName(ContactList<T> contactList){
//do something
}
means that only the method is generic and the type with a name T is valid only in the scope of the method. There's no need the class to be generic if the T type parameter is used only in a single method.
As a side note, remember that in Java you can make generic:
classes (except the anonymous ones)
methods
interfaces
but you can't make generic:
exceptions
anonymous classes
enums
It's better explained under Java Tutorial on Generic Methods and Generic Types along with detail examples and uses of generic methods.
here is an example (build-in Arrays class). Have a look at the method signature that ensures that method return type is exactly same as method arguments since class itself is not generic but you can make method as generic.
class Arrays {
public static <T> List<T> asList(T... a) {
...
}
You can create static generic utility methods as mentioned above where you don't need to create object of the class.
According to Java Language Specification:
A type variable is an unqualified identifier. Type variables are
introduced by generic class declarations, generic interface
declarations, generic method declarations, and by generic constructor
declarations.
A class is generic if it declares one or more type variables. These
type variables are known as the type parameters of the class. It
defines one or more type variables that act as parameters. A generic
class declaration defines a set of parameterized types, one for each
possible invocation of the type parameter section. All of these
parameterized types share the same class at runtime.
An interface is generic if it declares one or more type variables.
These type variables are known as the type parameters of the
interface. It defines one or more type variables that act as
parameters. A generic interface declaration defines a set of types,
one for each possible invocation of the type parameter section. All
parameterized types share the same interface at runtime.
A method is generic if it declares one or more type variables. These
type variables are known as the formal type parameters of the method.
The form of the formal type parameter list is identical to a type
parameter list of a class or interface.
A constructor can be declared as generic, independently of whether
the class that the constructor is declared in is itself generic. A
constructor is generic if it declares one or more type variables.
These type variables are known as the formal type parameters of the
constructor. The form of the formal type parameter list is identical
to a type parameter list of a generic class or interface.
You can use your method like this:
new ClassA().<String>getContactName(contactList);
or you can not specify the type parameter
new ClassA().getContactName(contactList);
You can read specification for further details and good faq you can find here
I was reading about Set interface from here which the code sipped below which is a generic method that removes duplicates from a collection.
My question is what is that **< E>** placed after static before Set<E> ?
I mean wouldn't that Set<E> be enough ? why <E> was there twice?
public static <E> Set<E> removeDups(Collection<E> c) {
return new LinkedHashSet<E>(c);
}
Here **<E>** is a generic type. Generic type is defined as
A generic type is a generic class or interface that is parameterized
over types. The following Box class will be modified to demonstrate
the concept. LINK
And regarding you question related to <E>. A good description for it can be found on the same tutorial
Type Parameter Naming Conventions
By convention, type parameter names are single, uppercase letters.
This stands in sharp contrast to the variable naming conventions that
you already know about, and with good reason: Without this convention,
it would be difficult to tell the difference between a type variable
and an ordinary class or interface name.
The most commonly used type parameter names are:
E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
You'll see these names used throughout the Java SE API and the rest of
this lesson.
This means that this method declares a generic parameter type which the class does not define; in this case, you MUST declare the parameter type before the return type (even if this "return type" is void).
Think about it this way. Remove the initial <E>. Your declaration would then become:
public static Set<E> removeDups(Collection<E> c)
What is E here? Unless it is a generic parameter type defined by the class itself, it can only be an existing class.
Hence this syntax. It allows you to define a generic parameter for use in the method signature.
It's just the generic type used within the method. Static methods that use generic types must specify that type before the return type.
Example:
interface S {}
interface SS extends S {}
abstract class A<T extends S> {
T get() {…}
}
abstract class B<BT extends SS> extends A<BT> {}
Why does ((B)someInstanceOfB).get() return an object of type S (and we should cast it to SS manually), when the compiler could determine that returned object is at least of type SS?
Why doesn't the compiler make implicit class cast to have clearer code? The code is of version 1.5+ and this is not secret for compiler. (Solved)
Update: Why doesn't the compiler compile B class as it implicitly has method BT get() { return super.get(); } ?
Is this problem solved in Java 1.7+?
By casting to B you're using a raw type.
Using a raw type removes all generic information from the object, no matter where it is.
That means that for the raw type B the get method looks like it is returning a S (because that's the erasure (i.e. the actual type used at runtime) of the type parameter T).
To avoid this, never use raw types! They are meant exclusively for backwards compatibility and interaction with legacy code.
Cast to B<? extends SS> instead.
And no: this problem will probably never be "solved" in any future version of Java, as it's non-existing when you use generics correctly.
Regarding Update: no, B does not have a method BT get(). It has a method T get() where T is bound to the type parameter BT which has a lower bound SS. But since all generic type information is discarded when you use a raw type, T will still fall back to the original erasure, which is S.
The rule is quite simple and basically says "when you use a raw type it acts as if the class has no generics at all". The implications, however, are not always obvious, as in this case.
You didn't parameterize your instance of B.
Let's say you have the class C implementing SS:
Then, new B<C>().get(); would return an object of type C.
On the new B().get(); line, your IDE must have told you "B is a raw type. References to generic type B should be parameterized.".