Java generics - compiler error - java

What's wrong with this method definition?
public static List<T extends MyObject> T find() {
}
Compiler says:
Syntax error, insert ";" to complete MethodDeclaration

You have two return types there.
If you wanted to introduce a generic type T that would be
public static <T extends MyObject> List<T> find() {}

The proper method declaration would be:
public static <T extends MyObject> List<T> find() { ... }
When creating (static) generic methods, the generic parameter(s) has to be defined before the return-type, because they may be used in the return-type.

Related

Unexpected behaviour with generics

I'm facing this error while work with Java generics, and I don't understand which is the problem;
I have two classes like these:
public abstract class BaseClass{
....
}
public class OneClass extends BaseClass{
....
}
I have a generic repo for OneClass:
public class MyRepo<T extends BaseClass>{
List<T> getElements();
}
Then I have a method that should works whit generics:
private MyRepo<OneClass> myRepo;
public <T extends BaseClass> List<T> myMethod(){
return myRepo.getElements();
}
The method doesn't work unless I force a cast to List ( as shown below ):
public <T extends BaseClass> List<T> myMethod(){
return (List<T>) myRepo.getElements();
}
I don't understand which is the problem given that OneClass extends BaseClass.
Thanks for any suggestion.
Having a method of the form:
<T> T myMethod()
makes the inference of the actual T dependent on the call-site:
String s = myMethod();
Integer i = myMethod();
Considering your scenario one could invoke your method like this:
List<BaseClass> a = myMethod();
List<OneClass> a = myMethod();
As you can see this can be incorrect as myMethod could actually return another subtype of BaseClass (lets say TwoClass) which is not correct to cast to List<OneClass> - thus you need the unsafe cast to List<T>.
You should change the signature of myMethod to one of the following:
public List<? extends BaseClass> myMethod(){}
public List<BaseClass> myMethod(){}
The first variant states that this is a list of any subtype of BaseClass the other just omits that information.
Dependent on what you want to achieve check the other answer or read about PECS (Producer Extends, Consumer Super) or f-bounded polymorphism / self-types to return the concrete type.
Error message tells you that not every T extends BaseClass is OneClass
You should make sure that the field myRepo is the same type as T as in your method. If you force it to be OneClass you cant use othere types except OneClass. So there is no use of a generic. If you want to allow every extending class from BaseClass you could make the class of the mehtod generic in oder to use the same type of T as shown below:
public class FunctionClass<T extends BaseClass> {
private MyRepo<T> myRepo;
public List<T> myMethod(){
return myRepo.getElements();
}
}

Bounded wildcard as a method parameter

I would like to create a method which returns type is a map object and parameter should be a class which extends A and implements I.
So my code is as follows:
public Map<String,String> getIdea(Class < ? extends A & I) { .....}
But i am getting a compilation error saying that my syntax is wrong. It is expecting a comma right after A. It does not work even with comma. Do you have any idea?
To put what Sotirios Delimanolis said in comments into code:
public <T extends A & I> Map<String, String> getIdea(Class<? extends T> clazz) { }
To be honest, I don't think that the wildcard gets you anything here since T is tightly bound, so you may be better off with the non-wildcard version.
For parameter to be a class which extends A and implements I, type parameter should be defined at method level as below:
public <T extends A & I> Map<String,String> getIdea(T t) { .....}

Generics - how to define a method that takes only classes that implement a particular interface

I've got a method that currently looks like this:
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
At the moment it can take any type of class. I want to limit that (at compile time) so that it can only allow a limited set of classes.
So I'm thinking I can define an interface like this:
public interface GettableBean<T> {}
and change the code to this (which looks horrid with a cast):
public static <T> T getBean(GettableBean<T> clazz) {
return (T) applicationContext.getBean(clazz.getClass());
}
and what's more when I try and call it using a class that implements GettableBean
public class MyClass implements GettableBean<MyClass>
I get a compile error:
Error:(119, 27) java: method getBean in class BeanLocator cannot be applied to given types;
required: GettableBean
found: java.lang.Class
reason: cannot infer type-variable(s) T
(argument mismatch; java.lang.Class cannot be converted to GettableBean)
What am I doing wrong here ?
I don't know why you think GettableBean needs to be parameterized. It's just a marker interface.
Remove the redundant generic type parameter and add a constraint to the getBean method.
public interface GettableBean {}
public class MyClass implements GettableBean {}
public static <T extends GettableBean> T getBean(Class<T> clazz) {}
The name of this parameter should have been your clue that what you were trying was not really the right approach:
public static <T> T getBean (GettableBean<T> clazz)
A GettableBean is not a class. It's an instance. It should be called gettableBean. When you rename that, it becomes more clear that you're passing an instance only pretty much immediately disregard everything about the instance.
ONE:
The error message originates in the return statement: clazz.getClass() returns a Class<?>. You try to cast it to T. To successfully do so Class would have to be an implementation or extension of T. You could declare that by
public static <T super Class<?>> T getBean(...) ...
But that's most likely not what you want.
TWO
Actually from my understanding what you want is to allow only Class parameters for implementations of GettableBean<?>. That should look like this:
public static <T> T getBean(Class<? extends GettableBean<T>> clazz) {
return applicationContext.getBean(clazz);
}

Java -- passing generic parameters

I am trying to write a method that takes in any subclass of MyInterface as a parameter, but getting syntax errors.
public Map<String, List<T extends MyInterface>> makeMap(List<T extends MyInterface>) {
Map<String, List<T extends MyInterface>> myMap = ...
return myMap;
}
This syntax is not valid. The signature gives the error "misplaced construct". But, the idea is that I can pass any subclass of MyInterface inn place of T. Can this be done in Java? how?
You are mixing up the concepts of declaring a generic type and referring to that generic type. Assuming that you want the method to be generic, declare the generic type parameter before the return type, then refer to it plainly as T elsewhere:
// Declaration ref ref
public <T extends MyInterface> Map<String, List<T>> makeMap(List<T>) {
// ref
Map<String, List<T>> myMap = ...
return myMap;
}
public <T extends MyInterface> Map<String, List<T>> makeMap(List<T> myList) {
More on generic methods here
I also noticed that in your original method declaration, you didn't have a variable defined for your method parameter.

Java generics: Declare map value of generic type

I am new to generics.
Having a Map like
private static Map<String, Object> map;
and a method like
public <T> T getObject(final Class<T> myClass) {
return (T)map.get(myClass);
}
How to change the map declaration in order to not have to do the cast when returning from the method ?
You would need to make a generic class, not a generic method:
public class MyClass<T> {
private Map<String, T> map;
public T getObject(final String key) {
return map.get(key);
}
}
Also, I changed the parameter from a Class to a String. It doesn't make sense to pass a Class if map.get() expects a String.
Edit: I didn't notice that map was static. If you can change it to non-static without it breaking other parts of your program, this could work. If you can't, then you cannot avoid a cast.
You can't avoid the cast operation as the get() method returns Object
see here for more info
If you're willing to drop the static modifier of your map, than you can do like so:
public class MyClass<T> {
private Map<String, T> map;
public T getObject(final Class<T> myClass) {
return map.get(myClass);
}
}
Otherwise:
It is a compile-time error to refer to a type parameter of a generic
class C anywhere in:
the declaration of a static member of C
(excerpt from the JLS), which prevents you from using parameterized class to achieve the above.
What you were trying to do, however, is to refer a parameterized method's type-parameter from another member (which happen to also be static), which also unreachable.

Categories

Resources