I've got the following method of an public abstract class Model { //impl } (declared exactly like this):
protected <T extends Model> HashMap<String, Model> resultsetMap(ResultSet res) {
HashMap<String, Model> data = new HashMap<String, Model>();
try {
while(res.next()) {
Model obj = T.getNew(res);
data.put(obj.toString(), obj);
}
} catch(SQLException e) {
return null;
}
return data;
}
T is supposed to tell the caller the concrete class it should use. Is this possible?
How would I call this method from another method of a subclass of Model? I've tried with resultsetMap<Course>(res); but it looks like a syntactic error
Since the method is inherited, you can call it either as super.<ConcModel>resultsetMap(/* arg */); or this.<ConcModel>resultsetMap(/* arg */);. Second or first respectively based on whether the subclass is overriding it or not.
Tutorial on how to call a generic method.
You can't call T.getNew() because the type of T is erased at runtime. You can pass in a Class object if you need to call Class methods.
In your code 'T' describes a type, it's not an instance of anything so you can't call methods on it. If it was an instance of an object you would need to pass it into the method anyway, if it's meant to be a static method it cant be overrided.
I would consider using the factory pattern, i.e. pass in a model factory to this method.
Related
Suppose I have a unknown interface, and I want to be able to construct an object which, when user calls some method from interface on it, returns something specified by that interface.
E.g. having a Class class object, representing unknown Interface, I want to be able to construct an Object, which behaves like something which correctly implements that Interface.
For instance, say I'm working on method
public <E> E myMethod(Class<E> class){
...
return res;
}
Where class is representation of an unknown interface, let for instance
public <E> interface Writer{
public String write(String s);
}
Class<E> class = Writer.class;
All I want now is that any call like
returnedFromMyMethod.write(s);
actually do the job, e.g. returns given string
I know that there's reflection to be used, because all of that is going on in runtime, we don't know what exactly the interface is. But can't figure it out. Any ideas?
EDIT: To avoid misunderstanding.
That's all going in runtime. I don't know what that interface is.
It can be Writer as possibly as Runnable, Comparable or any
other. It is for sure one interface.
Our object doesn't
exist, it hasn't got any of methods we want. It's like constructing
a new object (of parametrized type) from zero.
So question is about creating an object that imitates implementing all methods from given interface
You can create a dynamic proxy:
#SuppressWarnings("unchecked")
public static <E> E myMethod(Class<E> cls) {
return (E) Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls },
(Object proxy, Method method, Object[] arguments) -> {
// handle the invocation of the given method
return null; // return something actual
});
}
Writer result = makeProxy(Writer.class); // e.g.
As long as you have a plan for how to handle the invocations. Of course there is no way to do that out 'automagically'.
Change your method and interface as
public <E extends Writer> E myMethod(Class<E> clazz) {
...
return res;
}
public interface Writer {
public String write(String s);
}
Now you will be able to call write(String s) method on the return value of myMethod(Class<E> clazz).
Writer w = myMethod(WriterImpl.class);
w.write("any string");
You can put that class into a java decompiler such as javadecompilers.com and then you can find out what interface it extends, or you can go the reflection route like this:
//Assuming the class only extends 1 interface you can do this
Class<?>[] interfaces = class.getClass().getInterfaces();
//Now since we know interfaces[0] is the desired interface, we can get its name
System.out.printLn(intefaces[0].getName()); //You don't have to print the name if you're just going to continue with reflection
//now we're going to define the s variable which will hold what the method returns
String result = "";
//Next using reflection we're going to get the desired method, invoke it, give reflection it's return type and your argument
try {
result = interfaces([0].getMethod("write").invoke(String.class, args);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This is what you could do if you wished to use reflection.
On the contrary, if I have miss understood what the question was, any Class that implements an Interface automatically has those methods to be called. Therefore, doing class.write(s); would return a String just like normal.
I've got this class:
public class A<T> {
protected T something = new T();
...
}
Of course new T() is not possible. What can I do instead?
I must not change the code where the constructor of this class is called, because this is done via reflection.
Annother problem is how to get the Class object of a generic class. mymethod(A.class) worked, but now A has got the parameter T.
You can receive the T as a parameter of the constructor:
protected T something;
public A(T something) {
this.something = something;
}
Or, if the goal of A is to really create new T instances, then take a factory of T as an argument:
protected T something;
public A(Factory<T> somethingFactory) {
this.something = somethingFactory.newInstance();
}
Class<T> can be viewed as a Factory<T>, since it has a newInstance() method, that invokes the public no-arg constructor. But a Factory<T> could create new instances using something other than this constructor.
You can have a constructor (or method) that takes Class<T> parameter and have clazz.newInstance()
Whenever you instantiate the object you know the type, so you have:
A<Foo> a = new A<Foo>(Foo.class);
No. Also there's no way of specifying that T has a no-args constructor or is even non-abstract.
You can pass in an abstract factory, or a prototype.
Please don't use reflection!!!
I want to use the class information that was captured by the setup of a generic method in Java to potentially create an instance. But I can't see how to reference the class without an actual instance. Is it possible?
public class Fancy {
static public <TypeToFind> TypeToFind createInSomeCase() {
// any type of logic with TypeToFind "class" generic will do, I just want to reference it.
// the below code is invalid, I could also declare a variable, but can't always create an instance to get the class
if (TypeToFind.getClass().equals(Something.class)) {
return TypeToFind.getInstance();
}
}
}
... so later on I could do:
TheResultIsTheParameter t = Fancy.createInSomeCase();
... instead of
TheResultIsAParameter t = Fancy.createInSomeCase(TheResultIsAParameter.class);
... or
TheResultIsAParameter t = Fancy.createInSomeCase(t);
Am I making this too complicated?
You can't do it, because generics are lost at runtime (due to type erasure). You have to pass a Class<?> parameter
Well, you require somethink that is logical, unfortunattelly generics in Java are only a syntactic sugar for reflection.
List<MyClass> list;
(...)
MyClass my = list.get(0);
will compile to
MyClass my = (MyClass) list.get(0);
and this is what will you see in bytecode.
What is more, using reflection or casting to untyped list you can put any object into list and in both codes you'll get ClassCastException.
So the generics exists only on compiler level. A big feature which adds nothing new, only shortens a code in most cases.
As long as you do not try and statically (at compile time) reference any particular class, nothing prevents you from doing something like this:
public class GenericsTest {
#Test
public void testMe() {
GenericsTest test = new GenericsTest();
System.out.println(test.get("Hello").getClass());
}
public GenericsTest() {
super();
}
public <T extends Object> T get(T entity) {
return newInstanceForClass((Class<T>)entity.getClass());
}
public <T extends Object> T newInstanceForClass(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
But as you can see, you need to pass in an object of the class you are trying to instantiate, which might not be want you are after. In which case the only other option is to pass in a Class parameterized with the generic type, for reasons that other posters have eloquently stated.
I have this test method:
public void load(Class<? extends Object> className, XXXX)
{
Criteria criteria = session.createCriteria(className);
List<Object> list = criteria.list();
for (Object item : list)
{
list.add(new Object(item.getId, item.getCode); /* Object doesn't know getId */
}
}
How to replace XXXX in load method to call it using concrete Object? Something like:
load(Foo.class, testObject)
Is it possible?
Every generic type must extend Object, so this is sufficient:
public <T> void load(Class<T> className, T object)
{
// snip...
}
public <X> void load(Class<X extends Object> className, X object)
I think this is what you mean.
This should work.
public <T extends Base> void load(T object){
Criteria criteria = session.createCriteria(object.class);
List<T> list = criteria.list();
for (T item : list)
{
System.out.println(item.getId)); /* Object doesn't know getId */
}
}
Parameterizing the the void allows you to use generics. Since you are looking for an instance of T, and T is not defined yet, when you pass an object into load(T object) it will automatically set T to whatever class the object is. It auto parametrizes the void.
Generics are extremely useful. For an example, it's used in the List and Set classes as well as Map. However they come with their own risks. If you don't put the T extends Base or some class then you'll get compilation errors because java can not be sure that the class passed will have getId. Setting up a class that it must inherit will ensure that the object must know that method.
replace Base with the base class that knows "getId" and make all other classes you could even end up passing into load() extend that class. Notice no need to pass a Class into the load() because we will just use the class of the object instead, which has the same effect.
i've stumbled upon a curiosity in the java inheritance, and I wanted you to ask for better ideas on that:
Assume two interfaces A and A1
Interface A1 extends A
Interface A has a method which returns a generic type.
The generic type would be like GenericType<T>.
A basic idea is now to change this generic return type from
GenericType<Object> in Interface A into
GenericType<String> in Interface A1
Well seems to be easy at first (bad things will come later on)
We declare Interface A like
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
and Interface A1 like
public interface InterfaceA1 extends InterfaceA
{
#Override
public GenericType<String> getAGenericType();
}
As you see we are forced to write GenericType<? extends Object> in Interface A itself to allow overriding it with generic based "subclasses".
(In fact the generic parameter of the generictype is subclassed not the generic type itself)
Now assume the GenericType has its own method looking like:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Now trying to instantiate A1 works great.
Rather trying to instantiate A will suck. To see why look at this "use the interface" class:
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<? extends Object> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith( something );
}
}
You ask: "And now?"
It does not work on the last lines. In fact the parameter "something" is not even from type "Object" it is from Type "? extends Object". So you cannot pass the declared "Object" type. You can't pass anything at all.
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
Do you have ideas how to model such a use case, where the subclasses will have to override the return type, while the return type is a generics?
Or how would you go around such a model case?
Or am I just missing a simple point in the generic declaration and my example is possible this way?
----------- (1) edit due to answers -----------
A very good basic idea is making the interface A more abstract! I had exactly the same idea first, but... (this has to come)
Assume doing this:
We introduce a new interface AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Now we will have to extend A and A1 from this new interface:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
That works fine, althought it breaks the path of the original inheritance.
If we want A1 still be extendable from A, we have to change A1 to
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
and there a problem is again. This does not work, since we extend indirectly the same interface with different generic types. This is unfortunately not allowed.
You see the problem?
-
And to point to another circumstance:
If you cast the GenericType<? extends Object> to GenericType<Object> it obviously works.
Example:
public class LookAtTheInstance
{
public static void main( String[] args )
{
InterfaceA a = new InterfaceA()
{
#Override
public GenericType<? extends Object> getAGenericType()
{
return new GenericType<Object>()
{
#Override
public void doSomethingWith( Object something )
{
System.out.println( something );
}
};
}
};
;
#SuppressWarnings("unchecked")
GenericType<Object> aGenericType2 = (GenericType<Object>) a.getAGenericType();
Object something = "test";
aGenericType2.doSomethingWith( something );
}
}
So it seems for me that the resolving of the parameter type of the method
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
is wrong.
If D is unified with "? extends Object" why the parameter type is not forced to be "Object"?
Wouldnt this make more sence?
A basic idea is now to change this generic return type from GenericType in Interface A into GenericType in Interface A1
This is not possible, because Java Generics are invariant. [1]
As you found out, you cannot have an interface declaring a method that returns GenericType<Object> and in a sub interface override the method to return GenericType<String>: The latter return type is not a subtype of the former. And for good reason!
You tried to
extend indirectly the same interface with different generic types. This is unfortunately not allowed.
There is no way this could possibly work: E.g. what should be the type of E in public E set(int index, E element) in a class that implemented both List<String> and List<Object>? Your subclassed interface would have to produce a similar hybrid: The return value of getAGenericType in the sub interface would have to implement both the GenericType<String> and the GenericType<Object> interface. And as we saw, this is impossible.
The compiler does not know what you are going to do with the type parameter in GenericType (although it theoretically could find out, it doesn't). If you had a variable of type GenericType<String> and assigned a GenericType<Object> to it, you may very well end up putting a Long instance where a String is expected, and get a ClassCastException where you won't expect one.
In the doSomethingWith method of your variable GenericType<? extends Object> aGenericType2 you can pass one thing: null. null is the only object reference that has a subtype of ? extends Object. The lower bound type of ? extends Object is the null type, which cannot be expressed in Java, and only implicitly exists as the type of the null reference.
[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java
I don't know if this is what you are expecting, but you can declare your interface something like:
public interface Interface <K extends Object> { ... }
While your class might look like:
public class InterfaceImpl implements Interface<String> { ... }
#Override annotation:
When overriding a method, you might
want to use the #Override annotation
that instructs the compiler that you
intend to override a method in the
superclass. If, for some reason, the
compiler detects that the method does
not exist in one of the superclasses,
it will generate an error.
With this annotation you cannot change return type of function.
If you want to override return type, just make interface A more abstract, add generic to this interface:
public interface InterfaceA<T> {
public GenericType<T> getAGenericType();
}
Sample about overriding a generic method in a generic class.
The trouble is that InterfaceA doesn't know what type it's holding. If you get InterfaceA to take a generic argument then you could do this:
public interface InterfaceA<T>
{
public GenericType<T> getAGenericType();
}
public interface InterfaceA1 extends InterfaceA<String>
{
#Override
public GenericType<String> getAGenericType();
}
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA<String> a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<String> aGenericType2 = a.getAGenericType();
String something = null;
aGenericType2.doSomethingWith( something );
}
}
I'm several years late to the party, but I found this page while searching for a related question and none of the answers really hit on the central issue, which I think is worth clarifying. Let's look at a slightly-more-fleshed-out example:
interface GenericType<D> {
D getAValue();
void doSomethingWith(D value);
}
class StringType implements GenericType<String> {
#Override
public String getAValue() {
return "Hello World";
}
#Override
public void doSomethingWith(final String value) {
System.out.println(value.length());
}
}
interface InterfaceA {
GenericType<? extends Object> getAGenericType();
}
interface InterfaceA1 extends InterfaceA {
#Override
GenericType<String> getAGenericType();
}
class AnActualA1 implements InterfaceA1 {
#Override
public GenericType<String> getAGenericType() {
return new StringType();
}
}
class LookAtTheInstance {
public static void method() {
InterfaceA1 a1 = new AnActualA1();
// 'g1' is a StringType, which implements GenericType<String>; yay!
GenericType<String> g1 = a1.getAGenericType();
// Everything here is fine.
String value = g1.getAValue();
g1.doSomethingWith("Hello World");
// But if we upcast to InterfaceA???
InterfaceA a = (InterfaceA) a1;
// Note: a.getAGenericType() still returns a new StringType instance,
// which is-a GenericType<? extends Object>.
GenricType<? extends Object> g = a.getAGenericType();
// StringType.getAValue() returns a String, which is-an Object; yay!
Object object = g.getAValue();
// StringType.doSomethingWith() method requires a String as the parameter,
// so it is ILLEGAL for us to pass it anything that cannot be cast to a
// String. Java (correctly) prevents you from doing so.
g.doSomethingWith(new Object()); // Compiler error!
}
}
Conceptually, GenericType is NOT a GenericType, since a GenericType can only doSomethingWith() Strings, while a GenericType needs to be able to doSomethingWith() any object. GenericType is a compromise which the compiler allows you to use as a "base class" for any GenericType where D is-an Object, but only allows you to use a reference of that type to call methods that are type-safe for any possible runtime value of '?' (such as getAValue(), whose return value can always be safely cast to an Object since D is-an Object regardless of runtime type).
It's hard to tell what (if anything) the original poster was actually trying to model with this code, and in particular how much of the generic-ness of GenericType was really needed, but perhaps the inheritance should have gone the other way around?
/**
* I can do something with instances of one particular type and one particular
* type only.
*/
interface GenericType<D> {
void doSomethingWith(D value);
}
/**
* I can do something with instances of any type: I am-a GenericType<String>
* because I can totally do something with a String (or any other kind of
* Object).
*/
interface NonGenericType extends GenericType<Object>, GenericType<String> {
#Override
void doSomethingWith(Object value);
}
interface StringHandlerFactory { // nee InterfaceA1
GenericType<String> getAGenericType();
}
/**
* I extend StringHandlerFactory by returning a NonGenericType (which is-a
* GenericType<String>, satisfying the interface contract, but also so much
* more).
*/
interface ObjectHandlerFactory extends StringHandlerFactory { // nee InterfaceA
#Override
NonGenericType getAGenericType();
}
The downside being that there's no good way to express to the java compiler that NonGenericType extends GenericType, even though conceptually it could in this case, since GenericType never uses D as a return value. You have to manually specify each GenericType that you want it to extend. :(
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
I think that the purpose of InterfaceA is not to be instantiated at all, because one of its dependable classes are generic. That's what you meant declaring:
public GenericType<? extends Object> getAGenericType()