Перейти на главную   
  helloworld.ru - документация и книги по программированию  
helloworld.ru - документация и книги по программированию
    главная     хостинг    
Поиск по сайту:  
Смотрите также
Языки программирования
C#
MS Visual C++
Borland C++
C++ Builder
Visual Basic
Quick Basic
Turbo Pascal
Delphi
JavaScript
Java
PHP
Perl
Assembler
AutoLisp
Fortran
Python
1C

Интернет-технологии
HTML
VRML
HTTP
CGI
FTP
Proxy
DNS
протоколы TCP/IP
Apache

Web-дизайн
HTML
Дизайн
VRML
PhotoShop
Cookie
CGI
SSI
CSS
ASP
PHP
Perl

Программирование игр
DirectDraw
DirectSound
Direct3D
OpenGL
3D-графика
Графика под DOS

Алгоритмы
Численные методы
Обработка данных

Сис. программирование
Драйверы

Базы данных
MySQL
SQL

Другое

Хостинг


Друзья
demaker.ru
Реклама

Лучший хостинг. Аренда серверов




helloworld.ru

ГЛАВА 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):

    PrimitiveType:
    
    	NumericType
    
    	boolean
    
    NumericType:
    
    	IntegralType
    
    	FloatingPointType
    
    IntegralType: one of
    
    	byte short int long char
    
    FloatingPointType: one of
    
    	float double
    

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

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

Целочисленные типы: 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 Целочисленные типы и значения

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

  • Для byte, от -128 до 127, включительно
  • Для short, от -32768 до 32767, включительно
  • Для int, от -2147483648 до 2147483647, включительно
  • Для long, от -9223372036854775808 до 9223372036854775807, включительно
  • Для char, от '\u0000' до '\uffff включительно, т.е. от 0 до 65535

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

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

  • Операторы сравнения, которые возвращают значение типа boolean:
    • Числовые операции сравнения <, < =, >, и > = (§15.19.1)
    • Числовые операции равенства = = и != (§15.20.1)
  • Числовые операции, которые возвращают значение типа int или long:
    • Унарный плюс и минус + и – (§15.14.3, §15.14.4)
    • Мультипликативные операции *, /, и % (§15.16)
    • Аддитивные операции + и – (§15.17.2)
    • Оператор инкремента ++, в префиксной (§15.14.1) и постфиксной (§15.13.2) форме
    • Оператор декремента --, в префиксной (§15.14.2) и постфиксной (§15.13.3) форме
    • Операция сдвига со знаком и без знака <<, >>, и >>> (§15.18)
    • Операция поразрядного дополнения ~ (§15.14.5)
    • Целочисленные поразрядные операции &, |, и ^ (§15.21.1)
  • Условная операция ?: (§15.24)
  • Оператор приведения, который может преобразовывать целочисленное значение в значение любого числового типа (§5.4, §15.15)
  • Оператор конкатенации строк + (§15.17.1), который, когда дан строковый операнд и целочисленный операнд, преобразует целочисленный операнд в строку, представляющую значение в десятичном коде, и затем получает новую строку, которая является конкатенацией двух строк

Другие полезные конструкторы, методы и константы предопределены в классах 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 Вещественные операции

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

  • Операции сравнения, которые возвращают значение типа boolean:
    • Числовые операции сравнения <, <=, > и >= (§15.19.1)
    • Числовые операции равенства == и != (§15.20.1)
  • Числовые операции, которые возвращают значение типа float или double
    • Унарный плюс и минус + и – (§15.14.3, §15.14.4)
    • Мультипликативные операции *, /, и % (§15.16)
    • Аддитивные операции + и – (§15.17.2)
    • Операции инкремента ++, в префиксной (§15.14.1) и постфиксной (§15.13.2) форме
    • Операции декремента --, в префиксной (§15.14.2) и постфиксной (§15.13.3) форме
  • Условная операция ?: (§15.24)
  • Операция приведения, которая может преобразовывать вещественное значение в значение любого числового типа (§5.4, §15.15)
  • Операция конкатенации строк + (§15.17.1), которая, когда дан строковый операнд и вещественный операнд, преобразует вещественный операнд в строку, представляющую его значение в десятичном коде (без потери информации) и затем получает новую строку, которая является конкатенацией двух строк.

Другие полезные конструкторы, методы и константы определены в классах 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.20.2)
  • Операция логического дополнения ! (§15.14.6)
  • Логические операции &, ^, и | (§15.21.2)
  • Операции условное-и & & (§15.22) и условное-или || (§15.23)
  • Условная операция ?: (§15.24)
  • Операция конкатенации строк + (§15.17.1), которая, когда дан операнд типа String и логический операнд, преобразует данный логический операнд в операнд типа String (либо "true", либо "false"), созданная таким образом строка и будет конкатенацией двух строк.

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

Логическое выражение также устанавливает, которое из подвыражений вычисляется условной операцией ?: (§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).

    ReferenceType:
    
    	ClassOrInterfaceType
    
    	ArrayType
    
    ClassOrInterfaceType:
    
    	ClassType
    
    	InterfaceType
    
    ClassType:
    
    	TypeName
    
    InterfaceType:
    
    	TypeName
    
    ArrayType:
    
    	Type [ ]
    

Имена описаны в §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

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

  • Доступ к полю, с использованием квалифицированного имени (§6.6) или выражения доступа к полю (§15.10)
  • Вызов метода (§15.11)
  • Операция приведения (§5.4, §15.15)
  • Когда дан строковый операнд и ссылка, операция конкатенации строк + (§15.17.1), преобразует ссылку в строку, при этом используется метод toString (§20.1.2) упомянутого объекта (если ссылка или результат вычисления toString - есть ссылка типа null, то используется "null"), и тогда ее результат - вновь созданная строка и будет конкатенацией двух строк.
  • Операция instanceof (§15.19.2)
  • Операции ссылочных равенств == и != (§15.20.3)
  • Условная операция ? : (§15.24).

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

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

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 следующие: 

  • Метод getClass возвращает объект Class (§20.3), который представляет класс объекта. Объект Class существует для каждого ссылочного типа. Это может использоваться, например, для того чтобы обнаружить полностью квалифицированное имя класса, его членов, его непосредственный суперкласс, и любые интерфейсы, которые им реализованы. Метод класса, который объявляется со словом synchronized (§8.4.3.5) синхронизируется на замке, связанном с объектом Class данного класса.
  • Метод toString возвращает строковое представление объекта.
  • Методы equals и hashCode объявлены специально для перемешанных таблиц таких как java.util.Hashtable (§21.7). Метод equals определяет понятие равенства объекта, которое основывается на сравнении значения, а не ссылки.
  • Метод clone используется для создания дубликата объекта.
  • Методы wait, notify, и notifyAll используются в параллельном программировании, т.е. при использовании потоков, как описано в §17.
  • Метод finalize выполняется только до того как объект уничтожается это описано в §12.6.

4.3.3 Класс String

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

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

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

  • Они оба классовые или интерфейсные, загружены одним и тем же загрузчиком классов и имеют одно и тоже полное квалифицированное имя (§6.6), в котором они, как говорится, являются одинаковым классом или интерфейсом.
  • Они оба являются типами массива и имеют одинаковый тип элементов (§10).

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;
	}

}

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

  • Импортированные типы (§7.5); здесь тип Random, импортирован из типа java.util.Random пакета java.util, уже объявлен
  • Поля, которые являются переменными класса и переменными экземпляра класса (§8.3), и константами интерфейсов (§9.3); здесь поле divisor в классе MiscMath, будет уже объявлено как int
  • Параметры метода (§8.4.1); здесь параметр l метода ratio объявлен как long
  • Результаты метода (§8.4); здесь результат метода ratio объявленный как float, и результата метода gausser объявленного как double
  • Параметры конструктора (§8.6.1); здесь параметр конструктора для MiscMath, объявленного как int
  • Локальные переменные (§14.3, §14.12); локальные переменные r и val метода gausser, объявляются Random и double[] ( массив из double)
  • Параметры обработчика исключений (§14.18); здесь обработчик исключений имеет параметр e предложения catch, уже объявлен как Exception

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

 

  • Создание экземпляра класса (§15.8); здесь локальная переменная r метода gausser инициализирована выражением, создающим экземпляр класса, которое использует тип Random
  • Создание массива (§15.9); здесь локальная переменная val метода gausser - инициализируется выражением создающим массив, которое создает массив из double c размером 2
  • Приведения (§15.15); здесь оператор return из метода ratio использует в приведении тип float
  • Операция instanceof (§15.19.2); здесь операция instanceof проверяет совместимость eе с типом ArithmeticException

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 Переменные ссылочного типа

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

  • Ссылка типа null
  • Ссылка на любой объект (§4.3), чей класс (§4.5.5) есть совместимая по присваиванию (§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 Начальные значения переменных

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

  • Каждая переменная класса, переменная экземпляра, или компонент массива инициализируется значением, в момент создания (§15.8, §15.9, §20.3.6):
  • Для типа byte, значение по умолчанию - ноль, то есть (byte) 0.
  • Для типа short, значение по умолчанию - ноль, то есть (short) 0.
  • Для типа int, значение по умолчанию - ноль, то есть 0.
  • Для типа long, значение по умолчанию - ноль, то есть 0L.
  • Для типа float, значение по умолчанию - положительный машинный ноль, то есть 0.0f.
  • Для типа double, значение по умолчанию - положительный машинный ноль, то есть 0.0d.
  • Для типа char, значение по умолчанию ‘\u0000‘.
  • Для типа boolean, значение по умолчанию false.
  • Для всех ссылочных типов (§4.3) значение по умолчанию null.
  • Каждый параметр метода (§8.4.1) инициализируется соответствующими значениями переданных аргументов метода (§15.11).
  • Каждый параметр конструктора (§8.6.1) инициализируется соответствующим значением аргумента, переданным при создании экземпляра класса или при явном вызове конструктора (§8.6.5).
  • Параметр обработчика исключений (§14.18) инициализируется сгенерированным объектом, представляющим данное исключение (§11.3, §14.16).
  • Локальной переменной (§14.3, §14.12) должно быть явно задано значение перед тем как она будет использована, значение задается инициализацией (§14.3) или присваиванием (§15.25) таким путем, чтобы удовлетворялись правила определяющего присваивания, проверяемые компилятором.

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

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;
	}
}

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

  • Локальная переменная p метода main класса Test имеет тип Point и первоначально предназначена для ссылки на новый экземпляр класса Point.
  • Локальная переменная cp имеет тип ColoredPoint, и первоначально предназначена для ссылки на новый экземпляр класса ColoredPoint.
  • Присваивание значения cp переменной p заставляет p содержать ссылку на объект ColoredPoint. Это разрешается, так как ColoredPoint - подкласс Point, поэтому класс ColoredPoint совместим по присваиванию (§5.2) с типом Point. Объект ColoredPoint включает поддержку для всех методов Point. В дополнение к специфическим полям r, g, и b, он содержит и поля класса Point, а именно x и y.
  • Типом локальной переменной с является интерфейсный тип Colorable, так что с может содержать ссылку на любой объект, чей класс реализует Colorable; например, она может содержать ссылку на ColoredPoint.
  • Заметьте, что выражение вида " new Colorable () " неверно, потому что невозможно создать экземпляр интерфейса, а только класса.

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

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

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


[ Назад | Оглавление | Далее ]










helloworld.ru © 2001-2021
Все права защищены