Search code examples
javaclassinterfaceoverwritegeneric-type-argument

Is it possible to automatically chose the appropriated class method when having an interface argument?


Ok, so I have searched and I couldn't find the answer to this particular question. It's possible that this is a recurrent problem and I don't know the right terms to refer to it, so all help is appreciated. :)

Lets say we have a method m0 which receives an object from Interface I, object i.

Class A and B extend interface I, so object i can be of either class A or B.

then, inside method m1, I want to use a declared method in interface I, mi, which receives an argument of Interface I.

In Classes A and B I implement mi, and I want mi to behave according to the argument. If mi receives an object of class A, I want it to use the implementation of mi from class A, else, I want the implementation from class B. I don't want to check in method m0 if the object is an instance of A or B though, as I want the method to be independent and just rely on the interface I. There's a chance I would want to introduce many more classes that extend I.

public boolean m0(I i1, I i2){
   return i1.mi(i2);
}

public interface I{
   public boolean mi(I i);
}

class A implements I{

   boolean boolValue;
   ...
   mi(I i){
     if(this.boolValue == i.boolValue)
        return true;
     return false;
   }
}

class B implements I{

   int intValue;
   ...
   mi(I i){
      if(this.intValue == i.intValue)
         return true;
      return false;
   }
}

The idea is that class A and B are different in nature, yet I want them to have the mi method in common. so i1.mi(i2) should adapt according to the argument i2. it's guaranteed that i1 and i2 will always be of the same class in m0. Yet, in the m0 method implementation on both classes, I'm not allowed to access the i object properties booleanValue or intValue(depending on the argument type).

I've edited the question as I was not explaining the problem properly, thank you anyway for the answers so far.

Thanks

EDIT: This problem is solved. To achieve the kind of behavior I was looking for, it's possible to use Generic Types. https://docs.oracle.com/javase/tutorial/java/generics/types.html


Solution

  • You seem to complicate matters greatly. Your implementations should return the values you want, that's all, and don't need a pointer to themselves, since you can use this.

    public boolean m0(I i){
       return i.mi();
    }
    
    public interface I{
       public boolean mi();
    }
    
    class A implements I{
    
       boolean a = true;
    
       mi(){
          return this.a;
       }
    }
    
    class B implements I{
    
       boolean b = false;
    
       mi(){
          return this.b;
       }
    }
    

    of course in your precise example you could hardcode the value in the method:

    class A implements I{
    
       boolean mi(){
          return true;
       }
    }
    

    Note: you need to use implements and not extends since I is an interface.

    EDIT: You have clarified the question. I'm not too sure how you arrived at such a design, so maybe you should review your whole design, but given your question, this is how you can achieve it. Basically add a generic type on your interface, so that your interface acts as a wrapper around this type. The code may be easier to understand than any long winded explanation:

    public <T> boolean m0(I<T> i1, I<T> i2){
       return i1.mi(i2.getT());
    }
    
    public interface I<T>{
       public T getT(); 
    
       public boolean mi(T i);
    }
    
    class A implements I<A>{
    
       boolean boolValue;
    
       public A getT() {
            return this;
        }
    
       public boolean mi(A i){
         if(this.boolValue == i.boolValue)
            return true;
         return false;
       }
    }
    
    class B implements I<B>{
    
       int intValue;
    
       public B getT() {
            return this;
        }
    
    
       public boolean mi(B i){
          if(this.intValue == i.intValue)
             return true;
          return false;
       }
    } 
    

    So your classes both define a getT() that returns themselves, and the method mi that takes the exact subclass. The compiler gives you also the warranty that you can only call m0 with matching types.