I have the following classes:
public class Obj<T> extends BaseModel {
public static final String OBJECT = "object";
public Obj(T object) {
setObject(object);
}
public T getObject() {
return get(OBJECT);
}
public void setObject(T object) {
set(OBJECT, object);
}
}
And...
/** This is a 3rd party library class **/
public class BaseModel implements ModelData, Serializable {
//...members and stuff...
#SuppressWarnings({"unchecked", "rawtypes"})
public <X> X get(String property) {
X obj = null;
if (start > -1 && end > -1) {
Object o = map.get(property.substring(0, start));
String p = property.substring(start + 1, end);
if (o instanceof Object[]) {
obj = (X) ((Object[]) o)[Integer.valueOf(p)];
} else if (o instanceof List) {
obj = (X) ((List) o).get(Integer.valueOf(p));
} else if (o instanceof Map) {
obj = (X) ((Map) o).get(p);
}
} else {
obj = (X) map.get(property);
}
return obj;
}
}
When I compile, I get the following error.
type parameters of <X>X cannot be determined; no unique maximal instance exists for type variable X with upper bounds T,java.lang.Object -> getObject()
It doesn't happen in Eclipse, which, as far as I can tell, is using the same JDK as my Ant build. I've seen the SO thread about the Sun compiler issue, but that seemed to be for static methods declaring types on the fly.
Why am I getting this error, and more importantly, how do I get around it?
So far the only why I've found is to cast in my method like this:
#SuppressWarnings({"unchecked"})
public T getObject() {
return (T) get(OBJECT); //yuck
}
Telling my I'm on crack and this is the proper way is acceptable.
This is dummy bug that has been fixed in Java SE 7.
It does not compile because your code expects too much from generics -> i.e., the < X > X part in:
public <X> X get(String property) { ... }
In the following code:
public T getObject() {
return get(OBJECT);
}
you have to keep in mind that generics are always "unfolded" before the compiler actually starts to compile the Java code. It is a pre-processing step.
In your case, the compiler does not know what to use to replace X at compile time. The compiler needs to be sure about the type of X, because it needs to check it against T to validate the code. Hence the error...
A solution to your issue is to replace < X > X with Object:
public Object get(String property) { ... }
and add a cast in:
public T getObject() {
return (T) get(OBJECT);
}
Your will get an unchecked-cast warning at compile time, but your code will compile (so yes your workaround is valid).
Method type parameters are most often implicitly inferred from the arguments to that method. Note, however, get has no explicit relationship between the argument and the type parameter:
public <X> X get(String property)
Type inference is the usual path, but methods can also be invoked with explicit type arguments, just like classes. The format roughly follows that of the declaration, so inside of Obj you could have
public T getObject() {
return super.<T>get(OBJECT);
}
You could also just be direct and use <Object>, but you'd still have to use that unchecked cast to get it back to T. Note the explicit argument needs a qualifier, usually the instance name of the class. Since your example used a method of the superclass, its reference is implicit through super.
This doesn't solve the underlying problem of applying a generic method (<X> X get) inside of a non-generic class (BaseModel). Note the code in the library makes forcible type casts to the type argument. This style is indeed one of the solutions to back-porting generic features into non-generic Java code. It looks like they're trying to hide this from the library users, but since they didn't genericize the class the type can't be inferred from the instance (i.e. you really want to have Obj<T> extends BaseModel<T>).
[EDIT: corrected and explained explicit method type argument]
I just encountered a similar issue with a project using Apache Pivot. The client code was riddled with lines like:
boolean foo = org.apache.pivot.json.JSON.get(item, "foo");
The code would compile in Eclipse, but not using Maven or javac from the command line. It appears to be Bug 6302954, but I still see it after updating to the latest JDK.
As the JSON class is provided by Pivot, it's not something I could modify within my own source tree (forking the library is not an option on this project)
The solution that worked for me came from the first reply in the bug report, changing the code to read:
boolean foo = org.apache.pivot.json.JSON.<Boolean>get(item, "foo");
Related
< T > T foo(P p) {
...
}
I'll get different types of return from foo according to the parameter I inserted, which means T changes according to p.
Then I try to call this function and use its return result.
Class x = foo(p);
What should I write in substitute of Class here?
Suppose parameter is a enum type.
enum P {
XX,YY,ZZ
}
then the return type T is Xx, Yy, Zz respectively according to parameter.
Let me give the exact sample here.
public <T> List<T> getProperty(Property property) {
switch(property) {
case NAME: List<Name> names = new ArrayList<Name>();
names.add(this.name); return (List<T>) names;
case PHONE: return (List<T>) this.phones;
case EMAIL: return (List<T>) this.emails;
case ADDRESS: return (List<T>) this.addresses;
case NOTE: List<Note> notes = new ArrayList<Note>();
notes.add(this.note); return (List<T>) this.note;
default: return null;
}
}
public enum Property {
NAME, PHONE, EMAIL, ADDRESS, NOTE
}
public List<Entry> search(Property property, String s) {
if(this.isEmpty()) {
return null;
}
List<Entry> result = new ArrayList<Entry>();
for(Entry e : entries) {
if(e.getProperty(property) != null) {
for( **Object** p : e.getProperty(property)) { //What should I write instead of Object
if(p != null) {
if(p.containString(s)) { //there'll be errors if use Object. Need to know p's class.
result.add(e);
}
}
}
}
}
return this.nonDuplicatedResult(result);
}
I'm really not sure what you're asking. You haven't explained your use cases at all and haven't given us much code to look at. It's difficult to provide useful feedback from within the fog of obfuscation.
Generally speaking, if you want a method that returns a different object depending on the value of a supplied argument, then what you're probably talking about is a static factory method which can return any object that is a subtype of the method's return type. It is convenient to make such objects a part of an interface-based type system (eg. the static factories for the EnumSet class).
The use of an interface-based type system is actually necessary if you wish to return an enum, because enums cannot be part of a class hierarchy, but they can implement an interface that forms an interface-based type system.
Suppose parameter is a enum type.
enum P {
XX,YY,ZZ
}
then the return type T is Xx, Yy, Zz respectively according to parameter.
No it isn't. The return type is P. You're over-thinking this. The 'enum' case isn't a job for Generics at all.
Assuming you have an finite number of return types, you could just check through each one using instanceof to see if the returned value is of a certain type. So in this case Object would substitute class, then you could later cast it.
What is happening is basically with that method definition, what you are saying to the compiler is that your method will return whatever the parameter assignment declares itself to be. You can do that, but how your method is implemented will boil down to a compiler warning, as you can't actually ensure that you are generating the appropriate type - since you don't know it, it is never passed to the method, and erased at compile time.
More typically what you would do is:
<T extends P> T foo(T p) {
...
}
Now you get an object of the right type as a parameter, so you have some idea of what to return. That concept has little utility with enums, though.
Here is a real world example of where you could use the method definition you posed in your question:
public static <T> T generateProxy(Object realObject, Class<?>... interfaces) {
return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
}
Of course such a method generates a compiler warning. Now, what you are saying here is that the caller will define a variable, and will be sure to pass in at least one interface of the type they define. If they don't, they will end up with a ClassCastException at runtime, but you avoid calling code that knows what it is doing from explicitly casting.
It is debatable if that is a good idea.
So the short answer is that you can define the Class to be whatever you want - the compiler will accept anything - but if the method doesn't return the correct type, you will get an exception at runtime, so it is all about how you implement the method. Rarely can a method be smart enough to return the right thing without the correct type as a parameter. And if you can't pass in an appropriate parameter declared with the generic type to the method, you will have to deal with a compiler warning in order to return anything (other than null).
I have a method foo
void foo (String x) { ... }
void foo (Integer x) { ... }
and I want to call it from a method which does not care about the argument:
void bar (Iterable i) {
...
for (Object x : i) foo(x); // this is the only time i is used
...
}
the code above complains that that foo(Object) is not defined and when I add
void foo (Object x) { throw new Exception; }
then bar(Iterable<String>) calls that instead of foo(String) and throws the exception.
How do I avoid having two textually identical definitions of bar(Iterable<String>) and bar(Iterable<Integer>)?
I thought I would be able to get away with something like
<T> void bar (Iterable<T> i) {
...
for (T x : i) foo(x); // this is the only time i is used
...
}
but then I get cannot find foo(T) error.
The problem you are facing is that overloaded methods are bound at compile time. In your example, the compiler tries to figure out which of the foo() methods to call. However, the strongest static type of x in your example is Object, and there is not method foo(Object), so the compiler says it can't call the appropriate method.
If you add the foo(Object) method, no matter what the actual runtime type of x is, you will always call the foo(Object) method.
This problem extends to using generics. Since T can be any type, you must have a generic method foo(T) or your code will not compile. However, if you add that method, you lose the ability to have these methods discern between the different argument types, because only foo(T) will be called.
The only way to work around this is by doing a case by case check and cast like the other answers proposed. Unless the argument types are classes you define and they can all implement a common interface. Then you can do something like:
interface ArgumentType {
void callback(FooClass c);
}
class YourClassA implements ArgumentType {
void callback( FooClass c ) {
c.foo( this );
}
}
FooClass would still have to have a foo() method for every implementing class of ArgumentType, but this way you can have your selection by type agnostic.
Think of it this way: which version of foo should be called if x is an Object?
That's the problem faced by the JVM.
If you want a truly polymorphic method, then you need to explicitly write one. Such a method could then inspect the Object through introspection to see what it's actual class type is and call the appropriate method after that.
Or, you could take a close look at what foo does. Is it only calling methods defined by Object? If so, just create a void foo(Object x) method that does the necessaries.
The trouble is you are trying to find foo(Object x) and while String and Integer are both Objects, not all Objects are either String or Integer, and java doesn't narrowcast to the right class.
I would perhaps suggest creating a method like:
void foo(Object o){
if ( o instanceof String){
String s = (String) o;
//Deal with s
} else if ( o instanceof Integer){
Integer i = (Integer) o;
//Deal with i
}
}
Also, if you are using generics anyway, you shouldn't be passing a raw iterator in bar
I was wondering what is the difference between the following two method declarations:
public Object doSomething(Object obj) {....}
public <T> T doSomething(T t) {....}
Is there something you can/would do with one but not the other? I could not find this question elsewhere on this site.
Isolated from context - no difference. On both t and obj you can invoke only the methods of Object.
But with context - if you have a generic class:
MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();
Then:
Foo newFoo = my.doSomething(foo);
Same code with object
Foo newFoo = (Foo) my.doSomething(foo);
Two advantages:
no need of casting (the compiler hides this from you)
compile time safety that works. If the Object version is used, you won't be sure that the method always returns Foo. If it returns Bar, you'll have a ClassCastException, at runtime.
The difference here is that in the first, we specify that the caller must pass an Object instance (any class), and it will get back another Object (any class, not necessarily of the same type).
In the second, the type returned will be the same type as that given when the class was defined.
Example ex = new Example<Integer>();
Here we specify what type T will be which allows us to enforce more constraints on a class or method. For example we can instantiate a LinkedList<Integer> or LinkedList<Example> and we know that when we call one of these methods, we'll get back an Integer or Example instance.
The main goal here is that the calling code can specify what type of objects a class will operate upon, instead of relying on type-casting to enforce this.
See Java Generics* from Oracle.
*Updated Link.
The difference is that with generic methods I don't need to cast and I get a compilation error when I do wrong:
public class App {
public static void main(String[] args) {
String s = process("vv");
String b = process(new Object()); // Compilation error
}
public static <T> T process(T val) {
return val;
}
}
Using object I always need to cast and I don't get any errors when I do wrong:
public class App {
public static void main(String[] args) {
String s = (String)process("vv");
String b = (String)process(new Object());
}
public static Object process(Object val) {
return val;
}
}
You don't need to do additional class casting. In first case you will always get an object of class java.lang.Object which you will need to cast to your class. In second case T will be replaced with the class defined in generic signature and no class casting will be needed.
At runtime, nothing. But at compile time the second will do type checking to make sure the type of the parameter and the type of the return value match (or are subtypes of) whatever type T resolves to (the first example also does type checking but every object is a subtype of Object so every type will be accepted).
T is a generic type. Meaning it can be substituted by any qualifying object at runtime. You may invoke such a method as follows:
String response = doSomething("hello world");
OR
MyObject response = doSomething(new MyObject());
OR
Integer response = doSomething(31);
As you can see, there is polymorphism here.
But if it is declared to return Object, you can't do this unless you type cast things.
in the first case it takes a parameter of any type e.g.string and return a type foo. In the second case it takes a parameter of type foo and returns an object of type foo.
There are few reasons that you can consider Generics over Object type in Java:
Generics is flexible and safe. At the same time, working with Object that requires type-casting is error-prone
Type Casting in Java is slow
ref : [1]: https://www.infoworld.com/article/2076555/java-performance-programming--part-2--the-cost-of-casting.html
I still have trouble with some corner cases in the java generics system.
I have this method (I'm only interested in the signature) :
interface Extractor<RETURN_TYPE> {
public <U extends Enum<U>> RETURN_TYPE extractEnum(final Class<U> enumType);
}
(think about an interface whose implementations sometimes extracts an EnumSet sometimes an implementation extract a JComboBox etc.)
and I want to call it with a class obtained at runtime, so I simply call it this way :
public static <RETURN_TYPE> RETURN_TYPE extractField(final Extractor<RETURN_TYPE> extractor, final Field field) {
final Class<?> type = field.getType();
if (type.isEnum())
return extractor.extractEnum(/* error here*/type.asSubclass(Enum.class));
throw new RuntimeException("the rest of the visitor is not necessary here");
}
and I get a strange error message :
incompatible types
found : java.lang.Object
required: RETURN_TYPE
the location of the message if just after the opening braket of the call, before the "t" of type.
if I call it from a non-generic context, it works :
Integer extractField(final Extractor<Integer> extractor, final Field field) {
final Class<?> type = field.getType();
if (type.isEnum())
return extractor.extractEnum(type.asSubclass(Enum.class));
throw new RuntimeException("the rest of the visitor is not necessary here");
}
Does anybody have an explanation and a solution to this problem please ?
Here is a complete file for people wanting to play with it :
public class Blah {
interface Extractor<RETURN_TYPE> {
public <U extends Enum<U>> RETURN_TYPE extractEnum(final Class<U> enumType);
}
public static <RETURN_TYPE> RETURN_TYPE extractField(final Extractor<RETURN_TYPE> extractor, final Field field) {
final Class<?> type = field.getType();
if (type.isEnum())
return extractor.extractEnum(/* error here*/type.asSubclass(Enum.class));
throw new RuntimeException("the rest of the visitor is not necessary here");
}
public static Integer extractField(final Extractor<Integer> extractor, final Field field) {
final Class<?> type = field.getType();
if (type.isEnum())
return extractor.extractEnum(type.asSubclass(Enum.class));
throw new RuntimeException("the rest of the visitor is not necessary here");
}
}
thanks in advance,
Nico
I would not be surprised if this is a bug in your compiler, actually. Through serious use of generics (the kind of thing you're doing, combining parameterised methods, bounded wildcards and other "advanced" uses of generics) I've encountered two or three issues in the last year in javac (annoyingly, the same unit often compiled fine in the IDE).
In your case I'm fairly sure it's a bug, since the part that the compiler is complaining about is that extractor.extractEnum is returning an Object rather than a RETURN_TYPE. And regardless of what crazy inference it does with your enum method arguments... it knows from the type signature that the Extractor is an Extractor<RETURN_TYPE>, so you should always be able to say return extractor.extractEnum(...);.
The damning evidence is that even if you call the method with a null argument (thus completely removing any potential complications from the enum generics in the argument), the compiler still complains. In particular, it now says that it thinks the return type from the Extractor is U<RETURN_TYPE> which is clearly rubbish.
In general the solution to working around these issues is throwing in some explicit casts. Is the compiler happy if you cast the output of extractEnum to RETURN_TYPE? Edit: no, it's really not - it complains that U<RETURN_TYPE> and RETURN_TYPE are inconvertible - eep...
If you're using a recent 1.6 compiler, I suggest you report this to Sun as this is quite a big problem with javac. Here's a very short test case that exercises it:
public class Test {
interface Sub<O> {
public <I extends Enum<I>> O method(final Class<I> enumType);
}
public static <O> O go(final Sub<O> sub) {
return sub.method(null);
}
}
P.S. it's general convention to use a single uppercase letter to designate generic type parameters. I'm not going to say "I'm right, you're wrong", but bear in mind that I found your code much harder to read and follow than if you had used Extractor instead. (And judging by Hemal's phrasing of his answer it's the same for him too.)
I haven't been able to infer the original problem.
Am I correct that Extractor.extract has two type parameters, U which must be an Enum and T which is an arbitrary type? In the generic call, VV is both T and U? If U is VV than the parameter has to be Class<VV>, not Class<Enum>. The following compiles for me, but as you can see the generic method needs to be provides instance of Class<VV>
class Outer {
static class Extractor<T> {
public <U extends Enum<U>> T extract(final Class<U> lala) {
return null;
}
// two type parameters, T and U
// U must be an enum
// T is arbitrary class
}
static <VV extends Enum<VV>> VV extract(final Extractor<VV> extractor, Class<VV> vvClass) {
final Class<?> type = null;
return extractor.extract(vvClass);
// Outer.extract returns VV
// T -> VV
// it seems VV is also U
}
}
Looks like your Field.getType( ) will only return a generic Class. Because you will try to put a type with already erased type information this function will have to emit an "unchecked" warning, and ALL type information on generic interface WILL get erased.
Remember, that with type erasure your interface looks like this:
interface Extractor {
public Object extractEnum( final Class enumType );
}
So, because all type information is erased, the return type of extractEnum is java.lang.Object, so you have to add a specific cast. And this is precisely the error message that you've got.
Here is the modified example of your code.
#SuppressWarnings( "unchecked" )
public static <RETURN_TYPE> RETURN_TYPE extractField(
final Extractor<RETURN_TYPE> extractor,
final Field field
)
{
final Class type = field.getType(); // unchecked
if (type.isEnum())
{
// needs cast
return (RETURN_TYPE) extractor.extractEnum( type ); // unchecked
}
throw new RuntimeException("the rest of the visitor is not necessary here");
}
DISREGARD THIS COMMENT: To answher the original question on why you have a compile error. This is a square peg into a round hole kind of problem. type.asSubclass( Enum.class ) returns Class< ? extends Enum >, it is still not the same as Class< U > which the interface call expects.
I stumbled upon a function looking like this:
public void function(Class<?> clazz) {...}
What are the pros/cons of changing the method to:
public <T> void function(Class<T> clazz) {...}
edit: what are the compile time / runtime diff.
todd.run is totally right on, but that's only half the answer. There are also use cases for choosing <T> over <?> (or vice versa) that apply when you don't add type parameter to the class that encloses the method. For example, consider the difference between
public <E extends JLabel> boolean add(List<E> j) {
boolean t = true;
for (JLabel b : j) {
if (b instanceof JLabel) {
t = t && labels.add(b);
}
}
return t;
}
and
public boolean add(List<? extends JLabel> j) {
boolean t = true;
for (JLabel b : j) {
if (b instanceof JLabel) {
t = t && labels.add(b);
}
}
return t;
}
The first method will actually not compile UNLESS you add an appropriate type parameter to the enclosing class, whereas the second method WILL compile regardless of whether the enclosing class has a type parameter. If you do not use <?>, then you are locally responsible for telling the compiler how to acquire the type that will be filled in by the letter used in its place. You frequently encounter this problem - needing to use ? rather than T - when attempting to write generic methods that use or need "extends" and "super." A better but more elaborate treatment of this issue is on page 18 of Gilad Bracha's Generics Tutorial (PDF). Also see this stack overflow question whose answer illuminates these issues.
Check out this stack overflow link for information about your second question: Java generics - type erasure - when and what happens. While I don't know the answer to your question about the compile time difference between <?> and <T>, I'm pretty sure the answer can be found at this FAQ that erickson mentioned in that post.
Using "?" is the same as "any", whereas "T" means "a specific type". So, compare these interfaces:
public interface StrictClass<T> {
public T doFunction(Class<T> class);
}
public interface EasyClass<T> {
public > doFunction(Class<?> class);
}
Now, we can create classes:
public class MyStrictClass implements StrictClass<String> {
public String doFunction(Class<String> stringClass) {
//do something here that returns String
}
}
public class MyEasyClass implements EasyClass<String> {
public String doFunction(Class<?> anyClass) {
//do something here that returns String
}
}
Hope that helps!
Basically, they are equivalent. You can use the first syntax where you don't need to declare anything of type T.
UPDATE: oh, and T can be used to bind types together: if Class<T> is used in different parts of the function it will refer to the same class, but not Class<?>.
A good resource might be this: http://sites.google.com/site/io/effective-java-reloaded
The interesting part related to your question starts around the 5th minute.
Just in addiction to what previous users said.
Hope that helps :]