Подтвердить что ты не робот

Атрибуты/переменные-члены в интерфейсах?

Я хочу знать, есть ли какой-либо способ, с помощью которого я могу сделать обязательным для класса-реализатора объявление дескрипторов/примитивов объектов, как это делается с методами. например,

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 классами.!

  • Прямоугольник
  • Плитка
  • JLabel.

 

 class Tile extends JLabel implements Rectangle {}

будет работать.!

но

class Tile extends JLabel extends Rectangle {}

woud not.!

4b9b3361

Ответ 1

Точка интерфейса - это указать публичный API. Интерфейс не имеет состояния. Любые переменные, которые вы создаете, действительно являются константами (поэтому будьте осторожны при создании изменяемых объектов в интерфейсах).

В основном интерфейс говорит, что это все методы, которые должен поддерживать класс, который его реализует. Вероятно, было бы лучше, если бы создатели Java не допускали константы в интерфейсах, но слишком поздно, чтобы избавиться от этого сейчас (и есть некоторые случаи, когда константы разумны в интерфейсах).

Поскольку вы просто указываете, какие методы должны быть реализованы, не существует понятия состояния (нет переменных экземпляра). Если вы хотите, чтобы каждый класс имел определенную переменную, вам нужно использовать абстрактный класс.

Наконец, вы должны, вообще говоря, не использовать общедоступные переменные, поэтому идея ввода переменных в интерфейс - это плохая идея для начала.

Короткий ответ - вы не можете делать то, что хотите, потому что оно "неправильно" в Java.

Edit:

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 
{
}

Ответ 2

Вы можете сделать это только с абстрактным классом, а не с интерфейсом.

Объявить Rectangle как abstract class вместо interface и объявить методы, которые должны быть реализованы подклассом как public abstract. Затем класс Tile расширяет класс Rectangle и должен реализовывать абстрактные методы из Rectangle.

Ответ 3

Интерфейсы не могут требовать определения переменных экземпляра - только методы.

(Переменные могут быть определены в интерфейсах, но они не ведут себя так, как можно было бы ожидать: они рассматриваются как final static.)

Счастливое кодирование.

Ответ 4

В Java 8 были введены методы по умолчанию для интерфейсов, с помощью которых вы можете использовать методы. В соответствии с интерфейсами ООП следует действовать как договор между двумя системами/сторонами.

Но все же я нашел способ добиться сохранения свойств в интерфейсе. Я признаю, что это довольно уродливая реализация.

   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 дополнительно необходимо удалить эту слабую ссылку.

Ответ 5

В Java вы не можете. Интерфейс связан с методами и сигнатурой, он не связан с внутренним состоянием объекта - это вопрос реализации. И это тоже имеет смысл - я имею в виду, просто потому, что существуют определенные атрибуты, это не значит, что они должны использоваться исполнительным классом. getHeight может фактически указывать на переменную ширины (предполагая, что реализатор является садистом).

(В качестве примечания - это не относится ко всем языкам, ActionScript допускает объявление псевдо атрибутов, и я считаю, что С# тоже)

Ответ 6

Поля в интерфейсах неявно public static final. (Также методы неявно общедоступны, поэтому вы можете отказаться от ключевого слова public.) Даже если вы используете абстрактный класс вместо интерфейса, я настоятельно рекомендую сделать все непостоянное (public static final примитивной или неизменяемой ссылки на объект) private. В более общем плане "предпочитают композицию для наследования" - a Tile is-not-a Rectangle (конечно, вы можете играть в игровые игры с "is-a" и "has-a" ).

Ответ 7

Что-то важное было сказано Томом:

если вы используете концепцию has-a, вы избегаете этой проблемы.

В самом деле, если вместо использования расширений и инструментов вы определяете два атрибута, один из типов прямоугольников, один из типов JLabel в вашем классе Tile, тогда вы можете определить Rectangle как интерфейс, так и класс.

Кроме того, я бы обычно поощрял использование интерфейсов в связи с has-a, но я предполагаю, что это будет излишним в вашей ситуации. Тем не менее, вы единственный, кто может принять решение по этому вопросу (гибкость компромисса/чрезмерная инженерия).