Код не компилируется:
Test.java: 8: метод () в баре не может
переопределить метод () в Foo; переопределены
метод является статическим окончательным
public static void method () {
Сообщение вводит в заблуждение, поскольку статический метод по определению не может быть переопределен.
Я делаю следующее при кодировании (не 100% все время, но здесь нет ничего "неправильного":
(Первый набор «правил» сделан для большинства вещей - некоторые особые случаи рассматриваются позже)
- создать интерфейс
- создать абстрактный класс, который реализует интерфейс
- создает конкретные классы, расширяющие абстрактный класс
- создает конкретные классы, которые реализуют интерфейс, но не расширяют абстрактный класс
- всегда, если возможно, делать все переменные / константы / параметры интерфейса
Поскольку в интерфейсе не может быть статических методов, проблема не возникает. Если вы собираетесь создавать статические методы в абстрактном классе или в конкретных классах, они должны быть закрытыми, тогда нет способа переопределить их.
Особые случаи:
Классы утилит (классы со всеми статическими методами):
- объявить класс как окончательный
- предоставить ему приватный конструктор для предотвращения случайного создания
Если вы хотите иметь статический метод в конкретном или абстрактном классе, который не является частным, вы, скорее всего, вместо этого захотите создать вспомогательный класс.
Классы значений (класс, который очень специализирован для хранения данных, например java.awt.Point, где он в значительной степени содержит значения x и y):
- нет необходимости создавать интерфейс
- нет необходимости создавать абстрактный класс
- класс должен быть окончательным
- Неприватные статические методы в порядке, особенно для построения, так как вы можете захотеть выполнить кэширование.
Если вы будете следовать вышеприведенному совету, вы получите довольно гибкий код, который также имеет довольно четкое разделение обязанностей.
Примером класса значений является следующий класс Location:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class Location
implements Comparable<Location>
{
// should really use weak references here to help out with garbage collection
private static final Map<Integer, Map<Integer, Location>> locations;
private final int row;
private final int col;
static
{
locations = new HashMap<Integer, Map<Integer, Location>>();
}
private Location(final int r,
final int c)
{
if(r < 0)
{
throw new IllegalArgumentException("r must be >= 0, was: " + r);
}
if(c < 0)
{
throw new IllegalArgumentException("c must be >= 0, was: " + c);
}
row = r;
col = c;
}
public int getRow()
{
return (row);
}
public int getCol()
{
return (col);
}
// this ensures that only one location is created for each row/col pair... could not
// do that if the constructor was not private.
public static Location fromRowCol(final int row,
final int col)
{
Location location;
Map<Integer, Location> forRow;
if(row < 0)
{
throw new IllegalArgumentException("row must be >= 0, was: " + row);
}
if(col < 0)
{
throw new IllegalArgumentException("col must be >= 0, was: " + col);
}
forRow = locations.get(row);
if(forRow == null)
{
forRow = new HashMap<Integer, Location>(col);
locations.put(row, forRow);
}
location = forRow.get(col);
if(location == null)
{
location = new Location(row, col);
forRow.put(col, location);
}
return (location);
}
private static void ensureCapacity(final List<?> list,
final int size)
{
while(list.size() <= size)
{
list.add(null);
}
}
@Override
public int hashCode()
{
// should think up a better way to do this...
return (row * col);
}
@Override
public boolean equals(final Object obj)
{
final Location other;
if(obj == null)
{
return false;
}
if(getClass() != obj.getClass())
{
return false;
}
other = (Location)obj;
if(row != other.row)
{
return false;
}
if(col != other.col)
{
return false;
}
return true;
}
@Override
public String toString()
{
return ("[" + row + ", " + col + "]");
}
public int compareTo(final Location other)
{
final int val;
if(row == other.row)
{
val = col - other.col;
}
else
{
val = row - other.row;
}
return (val);
}
}