<T> T getInstance (final class <T>) why class <T> for both?
So, I am delving into Java and am interested in this use of parameters of this type.
<T>T getInstance
and then arg
Class<T> type
I'm a little confused here, because if we want a return type denoted like this T, then why not the same arg ... for example
private static String getInstance(String arg)
So I would understand that it would be
private static Class<T> getInstance(final Class<T> type)
So, I'm confused as to why the difference in an expression like return vs. argument
source to share
It is not necessary to have a return type the same as the type of the parameter, and in no way implies that this is a rule.
When the method is defined as
private static <T> T getInstance(final Class<T> type)
this means that the returned object will be of type T
, whereas the argument passed to this method is an instance of the typical type java.lang.Class
parameterized before T
.
This means that the method can be called like this:
String string = getInstance(String.class);
Therefore, this method takes an instance of the type Class
and returns an object of the type that matches this argument Class
.
On the other hand, when the method is defined as
private static <T> T getInstance(final T type)
then you need to pass an object of the type T
to get an instance. Imagine it will be called like this:
String string = getInstance("a");
Note that object "a" of type String
differs from String.class
type Class
.
source to share
T
and Class<T>
completely different.
The first says: "an object of some type, T." The second says: "A type object java.lang.Class
that represents a class for some type T
."
In other words, here are two possible implementations:
Class<T> getInstance(Class<T> type) {
return type;
}
T getInstance(Class<T> type) {
return type.newInstance();
}
For example, if it T
is String
, then the first one will return String.class
, and the second one will return an empty string ""
.
source to share
Think about what this method does: it returns instance
from Class
.
Using:
final String string = getInstance(String.class);
So what is the comeback - well it is String
. And what is the argument - it class String
is which is presented Class<String>
.
Thus, the method signature becomes:
String getInstance(Class<String> string);
Parameterizing String
as T
gives you the signature in your question.
source to share
This is a trick that Java implemented to combat the chicken-and-egg problem where you have to create an object inside a generic type erasable method.
Class<T>
is made generic so that you can call it getInstance
type safe. Without <T>
in Class
all yours T
will be erased, leaving you with
Object getInstance() {...}
and has no way to get a reference to the class T
that was removed.
Transmit Class<T>
solves this problem because now the erased signature looks like this:
Object getInstance(Class cl) {...}
Although the type is erased again, you now have an object Class
that can be used as a "factory" to create new objects of the class T
. The fact that it Class<T>
is generic to the type it creates allows the Java compiler to do type checking, ensuring that a cast implicitly injected by the compiler will succeed at runtime.
source to share
You must distinguish the class from your instance. This can be tricky because in Java, classes are also objects and therefore they also have a class (class class!). Say:
class Foo { ... }
- The Foo instance is of type Foo;
- The class itself
Foo
is an instance (only) of another class, exactlyClass<Foo>
.
So in the above description from left to right:
-
<T>
- a general parameter, which makes a method a general method; -
T
- this is the return type: the method returns an instance of the classT
; -
getInstance
is the name of the method; -
Class<T>
means that you must pass as a parameter an instance (only) of the classT
that the class itself hasClass<Foo>
.
You can access this singleton instance using an implicit static field Foo.class
. Every class declared has one, although you won't find it in the source code (tricky reflection issues).
Finally, why Class
is it common? Well, to have something like this:
package java.lang;
public final class Class<T> {
public static T newInstance();
...
}
so it Foo.class.newInstance()
returns a Foo
, Baz.class.newInstance()
returns a Baz
and so on. Gently, right?
source to share