接口中的属性/成员变量?


76

我想知道有什么方法可以强制实现者类声明对象的句柄/基元,就像它们对方法所做的那样。例如:

public interface Rectangle {    
    int height = 0;
    int width = 0;

    public int getHeight();
    public int getWidth();
    public void setHeight(int height);
    public void setWidth(int width);                
}


public class Tile implements Rectangle{
    @Override
    public int getHeight() {
        return 0;
    }

    @Override
    public int getWidth() {
        return 0;
    }

    @Override
    public void setHeight(int height) {
    }

    @Override
    public void setWidth(int width) {   
    }

}

在上述方法中,我们如何强制Tile类使用该接口声明height和width属性?由于某些原因,我只想使用界面来做!

我最初考虑将其与继承一起使用。但是,我必须处理3个班级。

  1. 长方形
  2. JLabel!

 

 class Tile extends JLabel implements Rectangle {}

会工作。!

class Tile extends JLabel extends Rectangle {}

不会。!


8
您的界面不正确。它不能包含属性。也许您想使用抽象类?
pvoosten 2011年

10
@lbp实际上会编译;-)只是……不是“预期的”行为。编译器假定/应用final static修饰符。

1
您可能希望使用Height而不是Hieght和Hight。Hight是highten,hihten,被呼叫的过去分词。;)
彼得·劳瑞

如果提供访问器,为什么要公开变量?
乔纳森·莱夫勒

您可以在接口中具有常量,但仅此而已,即使那样,您也很难找到一种不会使用这种常量的方案。
Wim Ombelets 2014年

Answers:


95

接口的重点是指定公共API。接口没有状态。您创建的任何变量实际上都是常量(因此请注意在接口中创建可变对象)。

基本上,一个接口说这是实现它的类必须支持的所有方法。如果Java的创建者不允许在接口中使用常量,但是现在太晚了,现在就不可以了(在某些情况下,在接口中使用常量是明智的),那可能会更好。

因为您只是指定必须实现的方法,所以不知道状态(没有实例变量)。如果要要求每个类都具有某个变量,则需要使用抽象类。

最后,通常来说,您不应该使用公共变量,因此从一开始就将变量放入接口的想法很糟糕。

简短的答案-您无法做您想做的事情,因为Java中这是“错误的”。

编辑:

class Tile 
    implements Rectangle 
{
    private int height;
    private int width;

     @Override
    public int getHeight() {
        return height;
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public void setHeight(int h) {
        height = h;
    }

    @Override
    public void setWidth(int w) { 
        width = w;  
    }
}

一个替代版本是:

abstract class AbstractRectangle 
    implements Rectangle 
{
    private int height;
    private int width;

     @Override
    public int getHeight() {
        return height;
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public void setHeight(int h) {
        height = h;
    }

    @Override
    public void setWidth(int w) { 
        width = w;  
    }
}

class Tile 
    extends AbstractRectangle 
{
}

kk!所以我该怎么做。(我已经编辑了问题,请检查)!
Shrey 2011年

我想这会有所帮助..!thnxx :)
Shrey 2011年

但这留下了一个问题,即您不能在具体的实现中弄乱高度。因此,您知道您需要一个高度,您知道您需要能够返回高度,但是您不能将其留给每个实现来计算高度(我认为这样做不符合目的)。当然,您可以声明getHeight抽象,而根本不声明高度,但是随后每次都必须重复返回代码,以使变量保持私有。
alianos-

1
-1为“接口的重点是指定公共API。接口没有状态。” 接口没有状态,但是就接口而言,公共成员变量是对象公共API的一部分。不幸的是,在Java领域,一个公共成员变量正在指定有关该API实现的某些信息(即它是一个内存变量),而不是让您自己灵活地更改实现。换句话说,obj.Property永远不能调用任何其他代码,但是obj.Property()可以,&在接口级别将两者区别对待。
weberc2 2014年

12

接口不能要求定义实例变量-只能是方法。

变量可以在接口中定义,但它们的行为不符合预期:将其视为final static。)

快乐的编码。


9

Java 8引入了接口的默认方法,您可以使用它们作为方法的主体。根据OOP,接口应充当两个系统/当事方之间的合同。

但是我仍然找到了一种在界面中存储属性的方法。我承认这有点难看。

   import java.util.Map;
   import java.util.WeakHashMap;

interface Rectangle
{

class Storage
{
    private static final Map<Rectangle, Integer> heightMap = new WeakHashMap<>();
    private static final Map<Rectangle, Integer> widthMap = new WeakHashMap<>();
}

default public int getHeight()
{
    return Storage.heightMap.get(this);
}

default public int getWidth()
{
    return Storage.widthMap.get(this);
}

default public void setHeight(int height)
{
    Storage.heightMap.put(this, height);
}

default public void setWidth(int width)
{
    Storage.widthMap.put(this, width);
}
}

这个界面很难看。为了存储简单属性,它需要两个哈希图,每个哈希图默认情况下会创建16个条目。此外,当取消对实际对象的引用时,JVM额外需要删除此弱引用。


2
很有趣,但很奇怪:)。您甚至可以消除内部类,而只在接口本身中存储静态最终映射。
iMysak

8

您只能使用抽象类而不是接口来执行此操作。

声明Rectangle为,abstract class而不是,interface并将必须由子类实现的方法声明为public abstract。然后,类Tile扩展了类,Rectangle并且必须实现的抽象方法Rectangle


我最初考虑将其与继承一起使用。但是,我必须处理3个班级。1.矩形2.平铺3. JLabel。class Tile扩展了JLabel的实现,Rectangle {}将起作用。但是类Tile扩展了JLabel扩展了Rectangle {}不会。
Shrey 2011年

2

在Java中,您不能。接口与方法和签名有关,与对象的内部状态无关,这是一个实现问题。这也很有意义-我的意思是,仅仅因为存在某些属性,并不意味着实现类必须使用它们。getHeight实际上可以指向width变量(假设实现者是施虐者)。

(请注意,并非所有语言都适用,ActionScript允许声明伪属性,我相信C#也会这样做)


1
在C#中,getter / setter(实际上只是特殊的方法调用)可以位于接口中,实例变量本身不能。

这就是我的想法(这就是我说伪的原因),ActionScript也做同样的事情。
cwallenpoole 2011年

kk!继承而不是实现会有所帮助。但这会给我带来一个新问题。你能给我建议的方法吗?(请参阅编辑后的问题)thnx!
Shrey 2011年

0

接口中的字段是隐式的public static final。(另外,方法也是隐式公开的,因此您可以删除public关键字。)即使您使用抽象类而不是接口,我也强烈建议使所有非常量(public static final原始或不可变对象引用)成为常量private。一般而言,“偏好构图而Tile不是继承”-is -not-a Rectangle(当然,您可以使用“ is-a”和“ has-a”玩文字游戏)。


瓷砖的形状是一个矩形。(是-和具有-最让我感到困惑)
Shrey 2011年

我猜想A仅在“对每个B是A的答案”为真时才应扩展B。从有效的Java中阅读..
Shrey

1
如果A扩展B,那么B怎么能成为A?你把它放回了前面。
RichieHH 2014年

0

汤姆说了一些重要的事情:

如果使用“具有”概念,则可以避免此问题。

事实上,如果不是使用扩展工具定义两个属性,类型长方形的,类型的一个JLabel在你的Tile类,那么你可以定义Rectangle为一个接口或类。

此外,我通常会鼓励与has-a一起使用接口,但是我认为这在您的情况下会显得过大。但是,您是唯一可以决定这一点的人(权衡灵活性/过度设计)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.