代码之家  ›  专栏  ›  技术社区  ›  anon

接口中的构造函数?

  •  129
  • anon  · 技术社区  · 14 年前

    我知道在接口中定义构造函数是不可能的。但我想知道为什么,因为我认为它可能非常有用。

    因此,可以确保为该接口的每个实现定义了类中的某些字段。

    例如,考虑以下消息类:

    public class MyMessage {
    
       public MyMessage(String receiver) {
          this.receiver = receiver;
       }
    
       private String receiver;
    
       public void send() {
          //some implementation for sending the mssage to the receiver
       }
    }
    

    如果a为这个类定义一个接口,这样我可以有更多的类来实现消息接口,那么我只能定义send方法,而不能定义构造函数。那么,如何确保这个类的每个实现都有一个接收器集呢?如果我用这样的方法 setReceiver(String receiver) 我不能确定是否真的调用了这个方法。在构造器中,我可以确保它。

    11 回复  |  直到 14 年前
        1
  •  121
  •   zb226 Steven Lizarazo    9 年前

    从你所描述的一些事情中:

    “因此,可以确保类中的某些字段是为 此接口的每个实现。”

    “如果a为这个类定义一个接口,这样我可以有更多 实现消息接口的类,我只能定义 发送方法而不是构造函数“

    …这些要求正是 abstract classes 是为了。

        2
  •  67
  •   daniel kullmann    11 年前

    当您允许接口中的构造函数时,一个问题来自于同时实现多个接口的可能性。当一个类实现几个定义不同构造函数的接口时,该类必须实现几个构造函数,每个构造函数只满足一个接口,而不满足其他接口。无法构造调用每个构造函数的对象。

    或在代码中:

    interface Named { Named(String name); }
    interface HasList { HasList(List list); }
    
    class A implements Named, HasList {
    
      /** implements Named constructor.
       * This constructor should not be used from outside, 
       * because List parameter is missing
       */
      public A(String name)  { 
        ...
      }
    
      /** implements HasList constructor.
       * This constructor should not be used from outside, 
       * because String parameter is missing
       */
      public A(List list) {
        ...
      }
    
      /** This is the constructor that we would actually 
       * need to satisfy both interfaces at the same time
       */ 
      public A(String name, List list) {
        this(name);
        // the next line is illegal; you can only call one other super constructor
        this(list); 
      }
    }
    
        3
  •  10
  •   rsp    14 年前

    接口为API定义了一个契约,这是API的实现者和用户都同意的一组方法。接口没有实例实现,因此没有构造函数。

    您描述的用例类似于一个抽象类,其中构造函数调用一个在子类中实现的抽象方法的方法。

    这里固有的问题是,在执行基本构造函数时,子对象尚未构造,因此处于不可预知的状态。

    总结一下:当您从父构造函数调用重载方法时,是否会遇到麻烦,引用 mindprod :

    一般来说,你必须避免打电话给 构造函数中的非最终方法。 问题是那个例子 初始化器/变量初始化 在派生类中执行 之后 基地的建设者 班级。

        4
  •  4
  •   Satyajit Gami    9 年前

    接口中只有静态字段在子类中创建对象时不需要初始化,接口方法必须在子类中提供实际的实现,因此接口中不需要构造函数。

    第二个原因是在子类的对象创建过程中,调用了父构造函数。但是如果实现了多个接口,那么在调用接口构造函数期间,将发生冲突,关于哪个接口的构造函数将首先调用

        5
  •  2
  •   Yishai    14 年前

    接口方法中未引用的依赖项应视为实现细节,而不是接口强制执行的内容。当然也可能有例外,但是作为一个规则,您应该将接口定义为行为的期望值。给定实现的内部状态不应该是接口的设计问题。

        6
  •  2
  •   Lappro    7 年前

    你可以尝试的工作就是定义一个 getInstance() 方法,以便实现人员知道需要处理哪些参数。它不像抽象类那样坚固,但它允许作为接口更灵活。

    但是,此解决方法确实要求您使用 获取实例() 以实例化此接口的所有对象。

    例如。

    public interface Module {
        Module getInstance(Receiver receiver);
    }
    
        7
  •  1
  •   Community gkalpak    7 年前

    this question 对于 为什么? (摘自评论)。

    如果您真的需要这样做,您可能需要一个抽象的基类,而不是一个接口。

        8
  •  1
  •   NoNaMe    11 年前

    这是因为接口不允许在其中定义方法体。但是我们必须在与接口默认情况下为所有要定义的方法定义抽象修饰符相同的类中定义构造函数。这就是为什么我们不能在接口中定义构造函数。

        9
  •  1
  •   Denys Vasylenko    7 年前

    如果要确保接口的每个实现都包含特定字段,只需 需要将该字段的getter添加到接口中 :

    interface IMyMessage(){
        @NonNull String getReceiver();
    }
    
    • 它不会破坏封装
    • 它会让所有使用你的界面的人知道 Receiver 对象必须以某种方式(通过构造函数或setter)传递给类。
        10
  •  0
  •   Tord Larsen smaznet    7 年前

    这里有一个使用这种技术的例子。在这个特定的示例中,代码使用模拟调用FireBase MyCompletionListener 这是一个被屏蔽为抽象类的接口,一个带有构造函数的接口

    private interface Listener {
        void onComplete(databaseError, databaseReference);
    }
    
    public abstract class MyCompletionListener implements Listener{
        String id;
        String name;
        public MyCompletionListener(String id, String name) {
            this.id = id;
            this.name = name;
        }
    }
    
    private void removeUserPresenceOnCurrentItem() {
        mFirebase.removeValue(child("some_key"), new MyCompletionListener(UUID.randomUUID().toString(), "removeUserPresenceOnCurrentItem") {
            @Override
            public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
    
            }
        });
        }
    }
    
    @Override
    public void removeValue(DatabaseReference ref, final MyCompletionListener var1) {
        CompletionListener cListener = new CompletionListener() {
                    @Override
                    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
                        if (var1 != null){
                            System.out.println("Im back and my id is: " var1.is + " and my name is: " var1.name);
                            var1.onComplete(databaseError, databaseReference);
                        }
                    }
                };
        ref.removeValue(cListener);
    }
    
        11
  •  0
  •   Sai Kumar    6 年前

    一般来说,构造函数用于初始化特定类中与对象相关的非静态成员。

    没有为接口创建对象,因为只有声明的方法,但没有定义的方法。为什么我们不能创建声明方法的对象?对象创建只是为非静态成员分配一些内存(堆内存中)。

    JVM将为完全开发并准备好使用的成员创建内存。基于这些成员,JVM计算出需要多少内存并创建内存。

    在声明方法的情况下,JVM无法计算这些声明方法需要多少内存,因为实现将在将来进行,而此时还没有完成。因此,不能为接口创建对象。

    结论:

    如果不创建对象,就无法通过构造函数初始化非静态成员。这就是为什么在接口内不允许使用构造函数的原因。(因为在接口内不使用构造函数)