The following code is very confusing to me.
public class Test<T> {
public static <T> Test<T> ok(T result) {
..
I understand the generics in class name. I could understand if "ok" method would be like this
public static Test<T> ok(T result) {
or this
public static T ok(T result) {
But why there is the extra < T > before the Test < T > return type I don't understand.
The example is in fact equivalent to
public class Test<T> {
public static <U> Test<U> ok(U result) {
..
The other <T> refers to a different generic type which applies only to the method. To avoid confusion, it's better to use different names for different things.
It is a static method, so it is unaffected by the generic type parameter of an instance.
If you want the ok method to be bound by the generic parameter , you will have to make something like TestFactory<T> class as a factory that only makes tests of T type, like that:
public class TestFactory<T> {
public Test<T> ok(T result) {
// ...
}
}
So in this case a TestFactory<String> only allows String results, anything else is a compiler error.
If you prefer the static method, you should do what #jurez posted to avoid confusion: The thing is, its type parameter of this static method only depends on type of given input parameter.
Related
Example is pretty simple. What I want is written. The problems are in the comments.
import java.util.*;
class Main
{
private static class X<T> {
public static T get() { return new T(); }
}
public static void main(String[] args)
{
System.out.println(X<Interger>.get()); // illegal start of type
// commenting out above yields:
// error: non-static type variable T cannot be referenced from a static context
}
}
The real confounder to me is the error: non-static type variable T cannot be referenced from a static context. The error seems clear: the class & method are static but the type variable isn't. Can I make the type variable work in this static context.
Further, as the example is written, I don't understand why I get an illegal start of type error with nothing else. Is this because the error about the non-static type variable is hidden?
You can't do new T(). For one thing, there is no guarantee that T has an accessible no-args constructor. Relevant here, there is no no-arg constructor for Integer.
Static methods, as well as instance methods and constructors, can have type parameters.
public static <T> T get() {
// Can only legally return null or throw.
...
}
...
System.out.println(X.<Integer>get());
What to use instead? Possibly an abstract factory of some sort, possibly java.util.function.Supplier.
While the type X is generic, the class X is not. In Java, there are no "generic classes" (only generic types). What was most probably intended is a generic parameter on the static method:
private static class X<T> {
public static <T> T get() {
return ...;
}
}
Also, since generics are erased, one cannot instantiate T (thus the three dots in the code above).
One would call the method like such:
...
X.<SomeConcreteType>get();
I think Supplier maybe more suitable for you than static X<T>.get:
public static class aClass {}
public static <T> aMethodWantToUseX(Supplier<T> x) {
T t = x.get();
}
aMethodWantToUseX(aClass::new)
what are the differences between the two? When should I use each?
Generic:
public static <T extends SomeClass> void doSomething(T class)
{
}
Parent class as a parameter:
public static void doSomething(SomeClass class)
{
}
Due to type erasure, both the methods are effectively the same.
Such a generic would only be useful if you're returning an instance of T from the method. A simple example would be casting an object stored somewhere to the expected type (this is unsafe, as we do no actual check if it is really and instance of T, but that is another story)
public static <T extends SomeClass> T get(String name) {
return (T) fancyLookup(name)
}
private static Object fancyLookup(String name) { ... }
So to answer your question:
What are the differences between the two?
Nothing, at runtime they are effectivly identical.
When should I use each?
Prefer the one without generics, as said they are the same, and introducing a generic where none is needed just complicates your code.
I am trying to make a method which takes in a variable object type as a parameter, and then updates a database depending on what object was passed, a bit like how Petapoco works for C#. For this I am trying to use a generic method in which the object that is passed passes a number of checks before it is inserted/updated into its relevant table. A number of questions on Stack Overflow point me towards using a method signature like this:
public <T> void upsertObject(Class<T> objectClass, T actualObject) { }
Within the method I would like to be able to call methods like actualObject.getId() but the compiler needs to know the actual type of the object to call its relevant methods. Is there any way around this? How would I go about achieving these calls?
EDIT:
Edited for more clarity
After adding an interface with which to bind T, I found I was getting the error:
"Cannot make a static reference to the non-static method getId() from the type CycleComponent"
The method now looks like this, the error line is under T.getId()
public <T extends CycleComponent> void upsertObject(Class<T> objectClass, T fitProObject) {
if (objectClass.getName() == "Cycle") {
if (isInserted(T.getId(), "Cycles")) {
// update the database
}else {
// insert into the database
}
}
}
The interface looks like:
public interface CycleComponent {
String getId();
}
And the method in the Cycle class looks like:
public String getId() {
return this.cycleId;
}
You can do it with generic type bounds.
Define:
public <T extends SomeType> void upsertObject(Class<T> objectClass, T actualObject) { }
Where SomeType is a class or interface, and you'll be able to call methods of SomeType on the actualObject instance.
This would limit this method to being used only with types that extend SomeType (if it's a class) or implement SomeType (if it's an interface).
For example:
public interface SomeType {
String getId();
}
And:
public <T extends SomeType> void upsertObject(Class<T> objectClass, T actualObject) {
if (actualObject.getId() != null) {
...
}
}
Assuming this doesn't have to be absolutely generic (for example, it probably doesn't make sense to upsert a java.lang.Integer, right?), I'd define an interface with all the methods you need, and add that to the generic classification:
public interface Upsertable {
int getID();
// Other methods you may need...
}
public <T extends Upsertable> void upsertObject(Class<T> objectClass, T actualObject) { }
I recently started writing a generic object mapper for a project and ran into something I don't quite understand. Given the following:
public class G<X> {
public G(Class<X> c) { }
public void m(X x) { }
public static <T> G<T> create(Class<T> c) {
return new G<T>(c);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<?> t = create(o.getClass());
t.m(o);
}
}
I get the following compilation error:
m(capture#402 of ?) in G<capture#402 of ?> cannot be applied to (java.lang.Object)
I can't seem to figure out a way to properly cast t to make this compile. What am I missing? Using JDK 1.6.
EDIT:
This is not an academic question. I'm trying to write a mapper from hibernate objects to their corresponding DTO to be passed around in the REST layer. The assumption is that for each ORM object Foo, there might exist a class FooDTO that has a constructor that takes an instance of Foo as a parameter. The generic class that maps Foo to FooDTO will encapsulate this assumption and throw appropriate exceptions if FooDTO doesn't exist or doesn't have the proper constructor:
class Mapper<Foo,FooDTO> {
private final Constructor<FooDTO> dtoConstructor;
Mapper(Class<Foo> fooClass, Class<FooDTO> fooDTOClass){
// find the constructor of FooDTO or throw ...
}
public FooDTO map(Foo f){
return dtoConstructor.newInstance(f);
}
// this factory is for convenience when we don't know the type of FooDTO:
public static Mapper<X,Object> create(Class<X> fromClass){
Class<Object> dtoClass = // ... find it
return new Mapper<X,Object>(fromClass,dtoClass);
}
}
This seems to break if I pass a generic object class to create.
Note that my actual implementation has all FooDTO classes extends from a generic super class, i.e., the signature of Mapper is actually something like Mapper<Foo,DTO<Foo>>. I don't think that's relevant here.
EDIT 2:
Actually the suggestion of changing the line G<?> t = create(o.getClass()); to G<Object> t = (G<Object>) create(o.getClass()); worked in this context.
Unfortunately I didn't realize that the fact that my class is more complex actually has an impact. Here's a more complete example (I apologize for the piecemeal question):
public class Y<T> {
}
public class G<X, Z extends Y<X>> {
public G(Class<X> c, Class<Z> s) {
}
public void m(X x) {
}
public static <T, S extends Y<T>> G<T, S> create(Class<T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<? extends Object, Y<? extends Object>> t = create(o.getClass());
t.m(o);
}
}
In this case the object Class<S> is created using reflection and some conventional location for objects of that type. That part works fine and should be irrelevant to this discussion. The error I am getting now is the following:
inconvertible types
found : G<capture#155 of ? extends java.lang.Object,Y<capture#155 of ? extends java.lang.Object>>
required: G<java.lang.Object,Y<java.lang.Object>>
And if I change the incriminated line to:
G<Object, Y<Object>> t = (G<Object, Y<Object>>) create(o.getClass());
I get a similar error:
java: inconvertible types
required: G<java.lang.Object,Y<java.lang.Object>>
found: G<capture#1 of ? extends java.lang.Object,Y<capture#1 of ? extends java.lang.Object>>
Once again, I apologize for the piecemeal information. I am sorting through this while I am writing.
You have passed the Class object from the getClass() method, which returns a Class<?>, meaning that you had to declare t to be a G<?>.
You cannot call a method with a generic type parameter when the generic type parameter of the variable is a wildcard. The compiler doesn't know which specific class the wildcard really is, so it cannot guarantee type safety when such a method is called. It's the same reason that add can't be called on a List<?>.
To get this to compile, you must use a class literal, to avoid having a Class<?>, and declare t not to have a wildcard.
G<Object> t = create(Object.class);
Then
t.mo(o);
will compile.
What you have here is a consumer. However, the following seems to compile (in Eclipse).
public static class G<X, Z extends Y<X>> {
public G(Class<? extends X> c, Class<Z> s) {}
public void m(X x) {}
public static <T, S extends Y<T>> G<T, S> create(Class<? extends T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
create(o.getClass()).m(o);
}
}
You're creating a G<Object> and then assigning it to a variable of type G<?>. The method invoked takes a variable of the generic type, which won't take anything for <?>. If you change the variable to G<Object> it will work.
Since you are specifying G<?>, javac is expecting to figure out what the generics are (what classes do they represent). Changing the statement to G t = create(o.getClass()); fixes the errors.
capture errors generally mean that the compiler is unable to figure out the classes...
Its not really clear what you are trying to do... Perhaps that information would be useful in helping you more...
I have an abstract class that has a generic method and I want to override the generic method by substituting specific types for the generic parameter. So in pseudo-code I have the following:
public abstract class GetAndParse {
public SomeClass var;
public abstract <T extends AnotherClass> void getAndParse(T... args);
}
public class Implementor extends GetAndParse {
// some field declarations
// some method declarations
#Override
public <SpecificClass> void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
But for some reason I'm not allowed to do this? Am I making some kind of syntax error or is this kind of inheritance and overriding not allowed? Specifically I'm getting an error about #Override because the eclipse IDE keeps reminding me to implement getAndParse.
Here's how I want the above code to work. Somewhere else in my code there is a method that expects instances of objects that implement GetAndParse which specifically means that they have a getAndParse method that I can use. When I call getAndParse on that instance the compiler checks to see whether I have used specific instances of T in the proper way, so in particular T should extend AnotherClass and it should be SpecificClass.
What we are having here is two different methods with individual type parameters each.
public abstract <T extends AnotherClass> void getAndParse(Args... args);
This is a method with a type parameter named T, and bounded by AnotherClass, meaning each subtype of AnotherClass is allowed as a type parameter.
public <SpecificClass> void getAndParse(Args... args)
This is a method with a type parameter named SpecificClass, bounded by Object (meaning each type is allowed as a type parameter). Do you really want this?
Is the type parameter used inside Args? I think the problem would be there.
The meaning of
public abstract <T extends AnotherClass> void getAndParse(T... args);
is that the caller of the method can decide with which type parameter he wants to call the method, as long as this is some subtype of AnotherClass. This means that in effect the method can be called with any objects of type AnotherClass.
Since the caller can decide the type parameter, you can't in a subclass narrow down the parameter type to SpecificClass - this would not be an implementation of the method, but another method with same name (overloading).
Maybe you want something like this:
public abstract class GetAndParse<T extends AnotherClass> {
public SomeClass var;
public abstract void getAndParse(T... args);
}
public class Implementor extends GetAndParse<SpecificClass> {
// some field declarations
// some method declarations
#Override
public void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
Now the getAndParse method implements the parent class' method.
You are seeing this problem because of the concept called "Erasure" in Java Generics.
Java uses "erasure" to support backward compatibility. i.e Java code which did not use generics.
Erasure Procedure:
The compiler will first do a type checking and then it will remove(erase) all the type parameters as much as possible, and also insert TypeCasting where ever necessary.
example:
public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass);
will become
public abstract void getAndParse(AnotherClass paramAnotherClass);
In class "Implementor.java",
The code
public <SpecificClass> void getAndParse(T paramAnotherClass)
will become
public void getAndParse(SpecificClass paramAnotherClass){ }
the compiler will see that you have not implemented the abstract method correctly.
There is a type mismatch between the abstract method and the implemented method. This is why you are seeing the error.
More details can be found here.
http://today.java.net/pub/a/today/2003/12/02/explorations.html
You cannot override to specific type T because there is in fact (at the bytecode level if you wish) only one method getAndParse because of type erasure (see other answer):
public abstract void getAndParse(AnotherClass... args); // (1)
For every type of T, the same method is used.
You can overload it (I think):
public void getAndParse(SpecificClass... args); // (2)
but this will not a different method from (1) ant it will not be called by generic code:
T x = whatever;
object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass
No, it's not valid. What would happen if someone with a GetAndParse reference called it with a different class extending AnotherClass?
That becomes a nonsense when someone has a reference to type GetAndParse and tries to call the getAndParse method. If Cat and Dog extend AnotherClass. I should expect to be able to call GetAndParse#getAndParse with either a Cat or a Dog. But the implementation has tried to restrict it and make it less compatible!
Static method can't override
class Vehicle{
static void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
#Override //error
void park(int location) { //error
System.out.println("Car Parking..");
}}
Private method can't override
class Vehicle{
private void park(int location){
System.out.println("Vehicle parking..");
}
void callPark(){
park(100);
}}
class Car extends Vehicle{
//#Override
void park(int location) {
System.out.println("Car Parking..");
}}
class Demo {
public static void main(String[] args) {
Vehicle v1=new Car();
v1.callPark();
}}
Final method can't override
class Vehicle{
final void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
//#Override
void park(int location) { //error
System.out.println("Car Parking..");
}}