Канонический вид Java-класса

Оригинальная статья опубликована Joseph Bergin, 13 сентября 2009

Большинство Java-классов включают в себя, как минимум, следующие составляющие. Это помимо заключенной в них функциональности, Согласно правилам стиля, названия классов в Java указываются прописными буквами.

public class Name extends Object implements Cloneable, java.io.Serializable
{ 	public Name()
	{	... DO NOT call non final methods from here.
	}

	public String toString()
	{	return ... 
	}

	public boolean equals(Object o)
	{	... Defines an Equivalence relation
			Reflexive: a.equals(a) must return true.
			Symmetric: If a.equals(o) then o.equals(a) as well. 
			Transitive: If a.equals(b) and b.equals(c), then a.equals(c).
		... Note that Symmetric is usually the difficult one to be sure of. 
	}

	public int hashCode()
	{	... Consistent with equals: two "equals" objects should have same hashCode result.
	}
}

Конечно же, почти для каждого класса есть свой конструктор. Иногда в этом нет никакой логики, это не является обязательной потребностью. Если для класса нет конструктора: конструкторы всех подклассов понадобятся для того: чтобы точно вызвать любой из конструкторов класса с супер представлением.

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

Метод toString используется Java системой ввода/вывода, а также некоторыми другими частями системы Java. Также данный метод полезен при поиске ошибок в программе, поскольку он предоставляет информацию об объекте и его полях, и программист видит, что происходит в программе, просто указывая интересные ему объекты.

Стандартное тело равенства выглядит примерно так:

public boolean equals(Object o)
{	if(o == null) return false;
	if(getClass() != o.getClass()) return false;
	return ... depending on fields of o and this. 
}

Объект представления равенства по умолчанию использует ==, относящемуся к равенству. Хотя такое сравнение зачастую ошибочно, поскольку не принимается во внимание значение объект. Метод hashCode применяется для расположения объектов в хеш-таблицах (Hashtable и HashMap) в качестве ключей. Если hashCode не соответствует равенствам, хеш-таблица будет работать неправильно. Если тестирование равенств основывается на некоторых установленных полях класса, основой hashCode должны быть эти же поля. (На ошибку в ранней версии указал Оуэн Эстрэчен из Университета Дьюка).

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

В некоторых классах может быть реализован java.io.Serializable, к которому нет требований. Он позволяет сохранять объект в файл или передавать его по сети.

В большинстве классов должен быть реализован метод Cloneable, а также метод возвращения точной копи:

	public Object clone()
	{	...
	}

По умолчанию этот метод защищен и при обращении к нему, вызывается CloneNotSupportedException

Заметьте, для инициализации большинства полей не требуется использование конструктора. Это можно сделать с помощью объявлений --, даже если для этого Вам необходимо вызвать функцию.

Также. Все Ваше поля должны быть приватными. Для доступа подклассов к некоторым полям можно использовать защищенный доступ.

ПРИМЕЧАНИЕ для пользователей Java 2. Если вы создаете класс в Java 2 (версия Java 1.2 или более поздняя), убедитесь в целесообразности реализации в вашем классе сравнительного интерфейса. Если его нет, объекты вашего класса не смогут быть сохранены в качестве ключей в TreeMaps. При реализации данного интерфейса также потребуется метод

public int compareTo(Object other)

public int compareTo(Object other)
{	...
}

Данный метод возвращает отрицательное значение, если значение может быть "меньше" другого, и положительное – если значение "больше" другого или ноля, если значения одинаковы. Заметьте, равенства должны быть согласованными с compareTo, то есть, если значение равенства true, compareTo должно выдавать ноль.

Как в большинстве классов Java 5 (как минимум тех, где сортируется объекты) должен быть реализован сравнительный интерфейс (из java.lang).

	class Foo implements Comparable<Foo>{
		int compareTo(Foo value){
			...
		}
	} 
 

Это позволяет сравнивать объекты в классе. Если а "меньше" b, a.compareTo(b) выдаст отрицательное значение. В общем, если a.equals(b), то a.compareTo(b) должно выдавать значение 0. Также a.compareTo(b) должен иметь знак, противоположный знаку b.compareTo(a). Фактически, compareTo формирует эквивалентное соотношение значений (симетрическое, переходное и возвратное), а также общий порядок. Методы java.util.Collections могут сортировать элементы автоматически, если они сортируются в массиве данных и т.д.. Также их можно вставлять в отсортированные коллекции, например, в отсортированный список, однако, есть и другие способы.