Н.А. Вязовик - Программирование на Java
Рассмотрим пример, в котором на консоль последовательно выводятся:
* временная зона по умолчанию;
* список всех возможных временных зон;
* список временных зон, которые совпадают с текущей временной зоной.
public class Test {
public Test() {
}
public static void main(String[] args) {
Test test = new Test();
TimeZone tz = TimeZone.getDefault();
int rawOffset = tz.getRawOffset();
System.out.println("Current TimeZone" + tz.getDisplayName() + tz.getID() + "nn");
// Display all available TimeZones
System.out.println("All Available TimeZones n");
String[] idArr = tz.getAvailableIDs();
for(int cnt=0;cnt < idArr.length;cnt++) {
tz = TimeZone.getTimeZone(idArr[cnt]);
System.out.println(test.padr(tz.getDisplayName() +
tz.getID(),64) + " raw offset=" + tz.getRawOffset() +
";hour offset=(" + tz.getRawOffset()/ (1000 60 60 ) + ")");
}
// Display all available TimeZones same as for Moscow
System.out.println("nn TimeZones same as for Moscow n");
idArr = tz.getAvailableIDs(rawOffset);
for(int cnt=0;cnt < idArr.length;cnt++) {
tz = TimeZone.getTimeZone(idArr[cnt]);
System.out.println(test.padr(tz.getDisplayName()+
tz.getID(),64) + " raw offset=" + tz.getRawOffset() +
";hour offset=(" + tz.getRawOffset()/ (1000 60 60 ) + ")");
}
}
String padr(String str,int len) {
if(len - str.length() > 0) {
char[] buf = new char[len - str.length()];
Arrays.fill(buf,' ');
return str + new String(buf);
} else {
return str.substring(0,len);
}
}
}
Пример 14.9.
Результатом будет:
Current TimeZone Moscow Standard TimeEurope/Moscow
TimeZones same as for Moscow
Eastern African TimeAfrica/Addis_Aba raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Asmera raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Dar_es_Sa raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Djibouti raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Kampala raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Khartoum raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Mogadishu raw offset=10800000;hour offset=(3)
Eastern African TimeAfrica/Nairobi raw offset=10800000;hour offset=(3)
Arabia Standard TimeAsia/Aden raw offset=10800000;hour offset=(3)
Arabia Standard TimeAsia/Baghdad raw offset=10800000;hour offset=(3)
Arabia Standard TimeAsia/Bahrain raw offset=10800000;hour offset=(3)
Arabia Standard TimeAsia/Kuwait raw offset=10800000;hour offset=(3)
Arabia Standard TimeAsia/Qatar raw offset=10800000;hour offset=(3)
Arabia Standard TimeAsia/Riyadh raw offset=10800000;hour offset=(3)
Eastern African TimeEAT raw offset=10800000;hour offset=(3)
Moscow Standard TimeEurope/Moscow raw offset=10800000;hour offset=(3)
Eastern African TimeIndian/Antananar raw offset=10800000;hour offset=(3)
Eastern African TimeIndian/Comoro raw offset=10800000;hour offset=(3)
Eastern African TimeIndian/Mayotte raw offset=10800000;hour offset=(3)
Пример 14.10.
Класс SimpleTimeZone
Класс SimpleTimeZone, как потомок TimeZone, реализует его абстрактные методы и предназначен для применения в настройках, использующих Григорианский календарь. В большинстве случаев нет необходимости создавать экземпляр данного класса с помощью конструктора. Вместо этого лучше использовать статические методы, которые возвращают тип TimeZone, рассмотренные в предыдущем параграфе. Единственная, пожалуй, причина для использования конструктора - необходимость задания нестандартных правил перехода на зимнее и летнее время.
В классе SimpleTimeZone определено три конструктора. Рассмотрим наиболее полный с точки зрения функциональности вариант, который, помимо временной зоны, задает летнее и зимнее время.
public SimpleTimeZone(int rawOffset,
String ID,
int startMonth,
int startDay,
int startDayOfWeek,
int startTime,
int endMonth,
int endDay,
int endDayOfWeek,
int endTime)
rawOffset - временное смещение относительно гринвича;
ID - идентификатор временной зоны (см. пред.параграф);
startMonth - месяц перехода на летнее время;
startDay - день месяца перехода на летнее время*;
startDayOfWeek - день недели перехода на летнее время*;
startTime - время перехода на летнее время (указывается в миллисекундах);
endMonth - месяц окончания действия летнего времени;
endDay - день окончания действия летнего времени*;
endDayOfWeek - день недели окончания действия летнего времени*;
endTime - время окончания действия летнего времени (указывается в миллисекундах).
Перевод часов на зимний и летний вариант исчисления времени определяется специальным правительственным указом. Обычно переход на летнее время происходит в 2 часа в последнее воскресенье марта, а переход на зимнее время - в 3 часа в последнее воскресенье октября.
Алгоритм расчета таков:
* если startDay=1 и установлен день недели, то будет вычисляться первый день недели startDayOfWeek месяца startMonth (например, первое воскресенье);
* если startDay=-1 и установлен день недели, то будет вычисляться последний день недели startDayOfWeek месяца startMonth (например, последнее воскресенье);
* если день недели startDayOfWeek установлен в 0, то будет вычисляться число startDay конкретного месяца startMonth ;
* для того, чтобы установить день недели после конкретного числа, специфицируется отрицательное значение дня недели. Например, чтобы указать первый понедельник после 23 февраля, используется вот такой набор: startDayOfWeek=-MONDAY, startMonth=FEBRUARY, startDay=23
* для того, чтобы указать последний день недели перед каким-либо числом, указывается отрицательное значение этого числа и отрицательное значение дня недели. Например, для того, чтобы указать последнюю субботу перед 23 февраля, необходимо задать такой набор параметров: startDayOfWeek=-SATURDAY, startMonth=FEBRUARY, startDay=-23;
* все вышеперечисленное относится также и к окончанию действия летнего времени.
Рассмотрим пример получения текущей временной зоны с заданием перехода на зимнее и летнее время для России по умолчанию.
public class Test {
public Test() {
}
public static void main(String[] args) {
Test test = new Test();
SimpleTimeZone stz = new SimpleTimeZone(
TimeZone.getDefault().getRawOffset()
,TimeZone.getDefault().getID()
,Calendar.MARCH ,-1
,Calendar.SUNDAY
,test.getTime(2,0,0,0)
,Calendar.OCTOBER ,-1
,Calendar.SUNDAY
,test.getTime(3,0,0,0) );
System.out.println(stz.toString());
}
int getTime(int hour,int min,int sec,int ms) {
return hour 3600000 + min 60000 + sec 1000 + ms;
}
}
Пример 14.11.
Результатом будет:
java.util.SimpleTimeZone[id=Europe/Moscow,offset=10800000,dstSavings=3600000,useDaylight=true, startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=7200000,startTimeMode=0, endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=10800000,endTimeMode=0]
Пример 14.12.
Интерфейс Observer и класс Observable
Интерфейс Observer определяет всего один метод, update (Observable o, Object arg), который вызывается, когда обозреваемый объект изменяется.
Класс Observable предназначен для поддержки обозреваемого объекта в парадигме MVC (model-view-controller), которая, как и другие проектные решения и шаблоны, описана в специальной литературе. Этот класс должен быть унаследован, если возникает необходимость в том, чтобы отслеживать состояние какого-либо объекта. Обозреваемый объект может иметь несколько обозревателей. Соответственно, они должны реализовать интерфейс Observer.
После того, как в состоянии обозреваемого объекта что-то меняется, необходимо вызвать метод notifyObservers, который, в свою очередь, вызывает методы update у каждого обозревателя.
Порядок, в котором вызываются методы update обозревателей, заранее не определен. Реализация по умолчанию подразумевает их вызов в порядке регистрации. Регистрация осуществляется с помощью метода addObserver(Observer o). Удаление обозревателя из списка выполняется с помощью deleteObserver(Observer o). Перед вызовом notifyObservers необходимо вызвать метод setChanged, который устанавливает признак того, что обозреваемый объект был изменен.
Рассмотрим пример организации взаимодействия классов:
public class TestObservable extends java.util.Observable {
private String name = "";
public TestObservable(String name) {
this.name = name;
}
public void modify() {
setChanged();
}
public String getName() {
return name;
}
}
public class TestObserver implements java.util.Observer {
private String name = "";
public TestObserver(String name) {
this.name = name;
}
public void update(java.util.Observable o,Object arg) {
String str = "Called update of " + name;
str += " from " + ((TestObservable)o).getName();
str += " with argument " + (String)arg;
System.out.println(str);
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Test test = new Test();
TestObservable to = new TestObservable("Observable");
TestObserver o1 = new TestObserver("Observer 1");
TestObserver o2 = new TestObserver("Observer 2");
to.addObserver(o1);
to.addObserver(o2);
to.modify();
to.notifyObservers("Notify argument");
}
}
Пример 14.13.
В результате работы на консоль будет выведено:
Called update of Observer 2 from Observable with argument Notify argument
Called update of Observer 1 from Observable with argument Notify argument
Пример 14.14.
На практике использовать Observer не всегда удобно, так как в Java отсутствует множественное наследование и Observer необходимо наследовать в самом начале построения иерархии классов. Как вариант, можно предложить определить интерфейс, задающий функциональность, сходную с Observer, и реализовать его в подходящем классе.
Коллекции
Зачастую в программе работа идет не с одним объектом, а с целой группой более или менее однотипных экземпляров (например, автопарк организации). Проще всего сделать это с помощью массивов. Однако, несмотря на то, что это достаточно эффективное решение для многих случаев, оно имеет некоторые ограничения. Так, обращаться к элементу массива можно только по его номеру (индексу). Также необходимо заранее задать длину массива и больше ее не менять.
Массивы существовали в Java изначально. Кроме того, было определено два класса для организации более эффективной работы с наборами объектов: Hashtable и Vector. В JDK 1.2 набор классов, поддерживающих работу с коллекциями, был существенно расширен.
Существует несколько различных типов классов-коллекций. Все они разрабатывались, по возможности, в соответствии с единой логикой и определенными интерфейсами и там, где это возможно, работа с ними унифицирована. Однако все коллекции отличаются внутренними механизмами хранения, скоростью доступа к элементам, потребляемой памятью и другими деталями. Например, в некоторых коллекциях объекты (также называемые элементами коллекций), могут быть упорядочены, в некоторых - нет. В некоторых типах коллекций допускается дублирование ссылок на объект, в некоторых - нет. Далее мы рассмотрим каждый из классов-коллекций.