Method returning as interface
Consider this example: I have 3 interfaces: A, B, C, with methods a(), b(), c(); extending a base interface Intf; I have a enum with options MyEnum.A, MyEnum.B, MyEnum.C; I have a class extending this 3 interfaces: X implements A, B, C; There is a way to implement a method in X like this;
public T getType (MyEnum enum)
and the result is the interface A, B or C, that is, accessing only method a(), b() or c()? EDIT: I want to use it on a builder with fluent api:
X var = X.getType(MyEnum.A).a("value").build();
X var = X.getType(MyEnum.B).b("value").build();
X var = X.getType(MyEnum.A).b("value").build(); //ERROR
I am not sure about the first requirement: As it stands I am assuming that the baseInterface Intf has the 3 methods a(), b() and c(). But as I keep reading I am not sure whether this is the case.
Please don’t explain code, show it. And please show how you would want to use / call the method getType(. ) .
I guess the OP wants getType(MyEnum.A) to return an instance of A , getType(MyEnum.B) to return an instance of B etc. — i.e. to express this in a method signature.
A signature like public
3 Answers 3
You could dispatch the enum value, and return a matching instance, as @GhostCat suggested.
You could also invert the lookup, so each enum value provides an appropriate instance of Intf :
Variant 1: singleton instance per enum value
public enum MyEnum < A(new AImpl()), B(new BImpl()), C(new CImpl()); private Intf instance; MyEnum2(Intf instance) < this.instance = instance; >public T getType() < return (T) instance; >>
Variant 2: factory, creating new instances:
public enum MyEnum < A(AImpl.class), B(BImpl.class), C(CImpl.class); private Classtype; MyEnum(Class type) < this.type = type; >public T getType() < try < return (T) type.newInstance(); >catch (InstantiationException | IllegalAccessException ex) < throw new RuntimeException(ex.getMessage(), ex); >> >
A a = MyEnum.A.getType(); B b = MyEnum.B.getType(); C c = MyEnum.C.getType();
@AxelH you’re right, I missed that A,B,C are interfaces as well. Editing my answer to provide implementations if those interfaces, thanks for hinting this out.
But the compiler will not reject writing A a = MyEnum.C.getType(); or C c = MyEnum.A.getType(); . Things can get worse in generic code when that doesn’t even fail immediately at runtime, but lead to heap pollution, instances of wrong types stored somewhere, which will fail at an even later time, when no-one knows where the object came from. Think Set someMethod() < return Collections.singleton(MyEnum.B.getType()); > …
If I read your question correctly you want compile-time safety for
public T getType (MyEnum enum)
to return A for MyEnum.A , B for MyEnum.B etc.
You can achieve this compile-time safety if you make MyEnum class generic. This does now work with normal enums, but it works with old-fashioned «typesafe enum» pattern.
Assume we have three interfaces AA , BB , CC extending the base interface II :
public interface AA extends II < void a(); >public interface BB extends II < void b(); >public interface CC extends II
Now the class TT implements all of these interfaces:
public class TT implements AA, BB, CC < @Override public void a() < . >@Override public void b() < . >@Override public void c() < . >>
Now let EE be our generic pseudo-enum class, parameterized with some subtype of II :
public class EE < public static final EEA = new EE(); public static final EE B = new EE(); public static final EE C = new EE(); >
With these definitions the getType method can be declared as follows:
public XX getType(EE enumVal)
This method may only return the type the type which parameterized the enumVal . Meaning
One of the ways to implement the getType method would be delegate «conversion» of the TT instance to AA , BB or CC to the corresponding pseudo-enums:
public abstract class EE < public static final EEA = new EE() < @Override public AA convert(PP instance) < return new AA() < public void a() < instance.a(); >; >; > >; public static final EE B = new EE() < @Override public BB convert(PP instance) < return new BB() < public void b() < instance.b(); >; >; > >; public static final EE C = new EE() < @Override public CC convert(PP instance) < return new CC() < public void c() < instance.c(); >; >; > >; public abstract XX convert(PP instance); >
You can also return instance directly, without wrapping in an anonymous inner class. But then the result can be force-casted to the other interfaces thus allowing access to other methods.
Finally, the implementation of getType is trivial:
public XX getType(EE enumVal)
From what I can see, the compiler won’t allow
BB bb = (BB) tt.getType(EE.A); bb.b();
won’t work as in «produces ClassCastException in the runtime».
The disadvantages are a pseudo-enum construct and somewhat ugly implementation of convert .
Methods that return Interface ? [given that there are many implementations of interface]
This question may be simple (I wish it is not) but i found in an interview. In general, given an interface class IntClass, and a number of classes that implements the interface named ImpIC1, ImpIC2, . ImpICk. The methods in IntClass are abstract public methods named void action1(), void action2() . void actionM(). I was given a public class Test with public static function named: public static IntClass foo(IntClass c1, IntClass c2). This method do some operations on c1 and c2 to create an an InClass and returns. However, the method must work for every valid implementation of IntClass. The problem is mainly with the definition of c3. How would I design method foo() .. see below for code details:
public interface IntClass
public class ImpIC1 implements IntClass < public void action1() < . >public void action2() < . >.. public void actionM() < . >>
public class ImpIC2 implements IntClass < public void action1() < . >public void action2() < . >.. public void actionM() < . >>
public class ImpICk implements IntClass < public void action1() < . >public void action2() < . >.. public void actionM() < . >>
- inside foo, c3 was defined as instance of Object .. i.e. IntClass c3 = (IntClass) new Object(). — compile-time error Object cannot be cast to IntClass
- inside foo, c3 was left with no initializion. (compile time error).
- inside foo, c3 is null, (null pointer exception)
- inside foo, c3 is initialized as one of the implemtation of c3 (i.e. c3 = (IntClass) new ImpIC1()) .. the problem is that if we execute in the exterior ImpIC2 s = (ImpIC1) foo(c1,c2) — we get an error (unable to cast).
c3 is of type IntClass (which is an interface) and is returned by function foo(IntCLass c1, IntClass c2) ..
I understand you want c3 to be an IntClass . But what is inside c3 ? How are you combining c1 and c2 to make it? If you simply want to return any IntClass at all, why not do return ImplC1() ?
@Ahmed Jedda — That is not an informative answer to the question what is c3 supposed to be and how it relates to c1 and c2. I still don’t see why return null; would not satisfy this problem.
Well let’s assume that each implementation ImpC1, ImpC2 .. ImpCk uses different data structures but the same functions action1() .. actionM(); then here we want function foo() to work on any implementation .. YET! we define foo() in a public class Test !! — it is really weird and I kept thinkin about it for a day !
5 Answers 5
I don’t know about your implementation. But here are some point which we need to know. You can not instantiate interface(Except anonymous inner class). if you want Interface to return change Test Class as follow —
That s very interesting answer in fact .. do you think we can do it without changing the structure of the function ?
Atleast you have to specify the name of class as argument so that correct object is initialize, There must be a way to know which class to be initiate.
Class.forName returns a Class —not a new instance. You need to use newInstance on the returned class.
You can take the class of either parameter to create a new object — to avoid changing the function signature. But I question the structure: if you return an INTERFACE, the one that uses the returned object should not cast it but use it as it is.
Perhaps they wanted to see if you knew how to use reflection to return an instance of whatever class c1 is. Every object is an instance of a class (even anonymous inner classes). You can give an interface for the type of a reference, but in the end it points to a class instance.
public IntClass foo(IntClass c1, IntClass c2) < IntClass c3 = c1.getClass().newInstance(); // requires no-arg constructor // use c1 and c2 to set up c3 . return c3; >
@AhmedJedda — There are far better questions to ask to test someone’s knowledge on reflection, especially since you cannot possibly know what should go between the newInstance and return . There’s no way to generically combine the return values from each pair of actionN methods. This makes for a bad interview question.
honestly .. it made me revise my knoweldge in Java !! .. but it s alright .. if they ll call, they ll call ! [you can look at the comments under Alderath’s comment above for an example, (as I understood it) — perhaps it helps]
The posted specifications are extremely vague. «This method do some operations on c1 and c2 to create an an InClass and returns». This does not specify ANY functional requirements at all.
The following solution does some operations on c1 and c2 (they are rather nonsensical operations, but the specifications don’t forbid the operations from being nonsensical). It also creates a new IntClass instance which is returned. And, any implementation of an IntClass can be passed as a parameter and the method will still work.
public static IntClass foo(IntClass c1, IntClass c2) < c1.getClass(); c2.toString(); return new IntClass< public void action1()<>public void action2()<> . public void actionM()<> >; >
Now, based on my guess on what the requirements might have been, I will present another more sensible solution. This does not fully comply to the stated requirements, but I think it might be what the interviewer was looking for.
public class Test < public static IntClass foo(IntClass c1, IntClass c2)< return new CompositeIntClass(c1, c2); >public class CompositeIntClass implements IntClass < private IntClass c1; private IntClass c2; public CompositeIntClass(IntClass c1, IntClass c2)< this.c1 = c1; this.c2 = c2; >public void action1() < c1.action1(); c2.action1(); >public void action2() < c1.action2(); c2.action2(); >. public void actionM() < c1.actionM(); c2.actionM(); >> >
Using this implementation, calling foo(c1, c2) will formally not perform any operations on c1 or c2. So it doesn’t satisfy the stated requirements. However, it will create a new IntClass instance which has the behaviour of c1 and c2 combined. I.e. invoking action2() on c3 will invoke action2() on both c1 and c2. I think this might be what the requirements were supposed to be (just a guess).
So in summary, this means that the returned object (c3) will have the behaviour of any arbitrary IntClass implementations. It will however not mean that you’ll be able to do SomeArbitraryImplClass c3 = (SomeArbitraryImplClass) foo(c1, c2); , because doing so would be a violation against the whole concept of interface abstraction (surely nothing that would be advocated in an interview).
The solution is an example of the Composite Pattern.
If you are using generalized abstractions, you have to ensure that they are compatible with the problems you intend to solve with them. As all the actionI() methods in the described problem setting have a void return type, it is impossible to extract the min and max of any PairInterface instance (as described in your comment). The abstraction does not allow for that.
If that is what you want to do, the solution is much simpler. (This is based on the assumption that the PairInterface contains the declarations int getX() and int getY() , which seems reasonable for a PairInterface):
Along with this, you also have to create the SomePairInterfaceImplementation class, or use some existing class which can accept x and y as constructor parameters.
1) If PairInterface only declares void methods, it is IMPOSSIBLE to figure out the max or min of x values of c1 and c2. The values are encapsulated and hidden and cannot be accessed.
2) It should not matter what implementation of PairInterface that the method returns. The reason for having an interface return type is that any consistent implementation of the interface should work.