I would like to write a generic method that takes a bounded parameter that extends Enum. For example, if I have an Enum as follows:
public enum InputFlags{
ONE (0000001),
TWO (0000002),
THREE (00000004);
public final int value;
InputFlags(int value){
this.value = value;
}
}
I can then do the following:
for (InputFlags ifg : InputFlags.values()){
// Do something with ifg
}
However if I try to do the above in a generic method whose return parameter is bounded, I cannot access the values() method:
public static <T extends Enum> T getFlags(int f){
T.values(); // NOT allowed, even though I have bounded by extending Enum.
}
It seems as though I cannot access values() in the generic method. Is this a peculiarity of Enums or is there a way round this?
values() is a very strange thing in Java. Look in the documentation for Enum - values() isn't even there! values() is not a method of Enum at all. Instead a static method called values() is implicitly added to every class extending Enum. But the values() method for one enum is different from the values() method in another enum.
The fact that T extends Enum means that if t has type T you can call instance methods from Enum on t. You can't call static methods of Enum (and even if you could, values() doesn't exist anyway!)
values() is only useful when you know the actual enum by name. It cannot be used when you only have a type parameter T.
The way around this problem is to pass a Class object. Like this:
public static <T extends Enum<T>> T getFlags(Class<T> clazz, int f){
T[] array = clazz.getEnumConstants(); // This is how you can get an array.
Set<T> set = EnumSet.allOf(clazz); // This is how you can get a Set.
}
values() is a static method inserted by the compiler in the InputFlags class. Thus, it is not possible to use T.values(), especially since T is a generic type. However, if you can get the Class object of T (usually via getClass(), or by passing it to getFlags(int f, Class<T> clazz)), you can use Class#getEnumConstants() on that object.
This is a peculiarity of static methods. There is no way in Java, with generics or otherwise, to define an interface that applies to static methods, ie. that a class should/must implement a static method.
Also, type erasure (among other things) prevents you from using a type variable T as a type name in a static method invocation expression.
Related
Suppose I have two methods:
public Set<String> method1()
public List<String> method2()
How do I make a generic method off this? Specifically, I'm looking to genericize the "Set" and "List".
Here's an attempt that didn't work:
public static <T extends Collection> T<String> genericMethod
It's showing a compiler error: Type "T" does not have type parameters.
As far as the signature goes, it would be
public static <T extends Collection<String>> T genericMethod() {
...
}
Presumably, genericMethod is going to create an instance of T at some point and return that, rather than just returning null (that wouldn't be very useful, would it?), but there is no guarantee that T has any constructors at all. And due to type erasure, the runtime wouldn't know what type to create anyway. To work around this, the method would also need to accept a parameter that tells it how to create a T:
public static <T extends Collection<String>> T genericMethod(Supplier<? extends T> tSupplier) {
...
}
Now, rather than saying new T(), which is invalid, you do tSupplier.get() to get a T.
If the caller wants a Set<String>, for example, they would do:
Set<String> set = genericMethod(HashSet::new);
Note that the specific implementation of the collection is now specified by the caller, rather than hidden as an implementation detail of genericMethod. This is inevitable, as the specific type of collection (T) is now unknown to genericMethod.
Hello I try pass to interface as parameter Enum object, and after this parse him to List<Enum> in body default function interface. So my interface looks like below
public interface SpecificObject<T extends Enum<T>>{
default List<Enum> asMyList(){
List<Enum> list = Arrays.asList(T.values()); // not works
return list;
}
}
After this I have a plane use in this way
class SomeObject implements SpecificObject<MyEnum>{
public SomeObject()
// dont' must Overwrite because I use as default
}
And somewhere in code usage, just as below
SpecificObject specificObject = new someObject SomeObject();
List<Enum> list = someObject.asMyList();
Is it possible in JAVA 8?
Step-by-step:
public static <T extends Enum<T>> List<T> getEnumConstants(T object) {
assert object != null;
Class<T> type = object.getClass();
T[] constants = type.getEnumConstants();
return Arrays.asList(constants);
}
Not tested, but this looks workable. The List is however as inflexible as the original T[].
Packing the function in an interface as default method will not bring any advantage.
Note Class.getEnumConstants is not typed for Enum, and will yield null for non-enums.
(When staying in one specific Enum, EnumSet (a kind of bitset) and EnumMap (a kind of array) is often quite efficient and fast.)
I am looking at the Java API from Oracle, particularly at this method that is part of the java.util.Arrays class:
public static <T> List<T> asList(T... a)
But how is it possible that this method is returning a List object when clearly it is an interface?
It is called polymorphism
It means you can refer to a subtype using supertype reference
In this case, the method is returning instances of class that implement the List interface
Source code of Arrays.asList method
public static <T> List<T> More ...asList(T... a) {
return new ArrayList<T>(a);
}
Any method that has an interface type as its return type actually returns an instance of some class that implements that interface. The point of having an interface type as the return type is allowing the developer of the method to change the implementation that the method returns without changing the API.
In the case of Arrays.asList, an instance of Arrays$ArrayList (a nested class inside the Arrays class) is returned.
Method will return the child class object. Check the source code of java
public static <T> List<T> More ...asList(T... a) {
return new ArrayList<T>(a);
}
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Arrays.java#Arrays.asList%28java.lang.Object%5B%5D%29
Read the polymorphism as well
http://www.tutorialspoint.com/java/java_polymorphism.htm
It is returning a reference to any instance of List. Now, any class that implements the List interface is also a List. example ArrayList is a List.
That being said, the method returns an instance of a List.
Note that the list instance returned cannot be cast explicitly to java.util.ArrayList, the actual instance returned is of type Arrays$ArrayList
So, I am delving into Java and curious about this type parameter usage.
<T>T getInstance
and then the arg
Class<T> type
I am a little confused here because if we require a return type, thus denoted by T then why isn't the arg the same... for instance
private static String getInstance(String arg)
So I'd figure it would be
private static Class<T> getInstance(final Class<T> type)
so, I am confused why the difference in expression of return type vs. argument
There is no need to have the return type the same as the parameter type and by no means any rule that dictates that.
When a method is defined as
private static <T> T getInstance(final Class<T> type)
it means that the return object will be of type T, whereas the argument passed to the method is an instance of the generic java.lang.Class type parameterized to T.
This means the method may be invoked as follows:
String string = getInstance(String.class);
Hence this method takes an instance of type Class and returns an object of the type corresponding to this Class argument.
On the other hand, when the method is defined as
private static <T> T getInstance(final T type)
then you are forced to pass an object of type T in order to get the instance. Imagine it will be called as follows:
String string = getInstance("a");
Notice how the object "a" of type String is quite different than String.class of type Class.
T and Class<T> are totally different.
The first says, "an object of some type, T." The second says, "an object of type java.lang.Class, which represents the class for some type T."
Put another way, here are two possible implementations:
Class<T> getInstance(Class<T> type) {
return type;
}
T getInstance(Class<T> type) {
return type.newInstance();
}
For instance, if T is a String, then the first of those will return String.class, and the second will return an empty string, "".
Think of what the method does: it returns an instance from a Class.
Usage:
final String string = getInstance(String.class);
So what is the return - well it's String. And what is the argument - it's the class String, which is represented by Class<String>.
So the method signature becomes:
String getInstance(Class<String> string);
Parameterising out the String as T gives you the signature in your question.
This is a trick that Java has implemented to combat the chicken-and-egg problem when you must create an object inside a type-erased generic method.
Class<T> is made generic so that you could call getInstance in a type-safe manner. Without <T> in the Class all of your Ts would get erased, leaving you with
Object getInstance() {...}
and no way to get a reference of the class T, which has been erased.
Passing Class<T> solves this problem, because now the erased signature looks like this:
Object getInstance(Class cl) {...}
Although the type is erased again, now you have a Class object, which can be used as a "factory" to make new objects of class T. The fact that Class<T> is generic on the type that it creates lets Java compiler perform type checking, ensuring that the cast inserted implicitly by the compiler is going to succeed at runtime.
You should distinguish a class from its instance. It can be tricky because in Java classes are also objects, and as such they also have a class (the class of the class!). Say:
class Foo { ... }
An instance of Foo has type Foo;
The class Foo itself is the (only) instance of another class, precisely Class<Foo>.
So in the above declaration, from left to right:
<T> is the generic parameter, making the method a generic method;
T is the return type: The method returns an instance of class T;
getInstance is the name of the method;
Class<T> means that you must pass as parameter the (only) instance of the class T, that itself has class Class<Foo>.
You can access such singleton instance by the implicit static field Foo.class. Every declared class has it, although you will not find it in the source code (tricky reflection issues).
Finally, why Class is generic? Well, to have something like that:
package java.lang;
public final class Class<T> {
public static T newInstance();
...
}
so Foo.class.newInstance() returns a Foo, Baz.class.newInstance() returns a Baz, and so on. Neat, isn't it?
I learned java generics some time ago, but now I'm learning collections and found some code that I don't understand. Here is the code:
static <E> List<E> nCopies(int n, E value)
It is from class java.util.Collections.
My question is why there is:
<E> List<E>
and not only
List<E>
Obviously I am missing something, can someone clarify this for me?
You use the <E> to typify the method you are defining.
The most common example of generics is to have a typified class like this:
public class SomeClass<E> {
...
}
Then, when you are creating a new object of that class you define the type directly like this:
new SomeClass<String>();
That way any method in that class that refers to <E>, will treat <E> as a String, for that instance.
Now consider a static method (which is not bound to any particular instance of a class), in order to typify that method you have use another kind of typification which applies to methods, like this:
static <E> List<E> nCopies(int n, E value)
You use the <E> before the return type to say "this particular method will consider some E when it executes". What <E> will be is decided when you invoke the method:
nCopies(3, "a");
In this example <E> will be a String, so the return type will be a List<String>.
Finally, you can even mix them both:
public class SomeClass<E> {
public <F> void doSomething(E e, F f) {
...
}
}
In this case, if you have an instance of SomeClass, the E in the doSomething method will always be String (for that instance), but the F can be anything you want it to be.
In <E> List<E>, the first <E> denotes that E is a type parameter. If you hadn't specified it, then Java would think the E in E value referred to an actual class named E, and ask you to import it. See generic methods.
The <E> is required to tell the compiler that you intend to use E as a type parameter, the same way you do when you make a generic class (e.g. public interface List<E>).
Since there is no rule (only conventions) on interface or class names being more than one character, and no rule (only conventions) that type parameter names have to be one character, the compiler would not know you intended it to be a type parameter rather than a concrete class name.
Edit
A lot of people have been saying this is directly related to static methods. That is not true. You can have an instance method that is generic on its own type parameters as well (though typically, the type parameters will be related to the class type parameters).
Here's an example of where you could have this:
public class MyList<E> {
public <N super E> MyList<N> createCopy() {
//...
}
}
This method would allow you to create a copy of the list but not restrain you to using the same type as the list you have, but rather allowing you to use a supertype. For example:
MyList<Integer> integers = createList(1, 2, 5);
MyList<Number> numbers = integers.createCopy();
List<E> is the return type for the method whereas <E> is the type being passed in (This is inferred by the compiler from what is being passed as E value).
static <E> List<E> someMethod(E myObject)
{
E objectOfMyType = myObject;
List<E> myList = new ArrayList<E>();
...
return myList;
}
This would be called as:
MyObject o = new MyObject();
List<MyObject> myList = SomeClass.someMethod(o);
IMHO the syntax for methods is kinda goofy, but there you have it. The relavent Oracle tutorial is here:
http://download.oracle.com/javase/tutorial/extra/generics/methods.html
in simple words: to indicate that E is not a class. List<E> would be a valid return type if E was a class (or interface) - despite not recommended, a class can be named with a single letter (as a type variable also could be named with more letters, even using an existing class name, to confuse anyone: static <Integer> List<Integer> method() {...}).