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

时间:2011-09-05 17:46:07

标签: java interface

我想知道是否有任何方法可以使实现者类必须像使用方法一样声明对象句柄/基元。 例如:

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类声明高度和宽度属性?出于某种原因,我希望只使用界面!

我最初想过将它与继承一起使用。 但事情是我必须处理3个班级。!

  1. 矩形
  2. 瓷砖
  3. 的JLabel!
  4.  class Tile extends JLabel implements Rectangle {}
    

    会起作用。!

    class Tile extends JLabel extends Rectangle {}
    
    不应该。!

7 个答案:

答案 0 :(得分:73)

接口的要点是指定公共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 
{
}

答案 1 :(得分:8)

您只能使用抽象类,而不能使用接口。

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

答案 2 :(得分:6)

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

Variables can be defined in interfaces,但它们的行为并不像预期的那样:它们被视为final static。)

快乐的编码。

答案 3 :(得分:5)

Java 8为接口引入了default methods,您可以使用这些接口来处理这些方法。根据OOPs,接口应作为两个系统/各方之间的合同。

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

   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还需要删除这个弱引用。

答案 4 :(得分:2)

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

(作为一个注释 - 所有语言都不是这样,ActionScript允许声明伪属性,我相信C#也会这样做)

答案 5 :(得分:0)

接口中的字段隐式public static final。 (方法也是隐式公开的,所以你可以删除public关键字。)即使你使用抽象类而不是接口,我强烈建议制作所有非常数(public static final的基元或不可变对象引用)private。更一般地说,“更喜欢组合到继承” - Tile不是Rectangle(当然,你可以用“is-a”和“has-a”来玩文字游戏)。

答案 6 :(得分:0)

汤姆曾说过一些重要的事情:

  

如果您使用has-a概念,则可以避免此问题。

的确,如果不是使用 extends implements ,而是在JLabel中定义两个属性,一个类型为矩形,一个类型Tile。然后,您可以将Rectangle定义为接口或类。

此外,我通常会鼓励使用与has-a相关的接口,但我想这对你的情况来说太过分了。但是,您是唯一可以决定这一点的人(权衡灵活性/过度工程化)。