Содержание | Предыдущая | Следующая


ГЛАВА 4

Типы, значения и переменные

Ява - строго типизированный язык, это означает, что каждая переменная и каждое выражение имеет тип, который известен во времени компиляции. Типы ограничивают значения, которые может принимать переменная, (§4.5) и значения, которые могут быть результатом выражения, ограничивают набор операций, применимых к этим значениям, и определяют смысл операций. Строгая типизация помогает обнаруживать ошибки времени компиляции.

Типы языка Ява разделены на две категории: примитивные типы и ссылки. Примитивные типы (§4.2) это тип boolean и числовые типы. Числовые типы - целочисленные типы: byte, short, int, long, и char, а также вещественные типы float и double. Ссылочные типы (§4.3) - классовые типы, интерфейсные типы, и типы массивов. Имеется также специальный тип null. Объект (§4.3.1) в языке Ява - это динамически созданный экземпляр классового типа или динамически созданный массив. Значения ссылочного типа - это ссылки на объекты. Все объекты, включая массивы, поддерживают методы класса Object (§4.3.2).Строковые литералы представляются объектами класса String (§4.3.3).

Типы считаются одинаковыми (§4.3.4), если они имеют одни и те же квалифицированные имена и были загружены одним и тем же классовым загрузчиком. Имена типов используются (§4.4) в объявлениях, в приведениях, в выражениях создающих экземпляр класса, в выражениях создания массива, и в выражениях с операцией instanceof.

Переменная (§4.5) - это определенное место в памяти. Переменная простого типа всегда имеет значение именно этого типа. A переменная классового типа T, может содержать ссылку типа null или ссылку на элемент классового типа T или любого класса, являющегося подклассом T. Переменная интерфейсного типа может содержать ссылку типа null или ссылку на любой элемент любого класса интерфейса. Если T - простой тип, то переменная типа "array of T " может содержать ссылку типа null или ссылку на любой массив типа "array of T "; если T - ссылочный тип, то переменная типа "array of T" может содержать ссылку типа null или ссылку на любой массив типа " array of S " такой, что тип S совместим (§5.2) с типом T. Переменная типа Object может содержать ссылку типа null или ссылку на любой объект, независимо является ли он элементом классового типа или массивогого типа.

4.1 Виды типов и значений

Имеются два вида типов в языке Ява: примитивные типы (§4.2) и ссылочные типы (§4.3). Имеется соответственно два вида значений данных, которые могут быть сохранены в переменных, переданы как параметры, возвращаемые методами, и вычислены: примитивные значения (§4.2) и значения U ссылки (§4.3).

Type:

	PrimitiveType

	ReferenceType

Имеется также специальный тип null, тип null-выражения, которое не имеет никакого имени. Так как тип null не имеет никакого имени, невозможно объявить переменную типа null или привести к типу null. Ссылка типа null является единственным возможным значением выражения типа null. Ссылка типа null может быть всегда приведена к любому из ссылочных типов. Практически, программист на языке Ява может игнорировать тип null и только признавать, что null - есть просто специальный литерал, который может иметь любой ссылочный тип.

4.2 Примитивные типы и значения

Примитивный тип предопределен языком Ява и назван зарезервированным ключевым словом (§3.9):

Разные простые значения не могут иметь одну и ту же переменную. Переменная, чей тип - примитивный тип всегда имеет примитивное значение того же самого типа. Значение переменной примитивного типа может быть изменено только операцией присваивания.

Числовые типы - это целочисленные типы и вещественные типы.

Целочисленные типы: byte, short, int, и long, значения данных типов являются 8-битовыми, 16-битовыми, 32-битовыми и 64-битовыми, целыми числами со знаком, соответственно, и char, его значения имеют 16-битовое представление целыми числами без знака, являющимися Unicode-символами.

Вещественные типы: float, значениями являются - 32-разрядные IEEE 754 числа с плавающей точкой и double, значениями являются - 64-разрядные IEEE 754 числа с плавающей точкой.

Тип boolean имеет ровно два значения: true(истина) и false(ложь).

4.2.1 Целочисленные типы и значения

Значения целочисленных типов - целые числа в следующих диапазонах:

4.2.2 Целочисленные операции

Язык Ява обеспечивает ряд операций, с целочисленными значениями:

Другие полезные конструкторы, методы и константы предопределены в классах Integer (§20.7), Long (§20.8), и Character (§20.5).

Если целочисленная операция, отличная от операции сдвига, имеет по крайней мере один операнд типа long, то операция выполняется используя 64-разрядное представление, и результат числовой операции имеет тип long. Если тип одного из операндов отличен от long, то он сначала расширяется (§5.1.2) чтобы иметь тип long (§5.6). Иначе, будет выполнена операция, использующая 32-разрядное представление, и результат целочисленной операции будет иметь тип int. Если же тип операнда не int, то сначала он будет расширен, чтобы иметь тип int.

Встроенные целочисленные операции никогда не дают переполнения. Единственные числовые операции, которые генерируют исключительные ситуации (§11) - операция целочисленного деления / (§15.16.2) и операция целочисленного остатка % (§15.16.3), которые выдают ошибку ArithmeticException, если правый операнд - ноль.

Пример:

class Test {
	public static void main(String[] args) {
		int i = 1000000;
		System.out.println(i * i);
		long l = i;
		System.out.println(l * l);
		System.out.println(20296 / (l - i));
	}
}

Выведет на экран:

-727379968
1000000000000

и затем сталкивается с ArithmeticException в делении на 1-i, потому что 1-i - это ноль. Первое умножение выполняется в 32-разрядном представлении, в то время как второе умножение - умножение типа long.

Значение -727379968 это десятичное значение младших 32 битов математического результата, 1000000000000, который является значением, слишком большим для типа int.

Любое значение любого целочисленного типа может быть приведено к любому числовому типу или быть получено из любого числового типа. Нет никакой связи между целочисленными типами и типом boolean.

4.2.3 Вещественные типы и значения

Вещественные типы - это float и double, представляющие в одиночном – 32 битном или в двоичном – 64 битном формате IEEE 754 значения и операции, как определено в IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Standard 754-1985 (IEEE, New York).

IEEE 754 стандарт не только для положительных и отрицательных чисел, но также для положительных и отрицательных нолей, положительных и отрицательных бесконечностей, и специальных Not-a-Number (“не число”, сокращенно NaN). Значение NaN используется, чтобы представить результат некоторых операций, таких как деление ноля на ноль. Типы NaN констант типа float и double предопределены как Float.NaN (§20.9.5) и Double.NaN (§20.10.5).

Конечные отличные от нуля значения типа float имеют форму, где s - это или +1, или -1, m - положительное целое число меньшее и e - целое число между -149 и 104, включительно. Те формы, в которых m–положительно, но меньше и e равно -149, как говорится, являются денормализованными.

Конечные отличные от нуля значения типа double имеют форму, где s или +1, или -1, m - положительное целое число меньшее , и e - целое число между -1075 и 970, включительно. Те формы, в которых m–положительно, но меньше и e равно -1075, как говорится, являются денормализованными.

За исключением NaN, вещественные значения имеют двоичное представление; NaN в порядке возрастания : отрицательная бесконечность, отрицательные конечные значения отличные от нуля, отрицательный ноль, положительный ноль, положительные конечные значения отличные от нуля, и положительная бесконечность.

Положительный ноль и отрицательный ноль равны; таким образом результат выражения 0.0 == –0.0 есть true, а результат 0.0 > –0.0 есть false. Но другие операции могут отличать положительный и отрицательный ноль; например, 1.0/0.0 имеет значение положительной бесконечности, в то время как значение 1.0/-0.0 - отрицательная бесконечность. Операции Math.min и Math.max также отличают положительный ноль и отрицательный ноль.

NaN не имеют двоичного представления, таким образом, числовые операции сравнения <, <=, >, и >= возвращают false если оба операнда - NaN (§15.19.1). Операция равенства == возвращает false, если один из операндов - NaN, и операция неравенства != возвращает true, если один из операндов - NaN 15.20.1). В частности x != x true тогда и только тогда, когда x - NaN, и (x < y) ==! (x >=y) будет false, если x или y - NaN.

Любое значение вещественного типа может быть приведено к любому значению числового типа или быть получено из любого числового типа. Не существует никакой связи между вещественными типами и типом boolean.

4.2.4 Вещественные операции

Язык Ява обеспечивает ряд операций над вещественными значениями:

Другие полезные конструкторы, методы и константы определены в классах Float (§20.9), Double (§20.10), и Math (§20.11).

Если по крайней мере один из операндов в двухместной операции имеет вещественный тип, то операция является вещественной операцией, даже если один из операндов целочисленный.

Если по крайней мере один из операндов числовой операции имеет тип double, то операция выполняется с использованием 64-разрядной вещественной арифметики, и результатом числовой операции будет значение типа double. (Если тип одного из операндов не double, то его сначала расширяют, чтобы он имел тип double (§5.6). Иначе, операция выполняется, используя 32-разрядную вещественную арифметику, и результат числовой операции имеет тип float. Если один из операндов имеет тип отличный от float, то его сначала расширяют, чтобы он имел тип float.

Операции над значениями вещественного типа ведут себя в соответствии с IEEE 754. В частности, язык Ява требует поддержки IEEE 754 денормализованных чисел с плавающей точкой и постепенной потери значимых разрядов, которые упрощают выполнение некоторых числовых алгоритмов. Вещественные операции в языке Ява не ”округляют результат к нулю”, если он - денормализованное число.

При вычислении вещественных арифметических выражений языка Ява результат каждой операции округляется с точностью результата всего выражения. Неточные результаты должны быть округлены до значения, самого близкого к точному; если два самых близких представления значений - сравнительно близки, то выбирается представление с меньшим значащим нолем. Этот режим округления является установленным по умолчанию в стандарте IEEE 754, и известен как округление до ближайшего.

Язык Ява использует округление до нуля при преобразовании вещественного значения к целочисленному (§5.1.3), которое действует, в этом случае, отсекая у числа биты мантиссы. Округление до нуля выбирает в качестве своего результата ближайшее и не превосходящее его точное значение.

В языке Ява в результате операций с вещественными числами не возникает исключительных ситуаций (§11). Результатом операции, приводящей к переполнению, является бесконечность со знаком; результатом операции, приводящей к потере значащих разрядов, является ноль со знаком; и результатом операции, приводящей к неопределенному результату, является NaN. Все числовые операции с NaN в качестве операнда имеют NaN в результате. Как уже было сказано, NaN не имеет численного представления, таким образом операция проверки на равенство, включающая один или два NaN возвращает всегда false, а операция !=, включающая NaN, возвращает true, даже для случая x != x, когда x - NaN.

Пример программы:

class Test {

	public static void main(String[] args) {

		// пример переполнения:
		double d = 1e308;
		System.out.print("overflow produces infinity: ");
		System.out.println(d + "*10==" + d*10);

		// пример пополнения:
		d = 1e-305 * Math.PI;
		System.out.print("gradual underflow: " + d + "\n      ");
		for (int i = 0; i < 4; i++)
			System.out.print(" " + (d /= 100000));
		System.out.println();

		// пример NaN:
		System.out.print("0.0/0.0 is Not-a-Number: ");
		d = 0.0/0.0;
		System.out.println(d);

		// пример неточных результатов и округления:
		System.out.print("inexact results with float:");
		for (int i = 0; i < 100; i++) {
			float z = 1.0f / i;
			if (z * i != 1.0f)
				System.out.print(" " + i);
		}
		System.out.println();

		// другой пример неточных результатов и округления:
		System.out.print("inexact results with double:");
		for (int i = 0; i < 100; i++) {
			double z = 1.0 / i;
			if (z * i != 1.0)
				System.out.print(" " + i);
		}
		System.out.println();

		// пример целочисленного округления:
		System.out.print("cast to int rounds toward 0: ");
		d = 12345.6;
		System.out.println((int)d + " " + (int)(-d));
	}
}

Выведет на экран:

overflow produces infinity: 1.0e+308*10==Infinity
gradual underflow: 3.141592653589793E-305
	3.1415926535898E-310 3.141592653E-315 3.142E-320 0.0
0.0/0.0 is Not-a-Number: NaN
inexact results with float: 0 41 47 55 61 82 83 94 97
inexact results with double: 0 49 98
cast to int rounds toward 0: 12345 -12345

Этот пример показывает, что потеря значимости может приводить к потере точности.

Когда i = 0 (вызывает деление на ноль), то z становится положительной бесконечностью, и z*0 становится NaN, уже не равным 1.0.

4.2.5 Логический тип boolean и логические значения

Тип boolean позволяет представить логическую величину, которая может принимать два значения true (истинный) или false (ложный) (§3.10.3). К типу boolean применимы следующие операции:

Логические выражения определяют поток управления в некоторых видах операторов:

Логическое выражение также устанавливает, которое из подвыражений вычисляется условной операцией ?: (§15.24).

В управляющих операторах, и в качестве первого операнда условной операции ?: могут использоваться только логические выражения. Значение x целочисленного типа может быть преобразовано к типу boolean, следуя соглашениям языка Си, где любое отличное от нуля значение есть true (истина), с помощью выражения x!=0. Ссылка на объект obj может быть преобразована к логическому типу boolean, следуя соглашениям языка Си, где любая ссылка тип которой не null есть true (истина), с помощью выражения obj!=null.

Допускается приведение значений типа boolean в тип boolean (§5.1.1); никакое другое приведение на типе boolean не позволяется. Логический тип может быть преобразован в строку строковым преобразованием (§5.4).

4.3 Ссылочные типы и значения

Существует три вида ссылочных типов: классовый тип (§8), интерфейсный тип (§9), и тип массив (§10).

Имена описаны в §6; имена типов в §6.5 и более подробно в §6.5.4.

Простой пример:

class Point { int[] metrics; }

interface Move { void move(int deltax, int deltay); }

объявляет классовый тип Point, интерфейсный тип Move, и использует тип массив int[] (элементы массива имеют тип int) чтобы объявить поле metrics класса Point.

4.3.1 Объекты

Объект это экземпляр класса или массив.

Ссылочные значения (часто называемые ссылками) - это указатели на объекты, и специальная ссылка типа null, которая не ссылается ни на какой объект.

Экземпляр класса создается явно выражением, создающим экземпляр (§15.8), или, вызовом метода newInstance класса Class (§20.3.8). Массив создается явно выражением, создающим массив (§15.8).

Новый экземпляр класса создается неявно, когда в выражении использована операция конкатенации строк + (§15.17.1), результатом которой будет новый объект типа String (§4.3.3, §20.12). Новый объект типа массив создается неявно, когда вычисляется новое инициализирующее массив выражение (§10.6); это может происходить, когда инициализируется класс или интерфейс (§12.4), когда создается новый экземпляр класса (§15.8) или когда выполнен оператор объявления локальной переменной (§14.3).

Многие из этих случаев иллюстрируются в следующем примере:

class Point {
	int x, y;
	Point() { System.out.println("default"); }
	Point(int x, int y) { this.x = x; this.y = y; }

	// Экземпляр Point создан явно во время инициализаци класса:
	static Point origin = new Point(0,0);

	// Строка может быть создана неявно операцией +:
	public String toString() {

		return "(" + x + "," + y + ")";

	}
}


class Test {
	public static void main(String[] args) {
		// Point создан явно, используя newInstance:
		Point p = null;
		try {
			p = (Point)Class.forName("Point").newInstance();
		} catch (Exception e) {
			System.out.println(e);
		}


		// Массив создан неявно с помощью конструктора массива:
		Point a[] = { new Point(0,0), new Point(1,1) };


		// Строки созданы неявно операциями +:
		System.out.println("p: " + p);
		System.out.println("a: { " + a[0] + ", "

										   + a[1] + " }");


		// Массив создан явно выражением создания массива:
		String sa[] = new String[2];
		sa[0] = "he"; sa[1] = "llo";
		System.out.println(sa[0] + sa[1]);
	}
}

который выводит на экран:

default
p: (0,0)
a: { (0,0), (1,1) }
hello

Операции со ссылками на объекты:

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

Пример программы:

class Value { int val; }
class Test {
	public static void main(String[] args) {
		int i1 = 3;
		int i2 = i1;
		i2 = 4;
		System.out.print("i1==" + i1);
		System.out.println(" but i2==" + i2);
		Value v1 = new Value();
		v1.val = 5;
		Value v2 = v1;
		v2.val = 6;
		System.out.print("v1.val==" + v1.val);
		System.out.println(" and v2.val==" + v2.val);
	}
}

Выводит результат:

i1==3 but i2==4
v1.val==6 and v2.val==6

потому что v1.val и v2.val ссылаются на одну и ту же переменную экземпляра (§4.5.3) в одном из объектов Value, созданного единственным выражением new, хотя i1 и i2 являются различными переменными.

Примеры создания и использования массивов смотрите в §10 и §15.9.

Каждый объект имеет связанный с ним замок (§17.13), который используется (синхронизированными) synchronized-методами (§8.4.3) и оператором synchronized (§14.17), чтобы обеспечить управление параллельным доступом к его состоянию различными потоками (§17.12, §20.20).

4.3.2 Класс Object

Стандартный класс Object - суперкласс (§8.1) всех других классов. Переменная типа Object может содержать ссылку на любой объект, который является экземпляром класса или массив (§10). Все классы и массивы наследуют методы класса Object, которые перечислены здесь и полностью определены в §20.1:

package java.lang;
public class Object {
	public final Class getClass() { . . . }
	public String toString() { . . . }
	public boolean equals(Object obj) { . . . }
	public int hashCode() { . . . }
	protected Object clone()
		throws CloneNotSupportedException { . . . }
	public final void wait()

		throws IllegalMonitorStateException,

			InterruptedException { . . . }
	public final void wait(long millis)
		throws IllegalMonitorStateException,
			InterruptedException { . . . }
	public final void wait(long millis, int nanos) { . . . }
		throws IllegalMonitorStateException,
			InterruptedException { . . . }
	public final void notify() { . . . }
		throws IllegalMonitorStateException
	public final void notifyAll() { . . . }
		throws IllegalMonitorStateException
	protected void finalize()
		throws Throwable { . . . }
}

Члены Object следующие: 

4.3.3 Класс String

Экземпляр класса String (§20.12) представляется последовательностями Unicode-символов. Строковый объект имеет постоянное (неизменное) значение. Строковые литералы (§3.10.5) - ссылки на экземпляры класса String. Операция конкатенации строк + (§15.17.1) неявно создает новый строковый объект.

4.3.4 Когда ссылочные типы одинаковы

Два ссылочных типа называются одинаковыми типами, если:

4.4 Где используются типы

Типы используются, когда они появляются в описаниях или в некоторых выражениях.

Следующий фрагмент содержит один или несколько случаев каждого вида употребления типа:

import java.util.Random;

class MiscMath {

	int divisor;


	MiscMath(int divisor) {
		this.divisor = divisor;
	}


	float ratio(long l) {
		try {
			l /= divisor;
		} catch (Exception e) {
			if (e instanceof ArithmeticException)
				l = Long.MAX_VALUE;
			else
				l = 0;
		}
		return (float)l;
	}


	double gausser() {
		Random r = new Random();
		double[] val = new double[2];
		val[0] = r.nextGaussian();
		val[1] = r.nextGaussian();
		return (val[0] + val[1]) / 2;
	}

}

В этом примере, типы используются в следующих описаниях:

и в выражениях следующих видов:

 

4.5 Переменные

Переменная размещается в памяти и имеет тип, иногда этот тип называется типом времени компиляции, который является или примитивным типом (§4.2), или ссылочным типом (§4.3). Переменная всегда содержит значение, которое совместимо по присваиванию (§5.2) с типом. Значение переменной изменяется либо с помощью присваивания (§15.25), либо с помощью операций ++ (инкремента) или -- (декремента) в префиксной или постфиксной форме (§15.13.2, §15.13.3, §15.14.1, §15.14.2).

Совместимость значения переменной с типом гарантируется проектом языка Ява. По умолчанию значения совместимы (§4.5.4) и все присваивания переменной проверяются для совместимости присваивания (§5.2), обычно во время компиляции, но, в отдельных случаях во время выполнения (§10.10).

4.5.1 Переменные примитивного типа

Переменная примитивного типа всегда содержит значение только примитивного типа.

4.5.2 Переменные ссылочного типа

Переменная ссылочного типа может содержать каждую из следующих ссылок:

4.5.3 Виды переменных

Имеется семь видов переменных:

  1. Переменная класса - поле, объявленное, используя ключевое слово static в описании класса (§8.3.1.1), или без ключевого слова static в описании (§9.3) интерфейса. Переменная класса создается когда класс или интерфейс загружается (§12.2) и инициализируется значением установленным по умолчанию (§4.5.4). Переменная класса перестает существовать, когда класс или интерфейс выгружен (§12.8), после всех необходимых заключительных действий класс или интерфейс (§12.6) будет завершен.
  2. Переменная экземпляра - поле, объявленное в пределах описания класса без использования ключевого слова static (§8.3.1.1). Если класс T имеет поле a которое является переменной экземпляра a, тогда новая переменная экземпляра создается и инициализируется значением установленным по умолчанию (§4.5.4) как часть каждого вновь созданного объекта класса T или любого класса, который является подклассом T (§8.1.3). Переменная экземпляра перестает существовать когда объект, на поле которого больше нет ссылок, после всех необходимых заключительных действий будет завершен (§12.6).
  3. Компоненты массива - безымянные переменные, которые создаются и инициализируются значением установленным по умолчанию (§4.5.4) всякий раз, когда создается новый объект массива (§15.9). Компоненты массива перестают существовать, когда на массив больше не ссылаются. Описание массивов см. в §10.
  4. Параметры метода (§8.4.1) - имена значений аргументов, переданных методу. Для каждого параметра, объявленного в описании метода, новый параметр-переменная создается каждый раз, когда метод активизирован (§15.11). Новая переменная - инициализируется соответствующим значением аргумента из вызова метода. Параметр метода прекращает существовать, когда выполнение тела метода закончено.
  5. Параметры конструктора (§8.6.1) - имена значений аргументов, переданных конструктору. Для каждого параметра, объявленного в объявлении конструктора, новая переменная-параметр создается каждый раз, когда выражение создающее экземпляр класса (§15.8) или явный конструктор вызова (§8.6.5) вызывает этот конструктор. Новая переменная инициализируется соответствующим значением аргумента из создающего выражения или вызова конструктора. Параметр конструктора прекращает существовать когда выполнение тела конструктора завершено.
  6. Параметр обработчика исключений создается каждый раз, когда исключение захватывается предложением catch оператора try (§14.18). Новая переменная инициализируется существующим объектом, связанным с исключением (§11.3, §14.16). Параметр обработчика исключений перестает существовать, когда выполнение блока, связанного с предложением catch закончено.
  7. Локальные переменные, объявленные с помощью операторов описания локальных переменных (§14.3). Всякий раз, когда поток управления входит в блок (§14.2) или оператор for (§14.12), для каждой локальной переменной создается новая переменная, немедленно объявленная в операторе описания локальной переменной, которая содержится в пределах того блока или оператора for. Оператор описания локальной переменной может содержать выражение, которое инициализирует переменную. Локальная переменная с инициализирующим выражением не инициализируется, однако, она выполняется до оператора описания локальной переменной, который ее и объявляет. (Правила определяющего присвоения (§16), не допускающего значения локальной переменной, используются прежде, чем будет проинициализирована, иначе присваивается значение.) Локальная переменная прекращает существовать, когда выполнение блока или оператора for завершено.

 

Это не только для одной исключительной ситуации, локальная переменная могла бы всегда рассматриваться после того как она создается, когда выполнено описание оператора этой локальной переменной . Исключительная ситуация содержит оператор switch (§14.9), где это возможно для контроля выхода из блока, но при этом обходит выполнение описания оператора локальной переменной. Из-за ограничений, наложенных правилами определяющего присваивания (§16), локальная переменная, объявленная с помощью такого обойденного оператора описания локальной переменной не может использоваться прежде, чем ей будет присвоено значение с помощью присваивания выражения (§15.25).

Следующий пример содержит несколько различных видов переменных:

class Point {
	static int numPoints;								// numPoints - переменная класса
	int x, y;								// x и y - переменные экземпляра
	int[] w = new int[10];								// w[0] - компонент массива
	int setX(int x) {								// x - параметр метода
		int oldx = this.x;							// oldx - локальная переменная
		this.x = x;
		return oldx;
	}
}

4.5.4 Начальные значения переменных

Каждая переменная в программе на языке Ява должна иметь некоторое значение прежде, чем это значение будет использовано:

Пример программы:

class Point {
	static int npoints;
	int x, y;
	Point root;
}


class Test {
	public static void main(String[] args) {
		System.out.println("npoints=" + Point.npoints);
		Point p = new Point();
		System.out.println("p.x=" + p.x + ", p.y=" + p.y);
		System.out.println("p.root=" + p.root);
	}
}

напечатает:

npoints=0
p.x=0, p.y=0
p.root=null

иллюстрирующий инициализацию npoints по умолчанию, которая происходит когда класс Point подготавливается (§12.3.2), и инициализацию по умолчанию x, y и root, которая происходит, когда создан новый экземпляр класса new Point. Смотрите §12 для полного описания всех аспектов загрузки, компоновки и инициализации классов и интерфейсов, плюс описание обработки классов при создании новых экземпляров класса.

4.5.5 Типы переменных и классы объектов

Каждый объект принадлежит некоторому специфическому классу: т.е. классу, упомянутому в выражении создания, которое произвело данный объект, классу, чей класс объекта использовался для вызова нового экземпляра метода (§20.3.6), чтобы произвести объект, или класс String для объектов, неявно созданных строковой операцией конкатенации + (§15.17.1). Этот класс назван классом объекта. (Массивы также имеют класс, как описано в конце этого раздела.) Упомянутый объект является экземпляром данного класса и всех суперклассов этого класса.

(Иногда говорят, что переменная или выражение имеет "тип времени выполнения", но это - злоупотребление терминологией; они ссылаются на класс объекта обращаясь к значению переменной или выражения во время выполнения (в предположении, что значение - не null). Короче говоря, тип - это понятие времени компиляции. Переменная или выражение имеют тип; объект или массив не имеют никакого типа, но принадлежат классу.)

Тип переменной всегда объявляется, а тип выражения может быть установлен во время компиляции. Тип ограничивает значения, которые может принимать переменная или иметь выражение во время выполнения. Если значение во время выполнения - это ссылка, не равная null, и она указывает на объект или массив, который имеет класс (не тип), то этот класс обязательно будет совместимым с типом времени компиляции.

Хотя переменная или выражение могут иметь тип времени компиляции, который является типом интерфейса, но не существует экземпляров интерфейсов. Переменная или выражение, чей тип - это тип интерфейса, может ссылаться на любой объект, если класс объекта реализует (§8.1.4) данный интерфейс.

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

public interface Colorable {
	void setColor(byte r, byte g, byte b);
}

class Point { int x, y; }

class ColoredPoint extends Point implements Colorable {

	byte r, g, b;


	public void setColor(byte rv, byte gv, byte bv) {
		r = rv; g = gv; b = bv;
	}

}


class Test {
	public static void main(String[] args) {
		Point p = new Point();
		ColoredPoint cp = new ColoredPoint();
		p = cp;
		Colorable c = cp;
	}
}

В этом примере:

Каждый массив также имеет класс; метод getClass (§20.1.1), когда он вызван для объекта массив, возвратит класс объекта (класса Class), который представляет класс массива. Классы для массивов имеют непривычные имена, которые не являются идентификаторами языка Ява; например, класс для массива компонент типа int имеет имя " [I " так что значение выражения:

new int[10].getClass().getName()

это строка " [I "; для получения более подробной информации смотрите §20.1.1.


Содержание | Предыдущая | Следующая