Из того, что я собрал, я хочу заставить класс использовать определенные частные поля (и методы). Мне нужен абстрактный класс, потому что интерфейс объявляет только общедоступные / статические / конечные поля и методы. Верный??
Я только что начал свой первый большой java-проект и хочу убедиться, что не собираюсь навредить себе позже :)




Это правильно. Но это не обязательно решение либо-либо, вы можете объединить преимущества интерфейсов и абстрактных классов, предоставив скелетную реализацию вместе с вашим интерфейсом. Вы можете найти очень интересное описание этого подхода в Эффективная Java, 2-е изд., пункт 18 («Предпочитайте интерфейсы абстрактным классам»).
Частные поля и методы не могут использоваться подклассами (кроме случаев, когда они также являются внутренними классами). Однако вы можете сделать их защищенными.
Это правильно. Интерфейсы предназначены для общего пользования. А частная реализация должна быть в абстрактном (или конкретном) классе.
Если вы когда-нибудь догадываетесь, какой из них выбрать, я предлагаю ошибиться в сторону интерфейсов - лучше иметь интерфейс, который должен быть абстрактным классом, чем наоборот.
Вы не хотите принудительно использовать определенные закрытые поля или методы. В общем, вас не волнует реализация, вам важен интерфейс. Итак, определите пару методов в паре интерфейсов (в зависимости от того, сколько вам нужно) и определите классы, которые их реализуют. Это, вероятно, меньше всего навредит вам в будущем.
+1 Я поражен тем, что на этот вопрос так много буквальных ответов, и ваш единственный ответ на неверное предположение, стоящее за вопросом.
Интерфейс определяет именно это - интерфейс (контракт) с миром за пределами реализующего класса. Открытые методы суперкласса (абстрактного или нет) делают то же самое. Вы не должны пытаться требовать, чтобы подклассы имели определенные частные члены - вы пытаетесь указать реализацию, которой ООП стремится избежать.
Вы используете абстрактный класс, когда хотите определить какое-то общее поведение в суперклассе, но этот класс не может существовать сам по себе (он должен быть подклассом). Может случиться так, что для общего поведения требуется некоторое собственное состояние - в этом случае оно может определять частные поля, а также может иметь частные методы, которые может использовать только оно.
Даже если вы унаследованы от абстрактного класса, вы не сможете получить доступ к его частным полям / методам.
Интерфейсы определяют договор для поведения. Они должны быть об этом, а не об атрибутах.
Если вы хотите, чтобы подкласс определял определенные методы, используйте интерфейс. Как говорили другие, дело не столько в как - подкласс делает это, сколько в том, что это делает будут.
Довольно часто предоставляется и то, и другое, так что в итоге вы получите:
public interface Sendable {
public void sendMe();
}
а также
public abstract class AbstractSender implements Sendable {
public abstract void send();
public void sendMe() {
send(this.toString());
}
}
Таким образом, любой, кто доволен реализацией по умолчанию в абстрактном классе, может быстро создать подкласс без переписывания большого количества кода, но любой, кому нужно сделать что-то более сложное (или кому нужно наследовать от другого базового класса), все равно может реализовать интерфейс и быть plug-and-play.
разве вы не хотите, чтобы AbstractSender реализует Sendable.
Да. Исправлено. На самом деле, я хочу менее надуманный пример, но сразу ничего не пришло в голову.
I want to force a class to use particular private fields (and methods)
Эта часть вашего вопроса вызывает сомнения: как вы думаете, почему вы хотите это сделать?
частные члены не видны подклассам, а интерфейсы определяют общедоступный интерфейс, поэтому ваш единственный выбор - использовать абстрактный класс ... но я не могу придумать ни одной причины, по которой кто-либо когда-либо захотел бы это сделать
Если вы хотите, чтобы класс использовал определенные поля или методы другого класса, вы можете объявить их защищенными.
public abstract class A {
protected Object thing;
}
может быть доступен другому классу в том же пакете (может расширять класс A или нет)
A a = new A();
a.thing.toString();
На самом деле это не «принуждение» другого класса к его использованию, а скорее «включение».
за исключением последних полей / методов в интерфейсе, это было бы правильно.