Can I store the generics attribute into an object's field - java

Assuming the following class stub:
public class Foo<T> {
private Class<T> type;
public Foo<T> () {}
}
Can I store the generic type T into the field type in the constructor, without changing the constructor's signature to "public Foo<T> (Class<T> type)"?
If yes, how? If no, why?
"type = T" doesn't seem to work.

No - type erasure means that you have to provide something at execution time. You could provide either an instance of T or Class<T> but the class itself will just have every occurrence of T replaced with Object.
This kind of thing is one of the biggest disadvantages of Java's generics vs those in .NET. (On the other hand, the variance story is stronger - if more confusing - in Java than in .NET.)

As said in this thread,
for Example List<Integer>
list.get (index).getClass()
will not give you type of object stored in list:
when the list is empty
even when the list is NOT empty, because any element can be any subclass of the generic type parameter.
Since type parameters are erased at compile time, they do not exist at runtime (sorry Jon, at execution time): Hence you cannot get generic type info via reflection in java.
There is a case for more reification which is on the table (Java 7 ?), and would facilitate what you are after.
One would hope that a bad type, casted into T, would provoke a Cast exception that would, at execution time, reveal the original type used for T, but alas, that does not work either.
Consider the following test class:
import java.util.ArrayList;
/**
* #param <T>
*/
public class StoreGerenericTypeInField<T>
{
private T myT = null;
private ArrayList<T> list = new ArrayList<T>();
private void setT(final T aT) { myT = aT; }
/**
* Attempt to do private strange initialization with T, in the hope to provoke a cast exception
*/
public StoreGerenericTypeInField()
{
StringBuilder aFirstType = new StringBuilder();
StringBuffer aSecondType = new StringBuffer();
this.list.add((T)aFirstType);
this.list.add((T)aSecondType);
System.out.println(this.list.get(0).getClass().getName());
System.out.println(this.list.get(1).getClass().getName());
setT((T)aFirstType);
System.out.println(this.myT.getClass().getName());
setT((T)aSecondType);
System.out.println(this.myT.getClass().getName());
}
/**
* #param args
*/
public static void main(String[] args)
{
StoreGerenericTypeInField<Integer> s = new StoreGerenericTypeInField<Integer>();
}
}
The constructor attempt to store nasty thing into its T variable (or its List of T)... and everything run smoothly!?
It prints:
java.lang.StringBuilder
java.lang.StringBuffer
java.lang.StringBuilder
java.lang.StringBuffer
The type erasure in in itself is not to blame... that is the combination of type erasure (new to java) and unsafe casting (java legacy old feature) which makes T truly out of reach at execution time (until you actually try to use it with 'T' specific methods)

Well, why not have an instance of T in your class? I mean what does T buy you anything if this is not the case? So if yout have T x, they you cando an x.GetType().

Does
type = T.getClass();
work?

You should try this maybe:
type = T.GetType();

Related

Why is usage of instanceof is not allowed, but Class.isInstance() is allowed in Generics?

I was reading about Generics from ThinkingInJava and found this code snippet
public class Erased<T> {
private final int SIZE = 100;
public void f(Object arg) {
if(arg instanceof T) {} // Error
T var = new T(); // Error
T[] array = new T[SIZE]; // Error
T[] array = (T)new Object[SIZE]; // Unchecked warning
}
}
I understand the concept of erasure and I know that at runtime, there is no type for T and it is actually considered an Object (or whatever the upper bound was)
However, why is it that this piece of code works
public class ClassTypeCapture<T> {
Class<T> kind;
public ClassTypeCapture(Class<T> kind) {
this.kind = kind;
}
public boolean f(Object arg) {
return kind.isInstance(arg);
}
}
Shouldn't we apply the same argument here as well that because of erasure we don't know the type of T at runtime so we can't write anything like this? Or am I missing something here?
In your example, T is indeed erased. But as you pass kind, which is the class object of the given type, it can be perfectly used for the said check.
Look what happens when you use this class:
ClassTypeCapture<String> capture = new ClassTypeCapture<>(String.class);
Here, the class object of String is passed to the given constructor, which creates a new object out of it.
During class erasure, the information that T is String is lost, but you still have
ClassTypeCapture capture = new ClassTypeCapture(String.class);
so this String.class is retained and known to the object.
The difference is that you do have a reference in the second snippet to an instance of java.lang.Class; you don't have that in the first.
Let's look at that first snippet: There is only one instance of Erased as a class. Unlike, say, C templates which look a bit like generics, where a fresh new class is generated for each new type you put in the generics, in java there's just the one Erased class. Therefore, all we know about T is what you see: It is a type variable. Its name is T. Its lower bound is 'java.lang.Object'. That's where it ends. There is no hidden field of type Class<T> hiding in there.
Now let's look at the second:
Sure, the same rule seems to apply at first, but within the context of where you run the kind.isInstance invocation, there's a variable on the stack: kind. This can be anything - with some fancy casting and ignoring of warnings you can make a new ClassTypeCapture<String>() instance, passing in Integer.class. This will compile and even run, and then likely result in all sorts of exceptions.
The compiler, just by doing some compile time lint-style checks, will really try to tell you that if you try to write such code that you shouldn't do that, but that's all that is happening here. As far as the JVM is concerned, the String in new ClassTypeCapture<String>(Integer.class) and the Integer are not related at all, except for that one compile-time check that says: The generics aren't matching up here, so I shall generate an error. Here is an example of breaking it:
ClassTypeCapture /* raw */ a = new ClassTypeCapture<Integer>(String.class);
ClassTypeCapture<Integer> b = a;
this runs, and compiles. And b's (which is the same as a's - same reference) 'kind' field is referencing String.class. The behaviour of this object's f() method is very strange.
we don't know the type of T at runtime
You're missing the point of generics: generics allow the compiler to "sanity check" the types, to make sure they're consistent.
It's tempting to read ClassTypeCapture<T> as "a ClassTypeCapture for type T", but it's not: it's a ClassTypeCapture, with a hint to the compiler to check that all of the method invocations/field accesses/return values involving that reference are consistent with the type T.
To make this more concrete (let's do it with List, that's easier):
List<String> list = new ArrayList<>();
list.add("hello");
String e = list.get(0);
the <String> is an instruction to the compiler to do this:
List list = new ArrayList();
list.add("hello"); // Make sure this argument is a `String`
String e = (String) list.get(0); // Insert a cast here to ensure we get a String out.
At runtime, the "T-ness" isn't known any more, but the ClassTypeCapture (or Object, or String, or whatever) still is. You can ask an Object if it's an instance of an Object, String, ClassTypeCapture, or whatever.
You just can't ask it if it was a ClassTypeCapture<String> at compile time, because that <String> is just a compiler hint, not part of the type.

Instantiating generic type ArrayList<T>

I am new to generics and read in a article "A parameterized type, such as ArrayList<T>, is not instantiable — we cannot create instances of them".
Full quote, from Java in a Nutshell:
A parameterized type, such as ArrayList<T>, is not instantiable - we
cannot create instances of them. This is because <T> is just a type
parameter - merely a place-holder for a genuine type. It is only when
we provide a concrete value for the type parameter, (e.g.,
ArrayList<String>), that the type becomes fully formed and we can
create objects of that type.
This poses a problem if the type that we want to work with is unknown
at compile time. Fortunately, the Java type system is able to
accommodate this concept. It does so by having an explicit concept of
the unknown type which is represented as <?>.
I understand that it should not be instantiable since the concrete (actual) type is not known. If so, why does the below code compiles without an error?
public class SampleTest {
public static <T> List<T> getList(T... elements) {
List<T> lst = new ArrayList<>(); // shouldn't this line return an error?
return lst;
}
}
I know there is a gap in my understanding of generics here. Can someone point out what am i missing here?
Because T is given as another generic type argument.
It's the whole purpose of generics to make the type parameterizeable. So the caller can specify the type. This can be done in multiple layers: the caller may also be generic and let its caller specify the type.
public static void main(String[] args)
{
foo(7);
}
public static <T> void foo(T value)
{
bar(value);
}
public static <U> void bar(U value)
{
baz(value);
}
public static <V> void baz(V value)
{
System.out.println(value.getClass().getSimpleName());
}
It prints out
Integer
A parameterized type, such as ArrayList<T>, is not instantiable
Means: You cannot create ArrayList of an unknown T. It must be specified at compile time. But it can be done indirectly, by another generic. In your case, it's another T, which will be specified again by the caller of your generic getList.
The wildcard <?> is something different. It is used to specify compatibility. <?> is the syntax to avoid specification of the type. You can use extends to require a basetype or interface. However, you cannot create instances with wildcards.
List<?> list = new ArrayList<String>();
list = new ArrayList<Integer>();
This wouldn't be possible otherwise. It makes most sense when using it in parameter specifications, for instance:
public static int foo(List<? extends Comparable> list)
{
return list.get(1).compareTo(list.get(2));
}
It's very confusing of this book. It assumes that <?> somehow solves the problem that a List with unknown T cannot be instantiated. IMHO, this is rubbish. T must be specified to create an instance.
The code that you mention can compile because the Object "lst" is not actually initialized until the method is called. Since the method knows that it will be getting a var-args argument of type T, it can compile in this scenario. Take the example Wrapper class below for example:
public class Wrapper<T> {
public static <T> List<T> getList(T... elements){
List<T> lst = new ArrayList<>();
for(T element: elements) {
lst.add(element);
}
return lst;
}
}
This code can compile because the method hasn't been called. When the method is called, Type T will be the type that we pass as the var-args argument and the code will have no issue compiling. Lets test this in our main method:
public static void main( String[] args ){
System.out.println(Wrapper.getList("Hi", "Hello", "Yo"));
}
And the output is:
[Hi, Hello, Yo]
However, lets generate a compile-time error to see what the article is talking about within our main method:
Wrapper<T> myWrap = new Wrapper<>();
We are actually trying initialize a generic Object of the Wrapper class in the code above, but is unknown. Since the value for the placeholder will be unknown even when we call the method, it results in a compile-time error, whereas creating a List of type T within the getList method does not cause a compile-time error because it will be initialized with a type when the method is called.
once you call the method -> you are using a concrete value.
the method defines T and later you use it in the return type and the parameter list.
public static <T> List<T> getList(T... elements)
once you will send the first parameter from specific type -> the contract will force you for the next parameters.
List<? extends Object> list = getList("", 1); -> in this case java doesnt find common between string and integer so it uses the most basic connection "Object"
List<String> list2 = getList("test", "test2"); -> here you can see that because all of the parameters are Strings - java find that in common and use it as the T.
The specific passage from the book doesn't make any sense and is wrong. new ArrayList<T>() is perfectly fine provided that we are in the scope of a type parameter named T (either a type parameter of a generic class that we are in, or a type parameter of the generic method we are in).
new ArrayList<T>() can no less be instantiated than new ArrayList<String>() -- both compile to the same bytecode and both just instantiate an ArrayList object at runtime. The object doesn't know anything about its type parameter at runtime, and therefore no knowledge of T at runtime is needed to instantiate it. The type parameter in an instantiation expression of a parameterized type (new ArrayList<T>) is just used by the compiler to type-check the parameters passed to the constructor (there are none in this case) and to figure out the type returned by the expression; it is not used in any other way.
And by the way the method does not need to receive any parameters of type T, or of any type containing T, in order for this to work. A method that receives no arguments can still instantiate and return an ArrayList<T> perfectly fine:
public static <T> List<T> emptyList() {
List<T> lst = new ArrayList<T>();
return lst;
}
Also, the section in the book where this statement appears in doesn't really have anything to do with instantiation -- the section is about wildcards, and wildcards don't really have anything to do with object instantiation at all. So I am not really sure why they are mentioning it (incorrectly) there.

Odd method call in java using a dot operator to access a generic list

I came across some advanced java code (advanced for me :) ) I need help understanding.
In a class there is a nested class as below:
private final class CoverageCRUDaoCallable implements
Callable<List<ClientCoverageCRU>>
{
private final long oid;
private final long sourceContextId;
private CoverageCRUDaoCallable(long oid, long sourceContextId)
{
this.oid = oid;
this.sourceContextId = sourceContextId;
}
#Override
public List<ClientCoverageCRU> call() throws Exception
{
return coverageCRUDao.getCoverageCRUData(oid, sourceContextId);
}
}
Later in the outer class, there is an instance of the callable class being created.
I have no idea what this is:
ConnectionHelper.<List<ClientCoverageCRU>> tryExecute(coverageCRUDaoCallable);
It doesn't look like java syntax to me. Could you please elaborate what's going on in this cryptic syntax? You can see it being used below in the code excerpt.
CoverageCRUDaoCallable coverageCRUDaoCallable = new CoverageCRUDaoCallable(
dalClient.getOid(), sourceContextId);
// use Connection helper to make coverageCRUDao call.
List<ClientCoverageCRU> coverageCRUList = ConnectionHelper
.<List<ClientCoverageCRU>> tryExecute(coverageCRUDaoCallable);
EDITED
added the ConnectionHelper class.
public class ConnectionHelper<T>
{
private static final Logger logger =
LoggerFactory.getLogger(ConnectionHelper.class);
private static final int CONNECTION_RETRIES = 3;
private static final int MIN_TIMEOUT = 100;
public static <T> T tryExecute(Callable<T> command)
{
T returnValue = null;
long delay = 0;
for (int retry = 0; retry < CONNECTION_RETRIES; retry++)
{
try
{
// Sleep before retry
Thread.sleep(delay);
if (retry != 0)
{
logger.info("Connection retry #"+ retry);
}
// make the actual connection call
returnValue = command.call();
break;
}
catch (Exception e)
{
Throwable cause = e.getCause();
if (retry == CONNECTION_RETRIES - 1)
{
logger.info("Connection retries have exhausted. Not trying "
+ "to connect any more.");
throw new RuntimeException(cause);
}
// Delay increased exponentially with every retry.
delay = (long) (MIN_TIMEOUT * Math.pow(2, retry));
String origCause = ExceptionUtils.getRootCauseMessage(e);
logger.info("Connection retry #" + (retry + 1)
+ " scheduled in " + delay + " msec due to "
+ origCause);
+ origCause);
}
}
return returnValue;
}
You more often think of classes as being generic, but methods can be generic too. A common example is Arrays.asList.
Most of the time, you don't have to use the syntax with angle brackets <...>, even when you're invoking a generic method, because this is the one place in which the Java compiler is actually capable of doing basic type inference in some circumstances. For example, the snippet given in the Arrays.asList documentation omits the type:
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
But it's equivalent to this version in which the generic type is given explicitly:
List<String> stooges = Arrays.<String>asList("Larry", "Moe", "Curly");
That is because, until Java 7, generics do not fully support target typing, so you need to help the compiler a little with what is called a type witness like in ConnectionHelper.<List<ClientCoverageCRU>>.
Note however that Java 8 significantly improves target typing and in your specific example the type witness is not required in Java 8.
It's ugly, but valid.
Whatever ConnectionHelper is, it has a static tryExecute method that needs to infer a generic type.
Something like:
public static <T> T tryExecute() { ... }
Edit from updated Question: Java has type inference for generic types. The first <T> in the method signature signifies the type will be inferred when the method is called.
In your updated post you show tryExecute() defined to take a generic argument:
public static <T> T tryExecute(Callable<T> command)
This actually means the use of that syntax is completely redundant and unnecessary; T (the type) is inferred from the command being passed in which has to implement Callable<T>. The method is defined to return something of the inferred type T.
Infer a type
|
v
public static <T> T tryExecute(Callable<T> command)
^ ^
| |
<-return type--------------------------
In your example, coverageCRUDaoCallable has to be implementing Callable<List<ClientCoverageCRU>> because the method is returning List<ClientCoverageCRU>
In my example above you'd have to use the syntax you were asking about because nothing is being passed in from which to infer the type. T has to be explicitly provided via using ConnectionHelper.<List<ClientCoverageCRU>>tryExecute()
From Java Generics and Collections,
List<Integer> ints = Lists.<Integer>toList(); // first example
List<Object> objs = Lists.<Object>toList(1, "two"); // second example
In the first example, without the type parameter there is too little information for
the type inference algorithm used by Sun's compiler to infer the correct type. It infers
that the argument to toList is an empty array of an arbitrary generic type rather than
an empty array of integers, and this triggers the unchecked warning described earlier.
(The Eclipse compiler uses a different inference algorithm, and compiles the same line
correctly without the explicit parameter.)
In the second example, without the type parameter there is too much
information for the type inference algorithm to infer the correct
type. You might think that Object is the only type that an integer
and a string have in common, but in fact they also both implement
the interfaces Serializable and Comparable. The type inference
algorithm cannot choose which of these three is the correct type.
In general, the following rule of thumb suffices:
In a call to a generic method, if there
are one or more arguments that correspond to a type parameter and they all have the
same type then the type parameter may be inferred; if there are no arguments that
correspond to the type parameter or the arguments belong to different subtypes of the
intended type then the type parameter must be given explicitly.
Some points for passing type parameter
When a type parameter is passed to a generic method invocation, it appears in angle
brackets to the left, just as in the method declaration.
The Java grammar requires that type parameters may appear only in method invocations that use a dotted form. Even
if the method toList is defined in the same class that invokes the code, we cannot
shorten it as follows:
List<Integer> ints = <Integer>toList(); // compile-time error
This is illegal because it will confuse the parser.
So basically, the tryExecute() method in the ConnectionHelper uses generics. This allows you to feed the type inference to it prior to the method call after the "dot operator". This is actually shown directly in the Oracle Java tutorials for Generics, even though I'd consider it bad practice in a production environment.
You can see an official example of it here.
As you can see in your modified post, the tryExecute() definition is:
public static <T> T tryExecute(Callable<T> command)
By calling it as such (<List<ClientCoverageCRU>> tryExcute), you are forcing T to be a List<ClientCoverageCRU>. A better practice in general, though, would be to let this be inferred from an actual argument in the method. The type can also be inferred from the Callable<T>, so supplying it a Callable<List<ClientCoverageCRU>> as an argument would eliminate the need for this confusing usage.
See its usage in the JLS 4.11 - Where Types Are Used:
<S> void loop(S s) { this.<S>loop(s); }
... and the formal definition of why this is allowed in method invocation in JLS 15.12 - Method Invocation Expressions. You can skip down to 15.12.2.7 and 15.12.2.8 for still more specifics. 15.12.2.8 - Inferring Unresolved Type Arguments explains the formal logic by which this functions.

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Generics in Java, using wildcards

I have a question about Generics in Java, namely using wildcards. I have an example class GenClass like this:
public class GenClass<E> {
private E var;
public void setVar(E x) {
var = x;
}
public E getVar() {
return var;
}
}
I have another simple class:
public class ExampleClass {
}
I have written the following test class:
public class TestGenClass {
public static void main(String[] str) {
ExampleClass ec = new ExampleClass();
GenClass<ExampleClass> c = new GenClass<ExampleClass>();
c.setVar(ec);
System.out.println(c.getVar()); // OUTPUT: ExampleClass#addbf1
}
}
Now, if I use a wildcard and write in the test class this:
GenClass<?> c = new GenClass<ExampleClass>();
on the place of:
GenClass<ExampleClass> c = new GenClass<ExampleClass>();
the compiler has no problem with this new statement, however, it complains about
c.setVar(ec);
It says that "the method (setVar()) is not applicable for the arguments (ExampleClass)". Why do I get this message?
I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of E I would have any class. This is just the declaration of the variable. Then I initialize it with
new GenClass<ExampleClass>()
which means that I create an object of type GenClass, which has as parameter a class of type ExampleClass. So, I think that now E in GenClass will be ExampleClass, and I would be able to use the method setVar(), giving it as argument something of type ExampleClass.
This was my assumption and understanding, but it seems that Java does not like it, and I am not right.
Any comment is appreciated, thank you.
This exact situation is covered in the Java Generics Tutorial.
Notice that [with the wildcard], we can still read elements from [the generic Collection] and give them type Object. This is always safe, since whatever the actual type of the collection, it does contain objects. It isn't safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
(emphasis mine)
mmyers has the correct answer, but I just wanted to comment on this part of your question (which sounds like your rationale for wanting to use the wildcard):
I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of E I would have any class. This is just the declaration of the variable. Then I initialize it with
If you really want to accomplish this, you could do something like without compilation errors:
GenClass<Object> gc = new GenClass<Object>();
gc.setVar(new ExampleClass());
But then again, if you want to declare an instance of GenClass that can contain any type, I'm not sure why you'd want to use generics at all - you could just use the raw class:
GenClass raw = new GenClass();
raw.setVar(new ExampleClass());
raw.setVar("this runs ok");

Categories