5

what I want to achieve here is that It's up to the subclass to decide whether they want to pass java.lang.String or java.util.HashMap as parameter to query() method. Interface just needs to claim that subclasses have to implement query method, but I don't care about what type of parameter subclasses want to pass in.

I have a interface like:

interface A<T>{
    public void query(T type);
}

Two subclasses like:

public class B implements A<String> {
    public void query(String type);
}

public class C implements A<HashMap> {
    public void query(HashMap type);
}

Then I have a factory class to produce B or C:

public class AFactory {
    public static A<?> getType(String type)  {
        if(type.equals("B")){
            return new B();
        } else if(type.equals("C")) {
            return new C();
        } 
   }
}

The idea is that the client can use the interface as below without having dependencies on B,C like:

A instance = AFactory.getType("B");
String a = "test";
instance.query(a); 

The problem I have here is: eclipse gives me error on the line of instance.query(a):

The method query(capture#2-of ?) in the type A is not applicable for the arguments (String).

I think the problem is that the interface contract doesn't know the query should be expecting String or HashMap. The way I can only think of solve this is that, I have to cast the result like:

B instance = (B)AFactory.getType("B");
String a = "test";
instance.query(a); 

But by doing this, I would have the dependency on B instead of just A(the interface) which is something I wanted to avoid at the beginning. Any idea how I can do this without having dependencies on the subclasses(in this case, B and C).

2
  • Compiler looks at A instance and says "I need T, not the String", but you do not tell him what T is. As much as i know. Commented Apr 17, 2012 at 13:22
  • graet, gotcha, Thanks @JMelnik Commented Apr 17, 2012 at 14:15

2 Answers 2

6

As Ernest says, you need to cast the returned value — A<String> is more specific than A<?>.

If you're willing to change the signature of the factory method, you could use generics to avoid having to cast yourself:

public static A<T> getType(Class<T> type) {
    if (type.equals(String.class)) {
        return new B();
    } else if (type.equals(HashMap.class)) {
        return new C();
    }
}

Then your calling code could look like this:

A<String> instance = AFactory.getType(String.class);
String a = "test";
instance.query(a);

If you can't do this then the caller of getType() will have to cast.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 Thanks for the shout-out and your answer is better than mine :)
1

You don't have to cast to B -- cast to A<String> . That will give you query(String), but without introducing B into your source:

@SuppressWarnings("unchecked")
A<String> instance = (A<String>) AFactory.getType("B");
String a = "test";
instance.query(a); 

I added the @SuppressWarnings annotation because you'll get an "unsafe" warning without it; you know the warning to be spurious, so the annotation is OK.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.