Ильдар Хабибуллин - Java 7 [Наиболее полное руководство]
- Название:Java 7 [Наиболее полное руководство]
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2012
- ISBN:978-5-9775-0735-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Ильдар Хабибуллин - Java 7 [Наиболее полное руководство] краткое содержание
Java 7 [Наиболее полное руководство] - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
i = Integer.parseInt(args[0]); sh = Short.parseShort(args[0]);
d = Double.parseDouble(args[1]); d1 = new Double(args[1]); k1 = new Integer(args[0]); }catch(Exception e){} double x = 1.0 / 0.0; System.out.println("i = " + i); System.out.println("sh = " + sh);
System.out.println("d = " + d);
System.out.println("k1.intValue() = " + k1.intValue()); System.out.println("d1.intValue() = " + d1.intValue());
System.out.println("k1 > k2? " + k1.compareTo(k2));
System.out.println("x = " + x);
System.out.println("x isNaN? " + Double.isNaN(x));
System.out.println("x isInfinite? " + Double.isInfinite(x));
System.out.println("x == Infinity? " + (x == Double.POSITIVE INFINITY)); System.out.println("d = " + Double.doubleToLongBits(d));
System.out.println("i = " + Integer.toBinaryString(i));
System.out.println("i = " + Integer.toHexString(i));
System.out.println("i = " + Integer.toOctalString(i));
}
}
Методы parseInt () и конструкторы классов требуют обработки исключений, поэтому в листинг 4.1 вставлен блок try{}catch(){}. Обработку исключительных ситуаций мы подробно разберем в главе 21.
Начиная с версии Java SE 5 в JDK входит пакет java.util.concurrent.atomic, в котором, в частности, есть классы AtomicInteger и AtomicLong, обеспечивающие изменение числового значения этих классов на уровне машинных команд. Начальное значение задается конструкторами этих классов. Затем методами addAndGet ( ), getAndAdd ( ), incrementAndGet ( ), getAndnIncrement(), decrementAndGet(), getAndDecrement, getAndSet(), set() можно изменять это значение.
Автоматическая упаковка и распаковка типов
В листинге 4.1 объекты числовых классов создавались статическим методом, в котором указывалось числовое значение объекта:
Integer k1 = Integer.valueOf(55);
Это правильно с точки зрения объектно-ориентированного программирования, но утомительно для программиста. Начиная с пятой версии Java, было решено упростить такую запись. Теперь можно писать
Integer k1 = 55;
как будто k 1— простая числовая переменная примитивного типа. Ничего нового в язык Java такая запись не вносит: компилятор, увидев ее, тут же восстановит применение статического метода. Но она облегчает работу программиста, предоставляя ему привычную форму определения переменной. Как говорят, компилятор делает автоматическую упаковку (auto boxing) числового значения в объект. Компилятор может сделать и автоматическую распаковку. После приведенных ранее определений объекта k1 можно написать, например,
int n = k1;
и компилятор извлечет из объекта k1 класса Integer числовое значение 55. Конечно, для этого компилятор обратится к методу intValue () класса Integer, но это незаметно для программиста.
Автоматическая упаковка и распаковка возможна и в методах классов. Рассмотрим простой класс.
class AutoBox{ static int f(Integer value){ return value; // Распаковка.
}
public static void main(String[] args){
Integer n = f(55);
}
}
В методе main() этого примера сначала число 55 приводится к типу параметра метода f() с помощью упаковки. Затем результат работы метода f () упаковывается в объект n класса Integer.
Автоматическую упаковку и распаковку можно использовать в выражениях, написав k 1++ или даже (k 1+ k 2/ k 1), но это уже слишком! Представьте себе, сколько упаковок и распаковок вставит компилятор и насколько это замедлит работу программы!
Настраиваемые типы (generics)
Введение в язык Java автоматической упаковки типов позволило определить еще одну новую конструкцию — настраиваемые типы (generics), позволяющие создавать шаблоны классов, интерфейсов и методов. Например, можно записать обобщенный настраиваемый (generic) класс
class MyGenericClass{ private T data;
public MyGenericClass(){}
public MyGenericClass(T data){ this.data = data;
}
public T getData(){ return data;
}
public void setData(T data){ this.data = data;
}
}
в котором есть поле data неопределенного пока типа, обозначенного буквой T. Разумеется, можно написать другую букву или даже идентификатор. Буква T появилась просто как первая буква слова Type.
Перед использованием такого класса-шаблона его надо настроить, задав при обращении к его конструктору определенный тип в угловых скобках. Например:
class MyGenericClassDemo{
public static void main(String[] args){
MyGenericClass iMyGen = new MyGenericClass(55);
Integer n = iMyGen.getData();
MyGenericClass dMyGen = new MyGenericClass(-37.3456);
Double x = dMyGen.getData();
}
}
Если при определении экземпляра настраиваемого класса и слева и справа от знака равенства в угловых скобках записан один и тот же тип, то справа его можно опустить для краткости записи, оставив только пару угловых скобок (так называемый "ромбовидный оператор", "diamond operator"). Используя это новое, введенное в Java 7, сокращение, предыдущий класс можно записать так:
class MyGenericClassDemo{
public static void main(String[] args){
MyGenericClass iMyGen = new MyGenericClass<>(55);
Integer n = iMyGen.getData();
MyGenericClass dMyGen = new MyGenericClass<>(-37.3456);
Double x = dMyGen.getData();
}
}
Рассмотрим более содержательный пример. Пусть нам надо вычислять среднее арифметическое значение нескольких чисел, причем в одном случае это целые числа, в другом — вещественные, в третьем — короткие или, наоборот, длинные целые числа. У среднего значения в любом случае будет тип double. В листинге 4.2 написан один общий класс-шаблон для всех этих случаев.
Листинг 4.2. Настраиваемый класс
class Average{ T[] data;
public Average(T[] data) { this.data = data; }
public double average(){ double result = 0.0;
for (T t: data) result += t.doubleValue(); return result / data.length;
}
public static void main(String[] args){
Integer[] iArray = {1, 2, 3, 4};
Double[] dArray = {3.4, 5.6, 2.3, 1.24};
Average iAver = new Average<>(iArray); System.out.println("int average = " + iAver.average()); Average dAver = new Average<>(dArray); System.out.println("double average = " + dAver.average());
}
Обратите внимание на то, что в заголовке класса в угловых скобках указано, что тип T — подкласс класса Number. Это сделано потому, что здесь тип T не может быть произвольным. Действительно, в методе average ( ) использован метод doubleValue ( ) класса Number, а это означает, что тип T ограничен классом Number и его подклассами. Кроме того, операции сложения и деления тоже допустимы только для чисел.
Конструкция ограничивает сверху множество типов, пригодных для настройки параметра T. Таким же образом, написав , можно ограничить снизу тип T только типом SomeClass и его супертипами.
У настраиваемого типа может быть более одного параметра. Они перечисляются в угловых скобках через запятую:
class MyGenericClass2{ private S id; private T data;
public MyGenericClass2() {}
public MyGenericClass2(S id, T data){ this.id = id; this.data = data;
}
public S getId(){ return id;
}
public void setId(S data){ this.id = id;
}
public T getData(){ return data;
}
public void setData(T data){ this.data = data;
}
}
Из этих примеров видно, что неопределенные типы S, T могут быть типами параметров конструкторов и типами возвращаемых методами значений. Разумеется, они могут быть типами параметров не только конструкторов, но и любых методов. Более того, типами параметров и типами возвращаемых значений методов могут быть настраиваемые типы. Можно написать метод в такой форме:
public MyGenericClass2 makeClass2(S id,
MyGenericClass data){ return new MyGenericClass2(id, data.getData());
}
и обратиться к нему так, как показано в листинге 4.3.
public class MyGenericClass2Demo{
Читать дальшеИнтервал:
Закладка: