Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I work with generic types from a calling class?

Tags:

java

generics

I'm currently brushing up my Java and reading up on Generics. Since they were not treated extensively in my Java class, I'm still having some trouble wrapping my mind about it, so please keep that in mind when answering.

First of all, I'm pretty sure that what I'm trying to is not possible. However, I'd like to find out where my thinking is wrong and how I should go about achieving what I want.

What I'm trying to do is manipulating an object that implements a generic interface from another class that has no knowledge about the instantiated type. Thus, I have something like the following classes:

public interface CalledInterface<E> {
    public E get() { ... }
    public set(E e) { ... }
}


public class Called implements CalledInterface<String> {
    ...
}

Now what I want to do is:

public class Caller {
    protected CalledInterface<?> c;

    public Caller (CalledInterface<?> arg) {
        c = arg;
    }

    public void run(){
        // I can do this:
        c.set(c.get());

        // But I'd want to be able to do something like:
        <?> element = c.get();
        c.set(element);
    }
}

What is the fundamental flaw in my thinking, if there is one? And what approach should I rather be taking?

like image 323
Vincent Avatar asked Dec 06 '12 12:12

Vincent


1 Answers

First of all, keep in mind that generics is a compile time thing not a runtime.

Now in your Caller you defined Called c. Called is defined to implement CalledInterface<String>, so automatically, Called has the following methods generated at compile time:

String get();
void set(String e); //i assume you wanted to return void

So essentially this doesn't really make sense:

<?> element = c.get();

The Caller class isn't even aware Called is using generics internally, for it, Called just deals with strings.

UPDATE

Based on your comment, since you don't want Caller to use Called directly but use CalledInterface first thing you have to do is change the type of c to that. In this case you should not use generics, because the whole point of generics is that the same class is used in different scenarios with different types (again determined at compile time), enforcing types without having repeated code.

If I understand correctly you don't want to restrict Caller to use String, so what you have to do is change CalledInterface to not use generics, and change the methods to:

Object get();
void set(Object o);

This is how we used to do things before Generics in Java 1.4. You obviously run the risk of not having type safety, so think through whether what you want really makes design sense, because it probably does not because you have to do instanceof anyway to check the type to use the Object in a useful way (i.e. to access its methods).

If on the other hand you just change the c member (and the constructor argument of Caller) to:

CalledInterface<String> c;

Your Caller will be interacting with the CalledInterface rather than the implementation and at the same time still be type safe. So you can still pass an instance of Called and set it to c.

like image 98
jbx Avatar answered Oct 16 '22 05:10

jbx