In Java, I can do that:
class JavaClass<A, B>{
A first;
B second;
}
And then declare an array, a list, or a single object of that type, without supplying generic parameters. They're being automatically converted to Object's, like in an example below:
JavaClass someArray = new JavaClass[4];
Now, the type of someArray[0].first is Object.
In C#, it doesn't seem to work:
class Leaderboard<UserType, UIEntry>
where UserType : User
where UIEntry : UserUIEntry{}
And the declaration:
Leaderboard someLeaderboard = new Leaderboard();
Gives:
Using the generic type Leaderboard requires two type arguments.
Is there any equivalent to make this work and allow me to declare that?
First of all, generics in C# and Java are very different, both conceptually and implementation-wise. C# has so-called reified generics, while Java uses type erasure. Therefore, looking for similarities between these two languages in generics is usually not a good idea.
In C#, Leaderboard and Leaderboard<UserType, UIEntry> are two distinct types. If you really want to, you can write
class Leaderboard<UserType, UIEntry>
where UserType : User
where UIEntry : UserUIEntry{}
class Leaderboard : Leaderboard<User, UserUIEntry>{}
and then use just new Leadeboard() (relying on inheritance). However, I wouldn’t think this is an especially great idea, trading a few keystrokes for worse readability.
Look how e.g. Tuple does it: Tuple is a nongeneric helper for the generic Tuple<...> class, containing a static .Create function which helps with type inference, reducing the need to write the generic parameters explicitly.
Related
I am currently studying Java and have recently been stumped by angle brackets(<>). What exactly do they mean?
public class Pool<T>{
public interface PoolFactory<T>{
public T createObject();
}
this.freeObjects = new ArrayList<T>(maxsize)
}
What does the <T> mean? Does it means that I can create an object of type T?
<T> is a generic and can usually be read as "of type T". It depends on the type to the left of the <> what it actually means.
I don't know what a Pool or PoolFactory is, but you also mention ArrayList<T>, which is a standard Java class, so I'll talk to that.
Usually, you won't see "T" in there, you'll see another type. So if you see ArrayList<Integer> for example, that means "An ArrayList of Integers." Many classes use generics to constrain the type of the elements in a container, for example. Another example is HashMap<String, Integer>, which means "a map with String keys and Integer values."
Your Pool example is a bit different, because there you are defining a class. So in that case, you are creating a class that somebody else could instantiate with a particular type in place of T. For example, I could create an object of type Pool<String> using your class definition. That would mean two things:
My Pool<String> would have an interface PoolFactory<String> with a createObject method that returns Strings.
Internally, the Pool<String> would contain an ArrayList of Strings.
This is great news, because at another time, I could come along and create a Pool<Integer> which would use the same code, but have Integer wherever you see T in the source.
It's really simple. It's a new feature introduced in J2SE 5. Specifying angular brackets after the class name means you are creating a temporary data type which can hold any type of data.
Example:
class A<T>{
T obj;
void add(T obj){
this.obj=obj;
}
T get(){
return obj;
}
}
public class generics {
static<E> void print(E[] elements){
for(E element:elements){
System.out.println(element);
}
}
public static void main(String[] args) {
A<String> obj=new A<String>();
A<Integer> obj1=new A<Integer>();
obj.add("hello");
obj1.add(6);
System.out.println(obj.get());
System.out.println(obj1.get());
Integer[] arr={1,3,5,7};
print(arr);
}
}
Instead of <T>, you can actually write anything and it will work the same way. Try writing <ABC> in place of <T>.
This is just for convenience:
<T> is referred to as any type
<E> as element type
<N> as number type
<V> as value
<K> as key
But you can name it anything you want, it doesn't really matter.
Moreover, Integer, String, Boolean etc are wrapper classes of Java which help in checking of types during compilation. For example, in the above code, obj is of type String, so you can't add any other type to it (try obj.add(1), it will cast an error). Similarly, obj1 is of the Integer type, you can't add any other type to it (try obj1.add("hello"), error will be there).
It is related to generics in java. If I mentioned ArrayList<String> that means I can add only String type object to that ArrayList.
The two major benefits of generics in Java are:
Reducing the number of casts in your program, thus reducing the number of potential bugs in your program.
Improving code clarity
is called a generic type. You can instantiate an object Pool like this:
PoolFactory<Integer> pool = new Pool<Integer>();
The generic parameter can only be a reference type. So you can't use primitive types like int or double or char or other primitive types.
<> is used to indicate generics in Java.
T is a type parameter in this example. And no: instantiating is one of the few things that you can't do with T.
Apart from the tutorial linked above Angelika Langers Generics FAQ is a great resource on the topic.
Generic classes are a type of class that takes in a data type as a parameter when it's created. This type parameter is specified using angle brackets and the type can change each time a new instance of the class is instantiated. For instance, let's create an ArrayList for Employee objects and another for Company objects
ArrayList<Employee> employees = new ArrayList<Employee>();
ArrayList<Company> companies = new ArrayList<Company>();
You'll notice that we're using the same ArrayList class to create both lists and we pass in the Employee or Company type using angle brackets. Having one generic class be able to handle multiple types of data cuts down on having a lot of classes that perform similar tasks.
Generics also help to cut down on bugs by giving everything a strong type which helps the compiler point out errors. By specifying a type for ArrayList, the compiler will throw an error if you try to add an Employee to the Company list or vice versa.
I would like to request for an item class of collection (kind of specific reflection). But regarding to type erasure it seems not possible and also regarding to some topics I've read here on stack. There are some workarounds (here), but I'm curious if somebody know how is it done for example by DWR:
http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/signatures.html
or in case that there is some better workaround it would be great.
Let's say we have something like:
public String foo(List<String> possibleFoos) {
and all I need to is find out that parameter possibleFoos is list of Strings, not just List
While it's true that Java will erase types at runtime (thus turning List<String> into just List), in many cases it actually does store the generic type in runtime allowing you to restore the information lost to erasure.
You can retrieve the actual generic types for these:
Method arguments (your case)
Method return types
Field types
Super classes/interfaces
This means if you simply have an object of type List, there's nothing you can do to get it's generic type (object.getClass() will get you List and that's it) - it's been permanently lost. But, if you're trying to figure out the generic type for a method argument or any of the above, you usually can by using reflection. As your case doesn't involve type variables or other complications, it's pretty straightforward to get the actual type:
ParameterizedType listArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", List.class).getGenericParameterTypes()[0];
Type listType = listArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the List
If you had a more parameters and a map instead:
public String foo(Object bar, Map<String, Number> possibleFoos) { ... }
The code would be similar:
ParameterizedType mapArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", Object.class, Map.class).getGenericParameterTypes()[1]; //1 is the index of the map argument
Type keyType = mapArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the Map key
Type valType = mapArgument.getActualTypeArguments()[1]; //This will be a Class representing Number, the type of the Map value
It's safe to assume this is what DWR is using as well, as the types are method arguments.
Similar methods are available for other listed cases:
Class.getMethod(...).getGenericReturnType() will get you the real return type
Class.getField(fieldName).getGenericType() will get you the real type of the field
Class.getGenericSuperClass() will get you the real super type
Class.getGenericInterfaces() will get you the real interface types
Equivalent methods exist allowing access to AnnotatedType (generic type plus annotations on the type usage) introduced in Java 8:
Class.getMethod(...).getAnnotatedParameterTypes()
Class.getMethod(...).getAnnotatedReturnType()
Class.getField(fieldName).getAnnotatedType()
Class.getAnnotatedSuperClass()
Class.getAnnotatedInterfaces()
Now, this is all dandy when your case as simple as in the example.
But, imagine if your example looked like this:
public T foo(List<T> possibleFoos) {...}
In this case, getGenericParameterTypes()[0].getActualTypeArguments()[0] would give you T which is rather useless. To resolve what T stands for, you'd have to look into the class definition, and perhaps super classes, while keeping track of how the type variables are named in each class, as the names could be different in each.
To make working with generic type reflection easier, you can use a wonderful library called GenTyRef that does the hard work for you, and if you need support for AnnotatedTypes, you can use my fork called GeAnTyRef (both are in Maven Central). They also include a type factory, that allows you to construct instances of (Annotated)Type, which you can not easily do using normal Java API. There's also a handy super type token implementation allowing you to get an (Annotated)Type literal.
With those, you can do everything with generic types that Java allows without the hassle I explained above:
GenericTypeReflector#getExactParameterTypes( ... )
GenericTypeReflector#getExactReturnType( ... )
GenericTypeReflector#getExactFieldType( ... )
GenericTypeReflector#getExactSuperType( ... )
And many more operations, like figuring out if one Type is a super type of another (similar to Class#isAssignableFrom but for generic types), resolving specific type variables etc.
Is it possible to create class, where e.g. second parameter is value?
Constructor would look something like this:
FancyClass<Integer, 1> myFancyClass = new FancyClass<>();
No. Generics are for types not for literal values.
I don't know what you're trying to do, but if there's some actual idea behind your code, you could easily implement it with
public class FancyClass<T> {
T myVal;
public FancyClass(T val) {
myVal = val;
}
}
FancyClass<Integer> myFancyClass = new FancyClass<>(1);
No. There's no logic in doing so anyway. From wikipedia:
Generics are a facility of generic programming that were added to the Java programming language in 2004 within J2SE 5.0. They allow a type or method to operate on objects of various types while providing compile-time type safety.
A small example:
The class Lunchbox represents a lunch box, which inside of it it's seperated into 2 different containers. Each "container" within the lunchbox can contain a bunch of items, but those items can be only of one (same) type.
Without generics, we would have to predefine 2 types for both sides of the containers. But lets say we wanted to do it so each Lunchbox can have different types of items. That's when we need generics:
public class Lunchbox<V1, V2>
Now inside the LunchBox class (and only inside the LunchBox class) you can access two types: V1 and V2. They're handeled like normal classes.
V1 objectOfTypeV1 = ...; //I can even declare variables with that type.
Now we can create lunchboxes of many kinds:
Lunchbox<String, Integer> lunchbox1 = new Lunchbox<>();//Contains strings and integers
Lunchbox<Foo, Bar> lunchbox2 = new Lunchbox<>();//Contains Foos and Bars
LunchBox<LunchBox<Foo, Bar>, Integer> lunchbox3 = new LunchBox<>(); //Contains lunchboxes (containing Foos and bars) and integers
For your question: If we were to put a value as a generic class, it wouldn't make any sense. Lets continue with the Lunchbox class - How can our lunchbox hold a type 1, when there is no such thing? You can't declare...
1 object = new 1();
That's not a class. That's a value. I don't understand why you'd want to put a value in a generic, and it doesn't make sense. Hope I helped.
Just in case you didn't understand anything from this, here's a link to Oracle where they have a lesson about generics, why to use them: Click here.
Why use generics? -Oracle
I have this code, which compiles:
new TypeToken<ArrayList<ServerTask>>() {}.getType()
Then I have tried
ArrayList<ServerTask>.class
which does not compile.
I am new to Java programming (came from C#) and I have thought that T.class is an exact equivalent of typeof(T) in C#. Apparently there is something really basic that I do not understand, so my question is what is wrong with ArrayList<ServerTask>.class and do I have no choice, but use new TypeToken<ArrayList<ServerTask>>() {}.getType() instead? Is there a shorter (nicer, saner) form?
Thanks.
Unfortunately (?) Java implements generics using Type Erasure.
This means that there is no construct to get the generic type, and at runtime your ArrayList actually only stores Objects.
To be exact, Generics in Java are a compile-time only construct. They guarantee type-safety at compile time only.
EDIT:
I just noticed this bit of code -
new TypeToken<ArrayList<ServerTask>>() {}.getType()
This is a workaround for the limitations of type erasure. Type information is preserved if you extend a generic class with a specific type. For example:
public interface List<T> {
}
public class StringList implements List<String> {
// The bytecode of this class contains type information.
}
In your example, you are trivially extending the class TypeToken, causing the compiler to generate an anonymous inner class that contains the type information. The implementation of TypeToken.getType() will use reflection to give you this type information.
EDIT2: For a more detailed explanation, have a look at Reflecting Generics.
Your first code sample creates an anonymous subclass of TypeToken complete with concrete generic bindings. The type returned will be an instance of Class. But beware, because
(new TypeToken<ArrayList<ServerTask>>() {}.getType()).getClass(TypeToken.class)
will return false!
In your second code sample, you're trying to do something that Java doesn't support because of how generics are implemented with type erasure. There is no class that represents an ArrayList whose generic parameter is bound...from the compiler's point of view an ArrayList is an ArrayList regardless of the generic type, so the expression doesn't compile.
It's possible that neither piece of code is going to work out quite right. If you need to be playing around classes with generic parameters, you may want to look into gentyref, which I've found to be very helpful in simplifying the API to ask the kinds of questions you're trying to get answers to.
About the ".class" construct, it is not an operator nor an instance member, it is actually a way to tell the language "go and find the Class object for this class name before the dot". Is a way of constructing class literals.
As specified in the JLE, section 15.8.2, the compiler will complain if you try to use it with a parameterized type (among others).
The example given by Bringer128 is considered an anti-pattern called pseudo-typedef antipattern.Here is the alternative:
class TokenUtil{
public static <T> TypeToken<T> newTypeToken(){
return new TypeToken<T>();
}
public static void main(String[] args) {
TypeToken<ArrayList<ServerTask>> typeTok = TokenUtil.newTypeToken();
Type type = typeTok.getType();
}
}
I have a legacy class that the class itself is not a generic but one of its methods return type uses generics:
public class Thing {
public Collection<String> getStuff() { ... }
}
getStuff() uses generics to return a collection of strings. Therefore I can iterate over getStuff() and there's no need to cast the elements to a String:
Thing t = new Thing();
for (String s: t.getStuff()) // valid
{ ... }
However, if I change Thing itself to be a generic but keep everything else the same:
public class Thing<T> {
public Collection<String> getStuff() { ... }
}
and then keep using the non-generic reference to Thing, getStuff() no longer returns Collection<String> and instead returns a non-typed Collection. Thus the client code does not compile:
Thing t = new Thing();
for (String s: t.getStuff()) // compiler complains that Object can't be cast to String
{ ... }
Why is this? What are the workarounds?
My guess is that by using a non-generic reference to a generic class, Java turns off all generics for the entire class. This is pain, because now I've broken my client code by making Thing a generic.
Edit: I'm making Thing generic for another method which is not listed in the above example code. My question is educational as to why the above cannot be done.
Ok, take two, I misunderstood your question.
When you delcare Thing (this is called a raw type) instead of Thing<?> (parameterized type) the Java compiler strips out all generic arguments, even thogh (as in your case) the generic type of the method has nothing to do with the generic type of the class.
From the (excellent) Java Generics FAQ:
Can I use a raw type like any other type?
Methods or constructors of a raw type have the signature that they would have after type erasure.
This seemingly inocuous and unobtrusive sentence describes the behaviour in question. You're using Thing as a raw type so the return type is Collection (not Collection<String>) since this is the type after type erasure.
Confused? Not surprising. Just look at the size of that FAQ. There's probably about three people on earth who nderstand the full implications of Java Generics. Just consider my favourite declaration from the JDK:
Enum<T extends Enum<T>>
(Theres an explanation of that in the FAQ too).
It is failing because of erasure. You can read more about it in these Java Tutorials
I think this is totally normal. In my opinion using Thing t = new Thing(); for generic enabled class is totally a mistake. When compiler see a generic class used as a class without type parameter, it think it must erase all generic types from that class. This is how you can compile old codes without use of generics in new java compilers and compiler let that old codes use generic enabled classes (e.g. java.util.ArrayList) without any problem. (and this is how java not need separated System.Collection.Generic.List and System.Collection.List like C#). You can run Thing t = new Thing(); with adding a simple type parameter on it, Thing<Object> t = new Thing<Object>();, only thing java compiler needs is making sure that you are using java generic consciously. I never can blame Java for its great backward compatibility.
I know I am a bit late :D