If you have only a Class object, how does one get a method reference to a method such as toString? Later we will have instances of this particular class on which we will invoke this method via the method reference.
For example, consider a Java enum, a subclass of Enum. Here T is defined as <T extends Enum>.
Class c = MyEnum.class
…
Function< T , String> f = c :: toString ;
I get an error saying "invalid method reference".
For toString, it's as easy as Object::toString. All Objects have toString, so you can use it right there. For other methods where you don't know statically that the object has that method, there's no easy way; you have to write a lambda that does it the ugly reflective way.
If you can access your Class object using a class literal in the form Class<MyEnum> c=MyEnum.class;, it implies that the type MyEnum is known at compile time. In this case, the Class object is an unnecessary detour. You can access all methods of the class MyEnum using the form MyEnum::methodName, e.g.
Function<MyEnum,String> f=MyEnum::toString;
This is what the tutorial describes as “Reference to an Instance Method of an Arbitrary Object of a Particular Type”. It doesn’t require an actual MyEnum instance.
Nevertheless, there is no point in dealing with MyEnum when you want to have a Function<T,…> as that function must be able to consume arbitrary instances of T, not necessarily being MyEnum. So this function can only use methods existing in T and it doesn’t need to search them in MyEnum.
Since your target method is not specific to MyEnum, that’s possible:
Function<T,String> f=T::toString;
But as already pointed out, the method toString is defined in java.lang.Object, so you may also use the form
Function<T,String> f=Object::toString;
as a method declared for all objects may also get invoked on instances of T. Though even this is a bit pointless as you can also use
Function<Object,String> f=Object::toString;
reflecting the ability to consume any instance of Object, not just T. Carefully written Generic code will always use wildcards to avoid unnecessary restrictions regarding its input. So it will accept a function which can consume T (which implies the ability to consume MyEnum) without requiring its type parameter to exactly match that type. For example:
<R> Stream<R> map(Function<? super T,? extends R> mapper)
map, applied on a Stream<T> will accept a Function<Object,…> as Object is a supertype of T…
So you can use T::methodName to access every method available for the bounds of that type, i.e. in your case you can use all methods of Enum and, of course, Object, but no methods specific to MyEnum not present in its supertypes. This isn’t different to ordinary method invocations you try to apply on instances of T. Further, a method not present in T wouldn’t be eligible for creating a valid Function<T,…> anyway.
If you want to create Function instances for methods not known at compile-time, you will have to use Reflection, and this is the only case where you have to deal with Class objects (in the context of method references). The second example of this answer shows how to create a Function for an instance method returning an object but that’s really only for those who know precisely what they are doing…
Note also that such reflectively created Functions have to use raw types as their appropriate generic type can’t be declared as it would refer to a type not present at compile-time.
What you are trying here, is to get the reference of toString() for the class Class, which is probably not what you intended. As toString() is defined for all objects, this should work (not tested):
Function< T , String> f = t -> t.toString();
Related
I know Java's constructors can't have any type and interestingly it cannot even be void. A logical explanation for that would be that a constructor returns the initialized object's reference.
MyClass myObject = new MyClass();
The constructor of myClass will now return the object reference after instantiating it and save it in the object variable MyObject and that's why the constructor can't have a return type.
Is that right? Could someone confirm this?
No, actually, the constructors are compiled into the class file like methods having the name <init> and a void return type. You can see these "<init>" invocations in stack traces. The expression new Type() is compiled as an instruction new which just creates the instance of Type and an additional method invokation (invokespecial) to one of the constructors declared in Type.
The verifier will ensure that such a special method is invoked at exactly once on a newly created instance and that it is called before any other use of the object.
It’s just a programming language design decision to let constructors have no return type from the Java language point of view. After all, new Type(…) is an expression that evaluates to the newly created instance of Type and you can’t get a return value from the constructor with that programming language construct. Further, if you add a return type, Java will unconditionally assume that it is a method, even if it has the same name as the class.
That’s simply how it was defined: (It makes parsing the class definition easier)
The SimpleTypeName in the ConstructorDeclarator must be the simple name of the class that contains the constructor declaration, or a compile-time error occurs.
In all other respects, a constructor declaration looks just like a method declaration that has no result (§8.4.5).
I suppose you could say that constructors have a "special syntax" used specifically for returning instances of the desired object. You do not specify the return type in these cases. The new keyword is used together with the constructor method to produce an instance of the class type.
If you'd like to control the return type of an instance generation method, then you should probably be looking at using a type of factory design pattern, wherein a static method creates an instance (using a constructor), and then returns a more explicit type (say for example, the super type, or an interface type).
This pattern is good when you'd like to decide which type to return based on some parameter, but leave the actual type hidden to the consumer of the instance generation method.
A constructor is not a methed. It does not return anything. It is used for initialization purposes, especially useful when those initializations depend on parameters or there is a chance that exceptions will be thrown (though both are optional).
So, unlike a method, it is not inherited and does not have a return type (not even void).
The idea is that you are "constructing" an instance of MyClass by calling the constructor itself. The idea of the constructor is to instantiate and not to return. Having created myObject you can then refer to public methods and variables part of its declaration which will provide you with the required data being returned as an answer to a call. It is important to understand that the constructor does not return anything it simply creates an instance which can then be used to refer to methods and variables (which return data) declared within the instantiated class.
Methods that are generic using the T parameter can for sure be handy. However, I am curious what the use of a generic method would be if you pass an argument such as Class<T> clazz to the method. I've come up with a case that maybe could be an possible use. Perhaps you only want to run a part of the method based on the type of class. For example:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* #return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
Is this an accepted practice? When is the Class<T> clazz argument useful with generic methods?
Is this an accepted practice?
Well, to me.. no not really. To me, it seems somewhat pointless when you can simply define some boundaries on the type of T. For example:
private static <T extends House> void load(Collection<T> t)
This will guarantee that either the object is of type House or of a subclass of House, but then again if you only want an instance of type House or it's subclasses, it should really just be:
private static void load(Collection<House> houses)
The idea of generics is to make a method or a class more malleable and extensible, so to me it seems counter-intuitive to start comparing class types in the method body, when the very notion of generics is to abstract away from such details.
I'd only pass class objects if the generic type could not be derived otherwise. In your case, the compiler should be able to infer T from the collection. To treat specific objects differently, I'd use polymorphism - e.g. House#something() and Other#something(), and just call anyObject.something().
I think it is acceptable but if it can be avoided then you should. Typically, if you can have different methods which accepts different type, then do it instead of one method which uses if clauses to do something different depending on the type of the parameter. You could also delegates to the class the operation you want to make specific for a given type.
In your case, you could simply test the type of each element of the collection using instanceof, to do what you need for the specific type. But it won't work if the list is empty.
A typical use is if you need to get the type to create it and you can find it from another way. For instance, Spring uses it to load a bean from its name:
<T> T getBean(Class<T> requiredType)
In that case, it cannot be avoided (without having to cast).
If the returned value or other parameters types are dependent or need to be equal, generics will add compile time checks, so that there's no need to cast to T.
Examples
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
Raw types
It is still possible to defer a casting error until runtime (ClassCastException) with some casts, e.g. with implicit casts from non-generic (raw) types to generic ones:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
The compiler will generate a bunch of warnings, unless you suppress them with annotations or compiler settings.
Compiler Settings (Eclipse):
For example, the usage of raw types generates a warning per default, one can treat warnings as errors and even as fatal errors:
You would pass a Class<T> argument in generics if, and only if, you would pass a Class argument before generics. In other words, only if the Class object is used in some way. Generics serves as a compile-time type checking tool. However, what arguments you pass should be determined by the runtime logic of the program, and should be irrelevant of generics.
I haven't seen passing a Class object in order to check the runtime type of an object as a common use case for generics. If you're doing that, there's a good chance that there's a better way to set up your class structure.
What I have seen is if you need to create a new instance of the class in question, or otherwise use reflection. In that case you do have to pass the Class object, because Java cannot derive it at runtime thanks to type erasure.
In your case actually having the Generic parameter is not strictly needed.
Since the output of the function you are describing does not depend on the type of the input you might as well use wild cards.
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
The only time you should use generic parameter is when the type of the result of a function will be dependent of the type of the parameters.
You will need to pass the Class corresponding to the type when your code will need it; most of the time this happens when:
- You need to cast/type check objects to T
- There is serialization/deserialization involved.
- You cannot access any instance of T in your function and you cannot call the getClass() method when you need it.
Passing a Class on every generic function will result in you passing an unnecessary parameter most of the time, which is regarded as bad practice.
I answered a similar discussion in the past:
When to use generic methods and when to use wild-card?
Enum is in the java.lang.Enum, and Object is in the java.lang.Object. So, why is Enum not an Object? (I am getting a java.lang.ClassCastException)
I want to make a class that can accept both Object and Enum, like this...
public class MyType<T extends Enum<T>, Object> {
But this gives a compilation error. How can i make my MyType so that it can accept all (or both) type of classes? (Enum or Object)?
Since every Java object is instanceof Object, there is nothing better to do than declare MyType<?> with no bounds. That will capture any type, including an enum type.
An Enum is an Object. See http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Enum.html
So
MyType<Object> {
should work.
You can see on documentation:
Excepting Object, which has no superclass, every class has one and
only one direct superclass (single inheritance). In the absence of any
other explicit superclass, every class is implicitly a subclass of
Object.
You can conclude:
even not explicit your class will extends from Object;
if Object was a figured manner to represent other class, you will not be able since java doesn't support multiple-inheritance.
Simply by looking at the API for class object, you can read:
Class Object is the root of the class hierarchy. Every class has Object as a superclass.
All objects, including arrays, implement the methods of this class.
This means that Enum is an object (you can verify this by looking at the JavaDocs for Enum aswell). Hence, if you simply tell MyType to contain Object(MyType<Object>), it will accept Object and Enum as you originally posted.
Although notice that this might cause unwanted behavior and is considered unsafe, since ALL classes are objects.
I don't think you've stated your question correctly. I think you want your class to accept Enum or Object. When you put it like that you can see that is the only possible choice.
If you want it to accept Enum and Object, that is equivalent to saying 'accept Enum'. In which case > is the answer.
I have a method which returns a complex generic type (which implements multiple interfaces)
protected abstract <BOB extends Stan & Jan<I>> BOB getStanAndJanItem();
This compiles fine, and i'm able to override it and return values. As soon as i call it i get compilation errors though (it doesn't even have to be assigned to anything). And i guess this makes sense, since BOB is only defined inside the method.
So, how do i define bob at a class level?
And YES, I know i can just split up the calls and have them return the same object, or introduce some additional inheritance (and i'll probably end up doing that) but can it be done this way as well?
Error Received:
Bound mismatch: The generic method getStanAndJanItem() of type MyAbstractClass<I> is not applicable for the arguments (). The inferred type Stan is not a valid substitute for the bounded parameter <BOB extends Stan & Jan<I>>
In order to call the method, you need to pass a generic type parameter that matches your constraint.
Even if your particular call doesn't need it, you still need to pass the type parameter.
Therefore, you can only call the method if you parameterize it with some class or interface that implements both of those types.
The real problem is the lack of support of intersection type. Suppose language support it directly, we can write intersection type like A&B etc, and your example would be like
Stan&Jan<I> getStanAndJanItem()
void setStanAndJanItem(Stan&Jan<I> item)
Stan&Jan<I> result = getStanAndJanItem();
result.doStanStuff();
result.doJanStuff();
setStanAndJanItem(result);
Without such support, we are stuck. Your generic declaration is probably wrong: it implies that the caller decides the BOB type, while you probably want the implementation to decide the BOB type. The implementation can return anything that implements both Stan and Jan<I>. Currently, that requirement cannot be expressed.
Most of the documentation regarding type erasure handling in Java assumes that the use case is handling a type like SomeType<ParamType>.
I am trying to process method parameter for the following method:
public void setOtherReferenceRanges(List<ReferenceRange<T>> referenceRanges)
When the container class is instantiated with a type DvQuantity, this signature should become
public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges) in runtime.
Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T>. Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity>.
However, when I created the class containing this method, I passed the DvQuantity type as T. So the type filling in T should be available to Java runtime, but I could not find a way of getting it. I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data.
Can you think of any ways to discover this information in runtime?
When you say
when I created the class containing this method
I guess you mean when you create an object of that type, for example:
foo = new ContainerClass<DvQuantity>();
In that case, because of erasure, there is no way to recover the type DvQuantity.
However, if you create a class passing a type parameter to the superclass, like this
class DvQuantityContainerClass extends ContainerClass<DvQuantity> {...}
...
foo = new DvQuantityContainerClass();
Or, shorter, an inline anonymous subclass (which looks almost like the first example but with a subtle but important difference):
foo = new ContainerClass<DvQuantity>(){};
Then you can recover the type parameter, because you recover the type parameter used to extend a superclass at runtime. Unfortunately, Java itself doesn't provide an easy way to now get the type of the DvQuantityContainerClass.setOtherReferenceRanges method with the T filled in. For that, I've written gentyref, to do advanced reflection on generic types:
Method m = DvQuantityContainerClass.class.getMethod("setOtherReferenceRanges", List.class);
// this will return List<ReferenceRange<DvQuanity>>, like you are lookingn for
return GenericTypeReflector.getExactParameterTypes(m, DvQuantityContainerClass.class)
Generic type information is erased by the compiler and is not available at runtime. When I need to ensure a certain type at runtime I pass in a class argument:
public <T> void doSomething(T t, Class<T> c);
This is not always convenient or even possible, but for many cases it is possible.
So the type filling in T should be available to Java runtime, but I could not find a way of getting it.
Perhaps it's not entirely correct, but the way I think about it is that at runtime there is no actual class - just an object without a specific type which meets the interface of T. In other words, erasure happens not with objects, but instead with these nebulous (in the OOP world at least) type-things.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
There are ways of capturing the type information inside the class itself (T types would need a method getUnderlyingType()... or something), but that's a bad idea. If you truly need to raw type of the object, I'd reconsider using generics.