8

I've seen a number of similar questions, but I don't think any were quite isomorphic, and none quite answered my question.

Suppose there are two interfaces, Tree and Named. Suppose further that I am given a method whose signature is

public <T extends Tree & Named> T getNamedTree();

How can I save the returned value to a variable, while still retaining the information that it implements both Tree and Named? I can't find a way of declaring a variable like

public <T extends Tree & Named> T mNamedTree;

and trying to cast it to an interface extending Tree and Named results in a class cast exception.

1
  • You'd need to know what that method actually returns in the implementation, from the signature I can tell you that it uses an unchecked cast. Commented Apr 20, 2017 at 23:48

3 Answers 3

4

Assuming there is no third interface inheriting both Named and Tree, you cannot retain information about both interfaces statically. The compiler will require you to do a cast for one or the other, or for both:

Object namedTree = getNamedTree();
Tree asTree = (Tree)namedTree;
Named asNamed = (Named)namedTree;

Both casts should succeed.

If you have influence on the design of the API for the class, ask the authors to introduce an interface combining both Named and Tree, and returning an instance of that interface instead.

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

4 Comments

Actually, that signature indicates the return of a specific type that would upcast to either Interface, not downcast as you chose to show. In fact, upcasting has nothing to do with the return type. The generics are type assertions about the concrete type. For example, public <T extends Serializable & Comparable<T>> maximum(T left, T right) can be met with a Integer max = maximum(Integer.valueOf(102), Integer.valueOf(-1)):. No casting!
Did you try to compile your advice here?
@LewBloch It compiles perfectly (see this demo). Why are you asking?
@LewBloch As far as your first comment goes, please re-read OP's question, especially the "Suppose further that I am given a method whose signature is ..." part. He's not implementing a method, where he must meet a requirement with a single class. He's getting back an object that already meets the two-interface requirement. The problem is, OP is not given that object type.
2

One possible solution would be to create another interface that extends both Tree and Named, and simply store that as the variable:

interface NamedTree extends Tree, Named {

}

public NamedTree namedTree;

public NamedTree getNamedTree();

Comments

0

What scope does the variable has to have?

There is three possibilities here.

A) the variable is just a local variable. In that case you nearly have already the answer... you just need to declare a type-parameter for the enclosing method for that type:

interface ItfA { Number propA(); };
interface ItfB { Number propB(); };

class Main {

  private <T extends ItfA & ItfB> T getT() {
     return null;
  }

  private <TT extends ItfA & ItfB> void doStuffWithT() {
     TT theT = getT();
     System.err.println(theT.propA());
     System.err.println(theT.propB());
  }

}

B) The scope is the live of an object and in that case is a member field. The obvious answer is to make the class generic and the type-parameter would have the same & constraint:

interface ItfA { Number propA(); };
interface ItfB { Number propB(); };

class Main<T extends ItfA & ItfB> {

  T theT;

  public void setT(T newT) {
     theT = newT;
  }

  public void doStuffWithT() {
     System.err.println(theT.propA());
     System.err.println(theT.propB());
  }

}

C) The scope is the live of the program, then the variable is a static class member. Here you don't have a generics solution.

C.1) Obviously if the class of the values that you are going to handle is known you would just use that class as the field type.

C.2) If not, you could constraint the code to handle only classes that implement an interface that extends ItfA and ItfB. That interface, say ItfAB. Would be to field type.

C.3) Now, what about not imposing that constraint? What about allow the code to handle objects from any class that implement those interfaces?

Unfortunately there is no a clean-cut solution to that:

C.3.a) You could either type the field Object and provide methods to access it as an ItfA or as a ItfB (basically hiding the casting).

C.3.b) Or, instead of holding directly a reference to the object, you use a proxy object that implements those interfaces and delegates calls to those interfaces methods to the original "T" typed value. The class for that proxy could itself be a generic accepting an arbitrary <T extends ItfA & ItfB> value (similar to the B. example above).

1 Comment

"A" is close enough; not exactly what I was hoping existed, but using a getter (and associated setter to an internal Object) instead of using the variable directly isn't too awful.

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.