Если ваш класс не предназначен для наследования, он должен быть окончательным. Вы должны быть очень осторожны, чтобы убедиться, что вы понимаете, как методы, которые будут переопределены в подклассе, который не был разработан для функции наследования, чтобы понять, как их изменить.
Конкретный пример:
Предположим, у вас есть класс, который управляет списком имен ...
public class MyNameManager {
private List<String> numbers = new LinkedList<String>();
public void add(String value) {
numbers.add(value);
}
public void addAll(Collection<String> values) {
for(String value : values) {
add(value);
}
}
public void remove(String value) { //... }
//...
}
Теперь предположим, что вы хотите создать новый подкласс, который также подсчитывает общее количество раз, когда имя добавляется в список, например:
public class MyCountingNameManager extends MyNameManager {
private int count = 0;
@Override
protected void addAll(Collection<String> values) {
count += values.size();
super.addAll(values);
}
@Override
protected void add(String value) {
count += 1;
super.add(value);
}
}
Кажется, довольно просто, нет? Но рассмотрим результат следующего:
MyCountingNameManager m = new MyCountingNameManager();
m.add("bob");
m.add("Sally");
Количество теперь 2, и все хорошо. Но если бы мы сделали следующее:
List<String> family = new List<String>();
family.add("mom");
family.add("dad");
family.add("brother");
MyCountingNameManager m = new MyCountingNameManager();
m.add(family);
Счет теперь 6, , а не 3, который вы, вероятно, ожидаете. Это связано с тем, что вызов addAll
добавляет размер коллекции значений (которая равна 3) к счетчику, а затем вызывает метод super.addAll
для выполнения фактической обработки. super.addAll
повторяет коллекцию и вызывает метод add
для каждого значения. Но поскольку мы работаем с MyCountingNameManager
и , а не a MyNameManager
, переопределенный метод add
в подклассе вызывается каждый раз. Метод MyCountingNameManager.add
, который выполняется, также увеличивает счет! Таким образом, в результате каждое имя считается дважды!
Я полагаю, что этот пример взят из Effective Java. Вы должны обязательно найти копию и прочитать пункты, перечисленные в ответе Viele, чтобы глубже понять некоторые случаи, когда наследование плохо подходит.