Главная | Java Incognita | Обзор систем | Студент | Пробные уроки | Коммуникатор | Вниз |
class Zexpnull{ public static void main(String [] args) { Zexpnull p=new Zexpnull(); p=null; null=p; // cannot assign a value to final variable null // incompatible types found : Zexpnull required: <nulltype> System.out.println("Hi!"); } }Результаты:
p=null;
null=p; // неправильно
null=p; // типы слева и справа от равенства - несовместимы
class Zexpnull{ public static void main(String []args){ Zexpnull p; null=p; System.out.println("Hi!"); } }Результаты:
null=p; // неправильно
null=p; // типы слева и справа от равенства - несовместимы
Опыт № 3. Условия: по ср. с № 2 ссылка инициализирована значением null
class Zexpnull{ public static void main(String []args){ Zexpnull p; p=null; null=p; System.out.println("Hi!"); } }Результаты:
null=p; // неправильно
null=p; // типы слева и справа от равенства - несовместимы
Опыт № 4. Условия: присвоение выражению null значения null
class Zexpnull{ public static void main(String []args){ null=null; System.out.println("Hi!"); } }Результаты:
Нельзя присвоить выражению null новое значение, потому что null - финальная переменная:
null=null;// неправильноВыражение null является финальной переменной в коде ей вообще невозможно присвоить значение, то есть это выражение не может находиться справа от оператора присвоения.
Опыт № 5. Условия: явное преобразование null к другому типу
public class Zexpnull{ public static void main(String []args){ Zexpnull p; p=(Zexpnull)null; //ok } }Результаты:
выражение null можно привести к произвольному типу. Мы сделали это путем явного приведения типа, но обычно это делается автоматически - при любом присвоении объектной ссылке значения null. Во время такого присвоения типом выражения null становится тип ссылки. Итак, <nulltype> может приводится к любому ссылочному типу.
Опыт № 6. Условия: проверка контроля типа со стороны компилятора. Мы приводим выражение null к типу, отличающемуся от типа выражения стоящего слева от знака равенства.
public class Zexpnull{ public static void main(String []args){ Pnull p; p=(Zexpnull)null; } } public class Pnull{ public void mainHi(){ System.out.println("Hi!"); } }Результаты:
При компиляции класса Zexpnull возникает ошибка:
incompatible types found: Zexpnull, required: PnullКроме того, что компилятор следит за типом, тут нечего сказать
p=(Zexpnull)null;
Опыт № 7. Апофеоз программирования
public class Zexpnull{ public void nHi(){ System.out.println("dry-bob"); } public static void main(String []args){ Pnull q=new Pnull(); Zexpnull p=new Zexpnull(); int s; q.mainHi(); p.nHi(); p=(Zexpnull)null; //присвоение p значения null типа Zexpnull q=(Pnull)null; //присвоение q значения null типа Pnull s=(int) null; //inconvertible types found: <nulltype> required: int } }Результаты:
Все работает, кроме последней инструкции: <nulltype> неприводим к примитивному типу.
Опыт № 8. Проверим можно ли литерал подставлять в выражения с преобразованием типа значения этого литерала.
public class Expnull{ public static void main(String []args){ int p; p=(byte)2; // приведение литерала int к типу byte System.out.println(p); } }Результаты:
все нормально. Значение литерала 2 приводится к типу byte, перед присвоением автоматически промотируется в int и присваивается переменной p.
Опыт № 9. Проверим можно ли литерал подставлять в выражения с преобразованием типа значения этого литерала.
public class Expnull1{ public static void main(String []args){ int p; p=(long)2; //несоответствие типа System.out.println(p); } }Результат: ошибка компиляции "недопустимое по типу присвоение"
possible loss of precision found: long required: int p=(long)2;
В начале значение литерала 2 преобразуется к типу long. Чтобы осуществить операцию присвоения компилятору нужно привести тип выражения стоящего справа от оператора присвоения к типу выражения стоящего слева. В данном случае требуется конвертировать тип long в тип int, однако такое преобразование может привести к потере точности (loss of precision) и запрещено Из опытов № 8 и № 9 следует, что целые литералы также могут преобразовываться из типа по умолчанию (int) в другие целые типы.
Опыт № 10 Попытка использовать null как название типа:
public class Zexpnull{ public void nHi(){ System.out.println("dry-bob"); } public static void main(String []args){ Pnull q=new Pnull(); Zexpnull p=new Zexpnull(); q.mainHi(); p.nHi(); p=(Zexpnull)null; q=(Pnull)null; q=(null)p;//неправильно воспринимается: ';' expected //q=(null)p ; ^ } }Результаты:
компилятор считает null выражением а не типом, поэтому скобки не воспринимает как оператор приведения типа.
"Имеется также особый null-тип: тип выражения null, который не имеет названия. Поскольку null-тип не имеет названия, то нет возможности объявить переменную null-типа или сделать преобразование к null-типу. Для выражения null-типа ссылка null - единственное возможное значение. Ссылка null всегда может быть преобразована к любому ссылочному типу. На практике, программист может игнорировать null-тип и делать вид, что null является просто особым литералом, тип которого может быть любым ссылочным типом".
Последняя фраза весьма любопытна: null - это литерал или все-таки - выражение? Прежде всего, согласно спецификации Java даже отдельный идентификатор является выражением (имеющим тип и значение), кроме того, любой литерал является выражением. Следовательно, null либо и выражение, и литерал, либо - выражение, но не литерал. Первый случай - банален и не заслуживал бы упоминания, а второй объяснил бы многозначительную фразу "делать вид, что null является просто особым литералом"
Итак, null является выражением, но не литералом. Действительно, литерал - это символьный эквивалент значения имеющего определенный тип. Это значение и этот тип попадают в память в виде переменной с тем же значением и того же типа что и литерал.То есть литерал представлен и на этапе компиляции и на этапе выполнения.
Выражение null имеет тип и значение, но этот тип и это значение не может, в принципе, попасть в память в виде переменной. Каждый раз во время использования null, его значение сперва приводится к определенному ссылочному типу, а только затем присваивается, то есть попадает в байт-код, а потом и в память. Значение null находясь в памяти имеет совершенно другой тип, несовместимый с первоначальным null-типом. Именно по причине того, что ссылка null со значением null-типа существует только во время компиляции, не попадает в байт -код и отсутствует во время выполнения, выражение null не является литералом, вернее сказать, требуется слегка напрячься, чтобы представить себе, что null - как бы литерал.
Конечно, задача такого плана вряд ли встретится на экзамене, но благодаря лабораторной работе мы хорошо разобрались с сущностью ссылки null и с тем, что такое литерал (и то и другое - весьма туманно излагаются во всех учебниках.
Главная | Java Incognita | Обзор систем | Студент | Пробные уроки | Коммуникатор | Вверх |