eManual.ru - электронная документация
Секция 4 из 7 - Предыдущая - Следующая
Все секции
- 1
- 2
- 3
- 4
- 5
- 6
- 7
массива?
Я не хочу использовать массив-шаблон. Я хотел бы делать это без
дублирования (возможно, большого) массива.
[*] Использование цикла, который поочередно присваивает значения элементам
массива, в 20 - 40 раз медленнее, чем старый добрый memset() в Си.
На многих Java Virtual Machine (JVM) можно сделать так: присвоить значение
первому байту массива, использовать System.arraycopy() для
последовательного заполнения следующего байта, затем следующих двух байт,
следующих четырех байт, следующих восьми байт и т.д. пока не останется
меньшая часть массива, которую System.arraycopy() заполнит в один прием.
public static void bytefill(byte[] array, byte value) {
int len = array.length;
if (len > 0)
array[0] = value;
for (int i = 1; i < len; i += i)
System.arraycopy( array, 0, array, i,
((len - i) < i) ? (len - i) : i);
}
На Sun'овской JVM этот код выполняется быстрее, чем обычный цикл, и даже
быстрее, чем на JIT-компиляторах, потому что контроль выхода за границы
массива здесь проводится всего лишь до log2(array.length) раз. Причем этот
способ работает, даже если размер массива не является степенью двух.
------------------------------
7. I/O
1. (Sect. 7) Как прочитать файл, содержащий числа в символьной форме?
[*] Есть несколько способов. Ниже приведен один из них. Допустим, файл
называется "C:workmydata.txt" и содержит строки вида:
135 7512 3659814 328 1 54829
68522 19982810 38
т.e. несколько строк ASCII, в которых числа разделены пробелами.
Вот фрагмент кода:
// Открываем файл
RandomAccessFile f = new RandomAccessFile("c:\work\datafile.txt", "r");
// Читаем из него одну строку
String s= f.readLine();
// Разбираем строку
StringTokenizer st = new StringTokenizer(s);
// Извлекаем из строки целое число
i = Integer.parseInt(st.nextToken());
Мы использовали RandomAccessFile, потому что здесь напрямую
поддерживается метод readLine(). Альтернативой могло бы быть создание
FileReader и на его базе BufferedReader. Теперь сведем все это вместе,
и, добавив обработку исключения в случае если файл не существует,
получим следующее:
import java.io.*;
import java.util.*;
public class c {
public static void main(String args[]) {
try {
RandomAccessFile f = new RandomAccessFile
("datafile.txt", "r");
String s;
while ( (s=f.readLine()) != null ) {
System.out.println("read: "+s);
StringTokenizer st = new StringTokenizer(s);
int i=0;
while (st.hasMoreTokens()) {
i = Integer.parseInt(st.nextToken());
// i сейчас содержит следующее целое число из строки
// аналогично используется Double.parseDouble(), и т.п..
System.out.print(" "+ i);
}
System.out.println();
}
} catch (Exception e) {System.out.println("Excpn: "+e); }
// файловый ввод-вывод, из книги "Just Java" Петера ван дер Линдена
}
}
Смотрите также следующий вопрос: как читать данные с клавиатуры.
2. (Sect. 7) Как читать String/int/boolean/т.п. с клавиатуры?
[*] Самое легкое решение - раздобыть исходники класса EasyIn, лежащие
по адресу http://www.afu.com/ (там же, где англоязычная версия этого
FAQ). Скомпилируйте их с вашим кодом и используйте, например, так:
EasyIn easy = new EasyIn();
int i = easy.readInt(); // читаем int из System.in
boolean b = easy.readBoolean(); // читаем boolean из System.in
double d = easy.readDouble(); // читаем double из System.in
... и так далее.
EasyIn бесплатен, с его исходниками вы имеете право делать все что вам
нравится. В том числе улучшать их.
Если вам необходим только собственноручно написанный код (зачем,
интересно), то в JDK 1.0.2
java.io.DataInputStream in = new java.io.DataInputStream(System.in);
String s = in.readLine();
Еще один способ в JDK 1.1:
java.io.BufferedReader in =
new java.io.BufferedReader( new InputStreamReader(System.in));
String s = in.readLine();
Если необходимо разобрать строку, из нее можно легко выделить лексемы
любого типа, как уже было показано выше в этом FAQ. Недостаток этого
способа в том, что искусственно усложняется простейшее решение для
ввода/вывода с клавиатуры. В ближайшем будущем Javasoft вряд ли
предложит более удобный способ.
3. (Sect. 7) Почему возникают проблемы с System.out.println()? Проверьте
написание. Последние две буквы - это "l" и "n", а не одна "n".
Имя метода происходит от словосочетания "print line" ("печать
строки"), так как он (метод) выводит на печать объект класса String и
переходит на следующую строку (в отличие от System.out.print() ). К
сожалению, соглашение о названиях методов в Java соблюдается
слабовато. Так, имя метода, предназначенного для чтения строки с
клавиатуры, вовсе не readln(), могло бы показаться, а readLine().
4. (Sect. 7) Как писать в COM порт, используя Java?
[*] В JDK 1.2 есть платформенно-независимый интерфейс
последовательного порта. Документацию к нему можно получить,
зарегистрировавшись на Java Developer Connection (это бесплатно),
http://java.sun.com) а там идите на
http://java.sun.com/jdc/earlyAccess/communications.html.
Для систем старше JDK 1.2 есть как минимум две библиотеки для работы с
COM- портами. Смотрите
o http://www.sc-systems.com есть версии для Windows 95, WindowsNT,
OS/2, Macintosh PPC, Solaris Sparc, Linux x86, FreeBSD x86, HP/UX
PA-RISC, и возможно еще для некоторых.
o http://www.cd.com/portio
o К тому же в Unix есть утилита для работы с последовательными
портами. Она вместе с исходниками лежит на
http://jarvi.ezlink.com/rxtx/ Она бесплатна на условиях GPL, и
работает на Linux, Irix, Solaris, Windows 95, и NT.
Есть еще одно решение проблемы, переносимое, работающее на Java 1.1 и
даже 1.0, но мало подходящее для домашних пользователей. Покупайте
COM-порты в форме "терминального сервера" ("terminal server").
Использование COM-порта становится таким же простым, как подсоединение
к порту с помощью Socket. Параметры порта могут быть программно
изменены с помощью SNMP для большинства терминальных серверов (если Вы
работаете с современным модемом, Вам это вряд ли понадобится). Любой
компьютер в сети (даже если он под Win95) может работать как
терминальный сервер, имея простое серверное ПО, но покупка
специализированного аппаратного обеспечения значительно упростит
задачу.
К тому же, ваши Windows95 приложения могут совместно использовать
СОМ-порты (с любыми модемами на портах) с помощью ПО "Dial-out IP" под
Windows95. Смотрите здесь: http://www.tactical-sw.com/.
Если порт подмонтирован к файловой системе, вы можете использовать его
как файл, открывая для чтения и/или записи. Таким же путем можно
выводить на печать текст, копируя его в устройство "prn" или "lpt1" на
РС-совместимых системах (обязательно завершив текст символом конца
файла), или в "/dev/что-нибудь" в Unix. Ниже приведен пример:
// класс, открывающий принтер как файл
// и записывающий в него строку "Hello, world"
import java.io.*;
public class lpt {
public static void main (String[] argv) {
try {
FileOutputStream os = new FileOutputStream("LPT1");
//создаем "дружественный" PrintStream
PrintStream ps = new PrintStream(os);
//выводим текст
ps.println("Hello world!");
//признак конца файла -- это важно
//Без него текст просто попадет в буфер принтера
// пока что-нибудь еще не будет выводиться на печать.
ps.print("f");
//сбрасываем буфер и закрываем поток
ps.close();
} catch (Exception e) {
System.out.println("Exception occurred: " + e);
}
}
}
Если необходимо изменить характеристики порта (напр., скорость или
четность), а не просто писать или считывать данные, то, к сожалению,
Java на данный момент не имеет переносимых решений для этой проблемы.
Вам придется воспользоваться одной из библиотек, указанных выше, или
же обратиться к системно-зависимому коду или утилите.
*(Часть 7) Как я могу сделать быстрее ввод/вывод? Моя программа
копирования файлов работает медленно.
[*] Для этой цели надо использовать BufferedInputStream. Недостатком Java
явлется то, что буферизованный ввод/вывод не используется по умолчанию;
можно было бы использовать некий флаг или альтернативный конструктор для
его отключения. Пакет ввода/вывода - второй наиболее плохо реализованный
пакет в Java после класса Data.
*(Часть 7) Как я могу организовать форматированный ввод/вывод вещественных
чисел?
[*] Используйте класс java.text.NumberFormat.
Также вы можете использовать http://www.newbie.net/sharky/lava/, или
используйте пакет Cay Horstmann'а
http://www.horstmann.com/corejava/Format.java
Несмотря на то,что много различных утилит заявляют поддержку всех
возможностей функции printf языка C, только вышеприведенные пакеты
корректно поддерживают эквивалент %e в printf.
*(Часть 7) Как я могу прочитать числа в научном (экспоненциальном)
формате?
[*] Нижеприведенная программа, написанная Steve Chapel, использует класс
StreamTokenizer для того, чтобы прочитать данные из стандартного ввода и
распознать вещественные числа двойной точности (double) в экспоненциальном
формате (например, -1.23e-45).
import java.io.*;
public class ReadExponential {
public static void main(String argv[]) {
DataInputStream in = new DataInputStream(System.in);
StreamTokenizer st = new StreamTokenizer(in);
try {
while (st.nextToken() != StreamTokenizer.TT_EOF) {
switch (st.ttype) {
case StreamTokenizer.TT_NUMBER:
double num = st.nval;
int exp = 0;
st.ordinaryChars(' ', ' ');
st.nextToken();
st.whitespaceChars(' ', ' ');
if (st.ttype == StreamTokenizer.TT_WORD &&
Character.toUpperCase(st.sval.charAt(0)) == 'E') {
try {
exp = Integer.parseInt(st.sval.substring(1));
} catch (NumberFormatException e) {
st.pushBack();
}
} else if (st.ttype < 0 || st.ttype > ' ')
st.pushBack();
System.out.println("Num " + num * Math.pow(10, exp));
break;
case StreamTokenizer.TT_WORD:
System.out.println("Word " + st.sval);
break;
default:
System.out.println("Char '" + (char) st.ttype + "'");
break;
} // end switch
} // end while
} catch (IOException e) {
System.out.println("IOException: " + e);
}
} // end main
}
*(Часть 7) Я пытаюсь прочитать символ из текстового файла, используя метод
readChar() класса DataInputStream. А когда я пытаюсь его напечатать,
получаю символы '?'.
[*] Помните, что в Java используются 16-битные символы Unicode, в то время
как многие системы хранят символы как 8-битные в кодировке ASCII. Таким
образом, чтобы прочитать отдельные символы из текстового файла, необходимо
убедиться в правильной конвертации. Правильно это делается так -
используйте InputStreamReader, который преобразовывает поток из 8-битного в
16-битный:
FileInputStream fis = new FileInputStream("myfile.txt");
InputStreamReader isr = new InputStreamReader(fis);
char c3 = (char) isr.read();
Другой, менее предпочтительный путь, состоит в том, чтобы прочитать байт и
преобазовать его в символ:
FileInputStream fis = new FileInputStream("myfile.txt");
DataInputStream dis = new DataInputStream(fis);
char c1 = (char) dis.readByte();
*(Часть 7) Как удалить директорию в Java?
[*] JDK 1.0 не поддерживает удаление директорий. JDK 1.1 поддерживает
удаление директорий при помощи метода public boolean delete() класса
java.io.File
Убедитесь, что в директории, которую вы собираетесь удалить, нет ни одного
открытого потока (stream). Выполните команду close() для всех потоков, даже
если читаемый файл закончился (the underlying file is gone).
*(Часть 7) Как я могу узнать, сколько свободно дискового пространства?
[*] На данный момент не существует хорошего API (программного интерфейса)
для инспектирования системы. В Java невозможно контролировать процессы или
смотреть на ресурсы системы. Вы можете использовать
Runtime.getRuntime().exec() для вызова "df" в юниксе или "dir" в Windows.
С другой стороны, взгляните на JConfig по адресу:
http://www.tolstoy.com/samizdat/jconfig.html
JConfig - это межплатформенная библиотека, которая заполняет многие
промежутки в Java API, и дает возможность работать с файлами, процессами,
мониторами и т.д. в манере, напоминающей Windows или Mac.
*(Часть 7) Как я могу получить список файлов в каталоге C: ?
[*] Кажущийся очевидным подход - вызвать File.list("C:") - не работает.
Для этого есть две причины. Во-первых, (slash) является escape-символом в
Java, то есть, если вам нужен этот символ, надо написать его дважды.
Во-вторых, необходимо указать имя директории, то есть точку. Объединив все
это вместе, увидим, что любой из следующих вызовов работает:
File.list("C:\.");
или
File.list("C:/.");
Замечание: разделитель "/" работает точно так же, как и "" во многих
программах и системных вызовах Windows. Дело в том, что в прародителе DOS -
операционной системе CP/M - не было директорий и, следовательно,
разделителей в именах файлов. Прямой слэш "/" был уже задействован для
передачи опций командам CP/M; обратный слэш "" стали использовать как
разделитель директорий в именах файлов, однако оболочка понимает и "/" для
совместимости с другими операционными системами.
*(Часть 7) В чем разница между различными форматами ZIP: ZIP, GZIPи PKZIP?
[*] Zip - формат архивного файла, популярный на PC, который содержит
несколько сжатых файлов внутри.
GZIP - это GNU ZIP. Реально это подмножество формата ZIP с одним файлом
внутри. В GZIP нельзя поместить целую директорию, а можно только один файл.
PKZIP - набор коммерческих программ для создания файлов Zip.
Все три используют алгоритм сжатия, основанный на LZ77. Этот метод сжатия
также используется библиотекой ZLIB и, следовательно, графическим форматом
PNG (который использует ZLIB). PNG - Portable Network Graphics -
предоставляет свободную, не защищенную какими-либо патентами, замену GIF и
TIFF.
Альтернативная технология сжатия, LZW, защищена патентом Unisys. LZW
используется в файлах GIF и в команде Unix'а compress. К счастью, будучи
свободным от патентных зависимостей, LZ77 также дает лучшее сдатие, чем
LZW. LZW - начальные буквы фамилий трех ученых, разработавших алгоритм
(Lempel, Ziv, Welch).
Основные классы (они находятся в java.util.zip), поддерживающие формат LZ77
- Deflater и Inflater. Они используются классами DeflaterOutputStream и
InflaterInputStream. В пакете java.util.zip есть так же классы
GZIPInputStream и ZipInputStream, унаследованные от InflaterInputStream.
PKZIP - коммерческая программа для DOS, Windows и OS/2, продаваемая PKWARE.
Файлы Jar (Java Archive) хранятся в формате ZIP, но существует одно отличие
- не сохраняются атрибуты файлов. Известно, что некоторые версии WinZip
неправильно поддерживают полный формат ZIP. Лучше использовать InfoZIP или
PKZIP.
*(Часть 8) Существуют ли пакеты в Java для управления HTML?
[*] Смотрите ответ на Вопрос 13.14.
*(Часть 8) Почему Dialogs не работают так, как я хочу?
[*] Модальные диалоги (диалоговые окна, присутвующие пока на них не
щелкнуть) проявляют глюкавость во многих браузерах и в JDK 1.0.2. Один из
багов это когда диалог не становится активным окном, при выводе не экран.
Многие из багов исправлены в JDK 1.1.
(Часть 8) Где я могу получить информацию о классах sun.* в JDK?
[ ] Эти классы поддерживают только функции в java.* иерархии. Они не
являются частью API, и не будут работать в Java системах от поставщиков не
Sun. Некоторые люди изменяли код и опубликовывали API для работы с этими
классами, но вы будете использовать их на свой риск, и это может испортить
что-либо без предупреждения.
Плохо, что эти программы не были перенесены на обычную Java и будут
работать только на JDK от Sun. По этой причине мы не реккомендуем
использовать классы вне java.* когда вы используете JDK от других фирм.
Если вы все-же настаиваете на том, что бы их использовать, можете
посмотреть здесь:
http://java.sun.com/products/api-overview/index.html
http://www.parmly.luc.edu/javaudio/
http://www.users.interport.net/~mash/javamidi.html
*(Часть 8) Как прочитать значения переменных ОС используя программу на
Java?
[*] Переменные окружения системы не используются в Java, так как они
зависят от платформы. Mac-системы вообще не имеют таких переменных,
например. У приложений Windows 95 не запускающихся из окна DOS нет
переменных окружения. Используйте опции вместо них. В JDK 1.0 была допущена
ошибка, из-за которой программистам самим приходилось устанавливать
значение пере менной CLASSPATH. Это значение должно быть установлено в
файле свойств.
Создайте ваш собственный файл свойств(см. java.util.Properties) или укажи
те опцией -D когда вы запускаете интерпретатор или JRE. Дополнительно на
некоторых системах вы можете установить значение из коммандной строки,
например:
java -Dfoo=$foo MyClass (Unix)
или
java -Dfoo=%foo% MyClass (Win95/NT)
Это установит значение "foo" в значение переменной окружения foo, и сделает
это доступным в опциях System. Следите за тем, чтобы не было пробелов после
-D или вокруг знака равенства("=") Внутри программы вы получите значение
переменной foo таким образом:
String env = System.getProperty("foo");
Можно поступить более просто, написав значение для foo в коммандной строке
и прочитав ее как arg[0].
java MyClass %FOO% ; Win32
java MyClass $FOO ; Unix
Наконец, вы можете запустить Runtime процесс для получения переменной
окружения, если вы используете платформу, допускающую это.
import java.io.*;
import java.util.Properties;
public class Main {
public static void main(String[] argv) {
Properties envVars = new Properties();
try {
envVars.load( // используйте "set" в Windows
Runtime.getRuntime().exec("/bin/env").getInputStream());
} catch (Throwable t) {t.printStackTrace();}
System.out.println("nn"+argv[0]+" = <"+envVars.get(argv[0])+">");
}
}
Это не обычный подход к Java и это построится, в зависимости от платформы,
которую вы используете. Смотрите Вопрос 10.6 для деталей. В Unix, комманда
выводящая переменные ОС это "/usr/bin/env". В Windows 95, это "set".
*(Часть 8) Как можно связать Java с базой данных Microsoft Access?
[*] Используйте JDBC-ODBC мост. Это не слишком трудно в установке, но это
требует особенного внимания к детялям. Мы предлагаем пример "шаг-за-шагом"
из текста Линден(van der Linden) "Просто Java" упомянутом в разделе
создателей этого документа.
Заметьте, что версия JDK от Microsoft не поддерживает JDBC-ODBC доступ,
из-за нестандартного интерфейса.
JDBC FAQ можно найти на
http://java.sun.com/products/jdbc/jdbc-frequent.html
*(Часть 8) Я не могу сменить текущую рабочую директорию, не так-ли?.
[*] Все верно. Это упущенная возможность является недосмотром, который мы
надеемся исправить в будущем. ID этого бага 4156278, пожалуйста
присоединяйтесь к JDC, и голосуйте, чтобы исправить это(и остальное).
Изменение опции user.dir просто изменит текстовое значение, не воплощая
изменения в жизнь.
Существуют несколько обходов этого.
* Запустите ваше приложение java как .bat или .sh файл и сделайте "cd" в
нем(перед запуском, разумеется), если вы уверены в том, что все
внешние процессы, запускаемые вашей программой могут быть запущены из
этой директории.
* Сделайте: exec("cd /home/wherever; externalApp.exe") в Unix, (этому,
кажется, нет эквивалента на NT).
* Вместо запуска .exe напрямую, запускайте (или записывайте на лету)
.bat или .sh файл, который делает cd и затем запускает ваш .exe (это
может создать проблему с возвращением обратно верного состояния).
*(Часть 8) Как мне создать вектор числа?
[*] Числа это обычные типы и следовательно не могут управляться векторным
классом, который содержит объекты, вам придется откорректировать числа.
Попробуйте это:
int i =7;
Vector holdsInts = new Vector(5,1);
holdsInts.addElement(new Integer(i));
int j = ((Integer)holdsInts.elementAt(0)).intValue();
*(Часть 8) У меня есть несколько рабочих нитей. Я хочу, чтобы моя главная
нить ожидала, пока остальные закончат работу, и действие начнется настолько
скоро, насколько они все закончат работу. Я не знаю, какая из нитей
закончит работу раньше остальных, поэтому я не иогу вызвать Thread.join на
этой нити. Как мне быть?
[*] Вам надо использовать механизм ожидание/сообщение, чтобы позволить
любой из рабочих нитей разбудить вашу главную нить, когда первая закончит
работу.
*(Часть 8) Как мне получить случайные числа?
[*] Если вам нужно быстро найти небольшое случайное число от 0.0 и до 1.0
double myrandom = Math.random(); // [0,1)
Система обозначения "[0,1)" это обычное математическое варажение для "от
нуля до .9999999 и т.п." Описания от Sun говорят, что это возвращает
значение от 0 до 1, но исследование исходных кодов показывает, что они
ошибаются. Однако, следуемые за присущими арифметической плавающей точке
неточностями, случайный выбор N до 0.999999 может привести к ошибке.
В JDK 1.2 входит другая версия nextInt, которая позволит более точно и
безошибочно возвращать случайные числа, заданного интервала.
Существует небольшая хитрость если вы используете JDK 1.1, и вам надо
получить int в определенном интервале. Допустим, в интервале от 1 до 6,
чтобы сэмулировать бросок костей или от 1 до 52 чтобы представить игральные
карты. Класс Random имеет метод nextInt, который возратит любое число.
import java.util.Random;
Random r = new Random();
int i = r.nextInt();
Однако, есть почти 50% на то, что это число окажется не из правильного
интервала. Так, вы просто получите значение abs() и затем разделите его на
верхнюю границу интервала.
int dice_throw = 1 + Math.abs(i) % 6;
Исключением является то, что метод abs() грубо ошибается в присутствии
Integer.MIN_VALUE (это тоже возращает отрицательный результат!). Поэтому,
лучше выполнить логическое умножение(and) для достижения верных значений -
при получении числа между определенными высшим и низшим значениями
интервала (включительно):
java.util.Random r = new java.util.Random();
int j = (r.nextInt() & Integer.MAX_VALUE) % (high-low+1) + low;
Это решение сработает корректно "(почти) в 50% случаев" потому что
существует на одно значение больше в отрицательных числах, чем в
положительных в арифметических комлектах, какие использует Java. Для
большинства целей, это предубеждение будет незначительным, а мы "и"
nextInt() сводим их к нулю. Конечно, это маловероятно, что вам встретится
эта ошибка, но вы же не хотите иметь критическую ситуацию, только из-за
того, что упустили этот случай при тестировании своего приложения.
Неприятная проблема это то, что с таким алгоритмом, младшие биты попадаются
реже, чем старшие, при случайном выборе. Причина в том, что при операции
деления (mod 2^n) младшие биты "пропадают" чаще, чем старшие. Можно
предположить, что используя java.security.SecureRandom, получится более
большая разбросанность случайных чисел, так как это использует
"Криптографическую разбросанность" (Cryptograpic hash), но это также
потребует более объемных вычислений от компьютера.
*(Часть 9) Какие изменения произошли с java.util.Date при переходе от JDK
1.0 к JDK 1.1?
[*] В JDK 1.1 класс java.util.Date был разделен для того, чтобы
обеспечивать лучшую поддержку временных зон и интернациональных свойств.
Классы, относящиеся к датам, выписаны ниже:
1. Класс Date представляет определенный момент времени, с
точностью до миллисекунды.
2. Класс TimeZone это абстрактный класс, который представляет
смещение часового пояса, а также вычисляет поправку при
переходе на летнее время.
3. Класс SimpleTimeZone это единственный непосредственный
подкласс класса TimeZone в JDK. Все что он определяет, это
обычный часовой пояс с простым переходом на летнее время и
периодом (этого перехода).
4. Класс Calendar это абстрактный класс для конвертирования
объекта Date в набор целых чисел, таких как год, месяц, день
и час (и обратно).
5. Класс GregorianCalendar это единственный непосредственный
подкласс класса Calendar в JDK. Он производит преобразования
из класса даты в целые числа (Date-to-fields) для
общеупотребительной календарной системы.
6. Класс DateFormat это абстрактный класс, который позволяет
Вам конвертировать класс Date в печатаемую строку с полями
заданного вида (например dd/mm/yy или dd.MMM.yyyy).
7. Класс SimpleDateFormat это единственный непосредственный
подкласс класса DateFormat в JDK. Он берет строку формата и
либо разбирает строку, чтобы получить дату, либо берет дату
и получает строку.
По крайней мере один критик употребил термин "причудливая", когда описывал
сложность связанных классов даты в Java, хотя остальные сказали бы
"ломаная". Хорошей новостью является то, что в JDK 1.2 все общие проблемы
были решены, и множество ошибок было исправлено в 1.1.4 и 1.1.6. Даже в
1.1.1 Вы можете избежать большинства наиболее распостраненных ошибок,
всегда имея в виду, какую временную зону использует каждый класс.
*(Часть 9) Что же в точности представляет из себя java.util.Date?
[*] Класс java.util.Date хранит момент времени, как длинное целое (long
integer), которое представляет из себя число миллисекунд, прошедших
с 00:00:00 Jan 1, 1970 UTC (Coordinated Universal Time). Этот момент
отсчета известен как "Epoch" ("Эпоха"). Это тот же момент отсчета (Epoch),
который используется в системах UNIX. Более ранние даты, чем Epoch,
представлены в виде отицательных чисел, отсчитываемых от 1/1/1970.
Этой схемы достаточно, чтобы представлять даты от 292,269,053 B.C. (до
нашей эры) до 292,272,993 A.D. (нашей эры) (64 бита покрывают диапазон от
-9,223,372,036,854,775,808 до +9,223,372,036,854,775,807 миллисекунд).
Заметьте, что версии, предшествующие JDK 1.2, GregorianCalendar не могут
принимать значения раньше, чем 4716 B.C.
Класс java.util.Date это легковесная (light-weight) конструкция,
предназначенная только для хранения значения миллисекунд. Он используется
для хранения и передачи момента времени. Другие задачи, такие как создание
форматированной строки, вычисление дат, реализованы в других классах.
*(Часть 9) Представляет ли класс java.util.Date верное значение UTC?
[*] Нет, но его свершенно достаточно для большинства пользовательских
задач, работющих с временем (time-keeping). На большинстве компьютеров он
представляет только время с момента epoch как число, полученное из значения
даты, содержащейся в аппаратном обеспечении. Если ваше аппаратное
обеспечение синхронизировано с атомными часами, то ваше время представлено
в UTC; большинство аппаратного обеспечения подразумевает, что день длится
24 часа, но есть еще 20 секунд (leap seconds), которые нужно добавлять к
UTC, с тех пор как однажды это было сделано в 1972 году.
*(Часть 9) Как я могу создать объект Date, который представляет из себя
текущее время?
[*] Значение по умолчанию объекта Date это текущее время. Таким образом
следующий код создает объект даты, который содержит текущее время.
Date now = new Date();
*(Часть 9) Я хочу создать строку, которая представляет из себя дату, в
формате отличном от того, который возвращает метод
java.util.Date.toString(). Должен ли я использовать Календарь (Calendar)?
[*] Нет. Вместо того, чтобы создавать Календарь, вытягивать из него все
необходимые поля и создавать строку, Вы можете использовать для ее создания
SimpleDateFormat.format().
*(Часть 9) Почему все методы в java.util.Date отказываются работать?
[*] Вероятнее всего потому, что исходный java.util.Date не был как положено
извещен о временной зоне и "не был ответственен за интернационализацию".
Чтобы научить этой временной зоне и интернационализировать потребуется
добавление некоторой функциональности, которую можно увидеть в
java.util.Calendar и некоторой функциональности из java.util.DateFormat.
Если Вы находите комбинацию всех родственных классов даты сложной, то
остается радоваться что они были разделены на разные классы.
*(Часть 9) Мне совершенно не нужны интернационализация, информация о
временной зоне, свехгибкий набор классов форматирования даты, есть
что-нибудь еще, что позволило бы мне хранить даты и позволяло бы
производить некоторые вычисления с ними?
[*] Вы можете рассмотреть исользование класса BigDate, написанного Роди
Грином (Roedy Green), и доступного в его весьма информативном голоссарии
(ищите BigDate). Если Вы намерены сохранять результат в базе данных как
объекты Date или TimeStamp. то Вам рекомендуется прочитать следующую ниже
Часть о классе java.sql.Date.
*(Часть 9) Если конструктор Date( String ) исключается из класса, то что я
должен использовать вместо него?
[*] Для создания объекта java.util.Date лучше всего использовать
SimpleDateFormat.parse().
Конструктор класса Date, который принимает в качестве параметра строку,
называется Date.parse( String). Метод Date.parse() имеет свои собственные
правила для перевода 2-х цифрового года (как точку отсчета использует 1980
год) и другие ограничения, которые делают его мало значимым. Другие
"тонкости" Date.parse(), которые не поддерживаются в SimpleDate не
ускользнули от взгляда многих разработчиков.
*(Часть 9) Конструктор Date(int year, int month, int date) и аналогичные
конструкторы убираются из класса, что использовать вместо них?
[*] Конструктор GregorianCalendar(int year, int month, int date) - вот его
Секция 4 из 7 - Предыдущая - Следующая
|