【问题标题】:Interface questions界面问题
【发布时间】:2010-09-14 09:40:49
【问题描述】:

假设我有接口 MyInterface 和 2 个实现 MyInterface 的类 A、B。
我声明了 2 个对象:MyInterface a = new A()MyInterface b = new B()
当我尝试传递给函数时 - 函数 doSomething(A a){} 出现错误。

这是我的代码:

public interface MyInterface {}

public class A implements MyInterface{}

public class B implements MyInterface{}

public class Tester {

    public static void main(String[] args){
        MyInterface a = new A();
        MyInterface b = new B();
        test(b);
    }

    public static void test(A a){
        System.out.println("A");
    }

    public static void test(B b){
        System.out.println("B");
    }

}

我的问题是我从一些可以是各种类的组件接口中获取,我需要为每个类编写函数。
所以一种方法是获取接口并检查它是哪种类型。 (A的实例)

我想知道其他人是如何处理这个问题的??

谢谢

【问题讨论】:

    标签: java interface


    【解决方案1】:

    你能不能只在每个类实现的接口上都有一个方法?还是您无法控制界面?

    这将提供多态性并避免定义任何外部方法的需要。我相信这是接口的意图,它允许客户端以非类型特定的方式处理所有实现它的类。

    如果您无法添加到界面,那么您最好使用适当的方法引入第二个界面。如果您无法编辑接口或类,那么您需要一个将接口作为参数的方法,然后检查具体类。然而,这应该是最后的手段,而是颠覆了接口的使用,并将方法与所有实现联系起来。

    【讨论】:

      【解决方案2】:

      听起来你在追求这样的事情:

      public static void test(MyInterface obj){
        if(obj instanceof A) {
           A tmp = (A)obj;
        } else if(obj instanceof B) {
           B tmp = (B)obj;
        } else {
           //handle error condition
        }
      }
      

      但请注意,这是一种非常糟糕的形式,表明您的设计出现了严重错误。如果您无法控制界面,那么按照 marcj 的建议,添加第二个界面可能是可行的方法。请注意,您可以在保持二进制兼容性的同时做到这一点。

      【讨论】:

        【解决方案3】:

        我不清楚您实际上在问什么,但问题是您没有采用 MyInterface 类型参数的方法。我不知道 Java 中的确切语法是什么,但是您可以执行 if (b is B) { test(b as B) } 之类的操作,但我不会。如果需要泛型,则使用 MyInterface 类型作为变量类型,否则使用 B 作为变量类型。你违背了使用界面的目的。

        【讨论】:

          【解决方案4】:

          我不确定我是否完全理解这个问题,但似乎一种方法可能是将 test() 方法移到子类中:

          public interface MyInterface {    
              public void test();
          }
          
          public class A implements MyInterface{
              public void test() {
                  System.out.println("A");
              }
          }
          
          public class B implements MyInterface{
              public void test() {
                  System.out.println("B");
              }
          }
          
          public class Tester {
          
              public static void main(String[] args){
                  MyInterface a = new A();
                  MyInterface b = new B();
                  b.test();
              }
          }
          

          您可以类似地使用 toString() 方法并打印其结果。不过,我不能完全从这个问题中看出,如果您的要求使这成为不可能。

          【讨论】:

          • 差不多。应该是: public void test(MyInterface mi) 是的,我知道你的方法可行,但我确定那是存根代码。
          【解决方案5】:

          我认为访客design pattern 会在这里为您提供帮助。基本思想是让您的类(A 和 B)自己调用适当的方法,而不是您尝试决定调用哪个方法。作为一个 C# 人,我希望我的 Java 能正常工作:

          public interface Visitable {   
             void accept(Tester tester) 
          }
          
          public interface MyInterface implements Visitable {    
          }
          
          public class A implements MyInterface{
             public void accept(Tester tester){
                 tester.test(this);
             }
          }
          
          public class B implements MyInterface{
             public void accept(Tester tester){
                 tester.test(this);
             }
          }
          
          public class Tester {
          
              public static void main(String[] args){
                  MyInterface a = new A();
                  MyInterface b = new B();
                  a.accept(this);
                  b.accept(this);
              }
          
              public void test(A a){
                  System.out.println("A");
              }
          
              public void test(B b){
                  System.out.println("B");
              }
          
          }
          

          【讨论】:

          • 哎呀...您不能在静态上下文中使用“this”。但是关于访客的想法是正确的。
          【解决方案6】:

          在一个 .java 文件中只使用一个公共类/接口,否则会抛出错误。并以对象名称调用对象。您只在Teater类中声明了两个方法,那么声明A,B类的目的是什么。

          【讨论】:

            【解决方案7】:

            我通常使用抽象类来解决这个问题,如下所示:

            public abstract class Parent {}
            public class A extends Parent {...}
            public class B extends Parent {...}

            这允许您将 Parent 对象传递给采用 A 或 B 的函数。

            【讨论】:

              【解决方案8】:

              您有 3 个选项:

              1. 访客模式;您需要能够更改 MyInterface 类型以包含方法 visit(Visitor),其中 Visitor 类包含许多用于访问每个子类的方法。
              2. 在您的方法 test(MyInterface) 中使用 if-else 在它们之间进行检查
              3. 使用链接。也就是说,声明处理程序ATesterBTester等,它们都实现了接口ITester,其方法是test(MyInterface)。然后在ATester 中,在做东西之前检查类型是否等于A。然后,您的主 Tester 类可以拥有这些测试器的链,并将每个 MyInterface 实例传递到链中,直到它到达可以处理它的 ITester。这基本上是将 if-else 块从 2 变为单独的类。

              在大多数情况下,我个人会选择 2。 Java 缺乏真正的面向对象。处理它!想出各种方法来解决它通常只会使代码难以遵循。

              【讨论】:

              • java 并不缺少“真正的”面向对象(不管是什么)——它只是缺少多个调度工具。
              【解决方案9】:

              听起来您需要 a) 通过将方法放在 MyInterface 上并在 A 和 B 中实现来利用多态性,或者 b) 组合和访问者设计模式的某种组合。当事情变得笨拙时,我会从 a) 开始,然后朝着 b) 前进。

              我对访客的广泛想法:

              http://tech.puredanger.com/2007/07/16/visitor/

              【讨论】:

                【解决方案10】:
                public interface MyInterface {}
                
                public class A implements MyInterface{}
                
                public class B implements MyInterface{}
                
                public class Tester {
                
                    public static void main(String[] args){
                       MyInterface a = new A();
                       MyInterface b = new B();
                       test(b); // this is wrong
                    }
                
                    public static void test(A a){
                        System.out.println("A");
                    }
                
                    public static void test(B b){
                        System.out.println("B");
                    }
                
                }
                

                您正在尝试将由MyInterface 引用变量引用的对象传递给使用其子类型(如test(B b))的参数定义的方法。编译器在这里抱怨是因为MyInterface 引用变量可以引用任何属于MyInterface 子类型的对象,但不一定是B 的对象。如果在Java 中允许这样做,可能会出现运行时错误。举一个例子,这将使您的概念更清晰。我修改了B 类的代码并添加了一个方法。

                public class B implements MyInterface {
                    public void onlyBCanInvokeThis() {}
                
                }
                

                现在只需更改test(B b) 方法,如下所示:

                public static void test(B b){
                    b.onlyBCanInvokeThis();
                    System.out.println("B");
                }
                

                如果编译器允许,此代码将在运行时崩溃:

                 MyInterface a = new A();
                 // since a is of type A. invoking onlyBCanInvokeThis()
                 // inside test() method on a will throw exception.
                 test(a); 
                

                为了防止这种情况,编译器不允许使用超类引用的这种方法调用技术。


                我不确定您想要实现什么,但您似乎想要实现运行时多态性。为此,您需要在 MyInterface 中声明一个方法并在每个子类中实现它。这样,对方法的调用将在运行时根据对象类型而不是引用类型来解决。

                public interface MyInterface {    
                    public void test();
                }
                
                public class A implements MyInterface{
                    public void test() {
                        System.out.println("A");
                    }
                }
                
                public class B implements MyInterface{
                    public void test() {
                        System.out.println("B");
                    }
                }
                
                public class Tester {
                
                    public static void main(String[] args){
                        MyInterface a = new A();
                        MyInterface b = new B();
                        b.test(); // calls B's implementation of test()
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-05-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多