tag:blogger.com,1999:blog-43319633399660029882024-03-09T00:56:26.194+03:00java, java and... javaДля самых маленьких...dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-4331963339966002988.post-11926682412715013692012-04-04T23:01:00.000+03:002012-04-04T23:02:45.288+03:00Ввод и вывод. Файл и консольДля начала поговорим о выводе данных.<br />
Давайте рассмотрим всем известный способ вывода данных, а именно:<br />
<pre class="brush:java">System.out.println("123");
</pre>
Окей. А теперь давайте посмотрим на класс <i>java.io.PrintWriter</i>. Выведем 1 000 000 чисел на экран и засечем время работы.<br />
<pre class="brush:java">import java.io.*;
public class Temp {
public static void main(String[] args){
PrintWriter writer = new PrintWriter(new OutputStreamWriter(System.out));
int n = 1000*1000;
long time = System.currentTimeMillis();
for (int i = 0; i < n; ++i)
writer.print(i + " ");
writer.println();
writer.println(System.currentTimeMillis()-time);
writer.close();
}
}</pre>
На моём компьютере результат получается равным примерно 1000-1100 мс. У вас может получится другое число. А теперь попробуем сделать тоже самое с помощью <i>System.out</i>.<br />
<a name='more'></a><br />
<pre class="brush:java">public class Temp {
public static void main(String[] args){
int n = 1000*1000;
long time = System.currentTimeMillis();
for (int i = 0; i < n; ++i)
System.out.print(i + " ");
System.out.println();
System.out.println(System.currentTimeMillis()-time);
}
}
</pre>
У меня получилось около 4500 мс. Чувствуете разницу? Чтобы использовать <i>PrintWriter </i>понадобилось добавить всего 2 строчки, а какой прирост скорости!<br />
Для записи в файл используйте <i>FileOutputStream</i> :<br />
<pre class="brush:java">PrintWriter writer = new PrintWriter(new FileOutputStream("output.txt"));
</pre>
И да, не забудьте обработать <i>IOException</i>. <br />
Будем считать, что с выводом мы разобрались.<br />
<b>Если для вас важны скорость и удобство вывода - используйте <i>PrintWriter</i>.</b><br />
Теперь разберемся с вводом.<br />
Для ввода есть очень удобный класс <i>java.util.Scanner</i>. Итак, давайте попробуем прочитать с помощью него всё те же 1 000 000 чисел из файла.<br />
<pre class="brush:java">import java.io.*;
import java.util.Scanner;
public class Temp {
public static void main(String[] args) throws IOException{
Scanner sc = new Scanner(new File("output.txt"));
int n = 1000*1000;
int x;
long time = System.currentTimeMillis();
for (int i = 0; i < n; ++i)
x = sc.nextInt();
System.out.println(System.currentTimeMillis()-time);
}
}
</pre>
У меня время работы получается равным примерно 1800 мс. Попробуем улучшить этот результат, правда теперь кода придется добавить побольше. Используем <i>java.io.BufferedReader</i>.<br />
<pre class="brush:java">import java.io.*;
import java.util.StringTokenizer;
class MyReader{
private BufferedReader reader = null;
private StringTokenizer tokenizer = null;
MyReader(Reader r) throws IOException{
reader = new BufferedReader(r);
}
public int nextInt() throws IOException {
return Integer.parseInt(nextToken());
}
public String nextToken() throws IOException {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
}
public class Temp {
public static void main(String[] args) throws IOException{
MyReader reader = new MyReader(new FileReader("output.txt"));
int n = 1000*1000;
int x;
long time = System.currentTimeMillis();
for (int i = 0; i < n; ++i)
x = reader.nextInt();
System.out.println(System.currentTimeMillis()-time);
}
}
</pre>
Время работы на моём компьютере около 300 мс! По аналогии с методом <i>nextInt()</i> можно добавить методы и для остальных типов и будет прямо как Scanner. Только работать будет в разы быстрее. ;)<br />
Для ввода из консоли используйте:<br />
<pre class="brush:java">MyReader reader = new MyReader(new InputStreamReader(System.in));
</pre>
<b>Нужна хорошая скорость ввода - <i>BufferedReader </i>вам в помощь!</b><br />
Надеюсь кому-нибудь это пригодится.<br />
Удачи!dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-73504384727694048662011-12-17T04:06:00.000+03:002011-12-17T04:06:01.695+03:00Integer пул(pool)Наверняка вам известно, что при сравнении двух объектов в Java на == обычно получается не тот результат, что нужен, т.к. идет сравнение ссылок на объекты, а не данных этих объектов.<br />
Хм, давайте тогда посмотрим на следующий код и на результат его выполнения:<br />
<pre class="brush:java">public class Temp {
public static void main(String []args){
Integer i1 = 10;
Integer i2 = 10;
System.out.println(i1 == i2);
}
}</pre>
Как думаете, что он напечатает? А напечатает он true.<br />
<a name='more'></a><br />
А вот еще один код:<br />
<pre class="brush:java">public class Temp {
public static void main(String []args){
Integer i1 = 130;
Integer i2 = 130;
System.out.println(i1 == i2);
}
}</pre>
Этот код уже выведет false.<br />
На первый взгляд странно, не так ли? Сейчас объясню.<br />
В Java есть пул(pool) целых чисел в промежутке [-128;127]. Т.е. если мы создаем Integer в этом промежутке, то вместо того, чтобы каждый раз создавать новый объект, JVM берет их из пула. Таким образом, в первом примере i1 и i2 указывают на один и тот же объект из пула, а во втором - создаются два разных объекта. Отсюда и результат.<br />
Стоит заметить, что в приведенных выше примерах не использовалось ключевое слово new.<br />
Пример:
<br />
<pre class="brush:java">public class Temp {
public static void main(String []args){
Integer i1 = new Integer(10);
Integer i2 = new Integer(10);
System.out.println(i1 == i2);
}
}</pre>
Результатом будет false. Тут мы уже явно говорим, что хотим создать новый(new) объект, так что ссылки разные.<br />
Вот и всё.dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com1tag:blogger.com,1999:blog-4331963339966002988.post-3435487364665127122011-12-15T01:05:00.000+03:002011-12-17T01:02:16.887+03:00Переопределение equals и hashCodeЕсть у класса Object такой метод, как equals, который используется для сравнения двух объектов. По умолчанию он выглядит так:<br />
<pre class="brush:java">public boolean equals(Object obj){
return (this == obj);
}</pre>
Т.е. просто сравниваются две ссылки(прямо как оператор "=="). Понятно, что обычно, это не то, что нам надо. Обычно два объекта равны, если основные данные их равны. Чтобы это понимали не только мы, но и компилятор, нам и нужно переопределять метод equals. Существует несколько свойств, которым должен удовлетворять наш переопределенный метод, а именно:<br />
<ol>
<li>Симметричность. Т.е. если для каких-либо объектов <i>x </i>и <i>y</i> x.equals(y) возвращает true, то и y.equals(x) должен возвращать true.</li>
<li>Рефлексивность. Для любого объекта <i>x </i>x.equals(x) должен возвращать true.</li>
<li>Постоянство. Для любых объектов <i>x</i> и <i>y </i>x.equals(y) возвращает одно и тоже, если информация, используемая в сравнениях, не меняется.</li>
<li>Транзитивность. Для любых объектов <i>x, y </i>и <i>z, </i>если x.equals(y) вернет true и y.equals(z) вернет true, то и x.equals(z) должен вернуть true.</li>
</ol>
В этих свойствах подразумевается, что объекты не null. А для null всё просто<br />
<ul>
<li>Для любого не null объекта <i>x </i>x.equals(null) должен возвращать false.</li>
</ul>
Итак, предположим у нас есть такой вот класс:<br />
<a name='more'></a><br />
<pre class="brush:java">public class MyClass{
private int x;
public MyClass(int x){ this.x = x; }
public int getX(){ return x; }
}</pre>
Очевидно, нам надо, чтобы equals возвращал true тогда и только тогда, когда поля <i>x</i> у объектов равны. Что ж, переопределенный метод будет выглядеть примерно так:
<br />
<pre class="brush:java"> @Override
public boolean equals(Object obj){
if (this == obj)
return true;
if (!(obj instanceof MyClass))
return false;
MyClass myClass = (MyClass)obj;
return (x == myClass.getX());
}</pre>
Кстати, не забывайте, что тип аргумента должен быть именно Object, а не MyClass. В этом случае это будет уже не переопределение(overriding), а перегрузка(overloading). Именно поэтому, при переопределении следует использовать конструкцию @Override, она проверит, действительно ли ваш метод переопределяет метод суперкласса, и, если это не так, выдаст ошибку.<br />
Пройдемся по коду. Сначала идет проверка на свойство №2(рефлексивность). Затем мы должны сравнить наши поля <i>x</i>, но т.к. в метод передается Object, то нам надо делать приведение типа. А вдруг нам передали не MyClass? Тут нам пригодится instanceof. x instanceof y проверяет: является ли <i>x</i> экземпляром <i>y</i>. Однако конструкция instanceof не только позволяет нам отбросить неверные объекты, но и проверяет наше свойство о null-объектах, т.к. x instanceof y возвращает false, если <i>x - </i>null. Ну а дальше мы непосредственно проверяем наши поля на равенства.<br />
И вроде все бы ничего, переопределили equals, всё работает. Однако, переопределяя equals вы должны позаботиться еще об одном методе класса Object:<br />
<pre class="brush:java">public native int hashCode()</pre>
Существуют следующие соглашения, относительно этих двух методов:<br />
<ul>
<li>Всякий раз, когда метод вызывается у одного и того же объекта во время выполнения приложения, он должен возвращать одно и то же число, если используемая информация не изменяется. hashCode может возвращать разные значения для идентичных объектов в различных экземплярах приложения.</li>
<li>Если два объекта равны, согласно equals, то их hashCode должны возвращать одинаковые значения.</li>
<li>Обратное требование необязательно. Два неравных объекта могут возвращать одинаковый hashCode. Однако для повышения производительности, лучше, чтобы разные объекты возвращали разные коды.</li>
</ul>
Итак, равные объекты должны иметь одинаковые хэш-коды. Лучший способ гарантировать это - использовать для вычисления хэш-кода те же данные, что участвуют в сравнении.<br />
Метод hashCode используется в hash-коллекциях(например HashSet), и чем меньше будет коллизий(одинаковый код при разных объектах) тем эффективнее эти коллекции будут работать с объектами вашего класса.<br />
В приведенном выше классе MyClass хэш-кодом может выступать само значение <i>x</i>. Это совсем тривиальный случай. А что, если у нас, наряду с числом <i>x</i>, будет например строка <i>s.</i><br />
Часто используют примерно такой подход:
<br />
<pre class="brush:java"> @Override
public int hashCode(){
int code = 11;
int k = 7;
code = k*code + x;
code = k*code + s.hashCode();
return code;
}</pre>
Думаю принцип понятен.
Всем удачи!dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-25765325047160995352011-12-05T21:57:00.001+03:002011-12-05T22:58:20.533+03:00Сериализация статических полейСериализация (serialization) объектов Java позволяет взять вам любой объект, реализующий интерфейс Serializable, и превратить его в последовательность байтов, из которой затем можно полностью восстановить исходный объект.<br />
Чтобы сериализовать объект, требуется создать выходной поток OutputStream, который нужно вложить объект ObjectOutputStream. По сути, вызов метода writeObject() осуществляет сериализацию объекта, и далее вы пересылаете его в выходной поток данных OutputStream. Для восстановления объекта необходимо надстроить объект ObjectInputStream для входного потока InputStream, а затем вызвать метод readObject(). Этот метод возвращает ссылку на объект типа Object, поэтому после вызова метода следует провести нисходящее преобразование для получения объекта нужного типа.<br />
<a name='more'></a>Давайте рассмотрим пример сериализации:<br />
<pre class="brush:java">import java.io.*;
class A implements Serializable{
private static int n=0;
private int i;
A(int i){
this.i=i;
n=i;
}
public String toString(){
return i+" "+n;
}
}
public class Temp{
public static void main(String []args) throws IOException,ClassNotFoundException {
A a = new A(5);
System.out.println(a);
String path = "serial.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
oos.writeObject(a);
a = new A(10);
System.out.println(a);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
a = (A)ois.readObject();
System.out.println(a);
}
}</pre>
Вывод этой программы будет следующий:<br />
5 5<br />
10 10<br />
5 10<br />
<br />
Итак, мы сериализовали объект со значением поля i=5 и значением статического поля n=5, создали новый объект(i=10,n=10), и десериализовали записанный объект. Как видим, обычное поле успешно десериализовалось, а вот статическое осталось без изменений. Если вам нужно сериализовать статические поля, вы должны делать это вручную. Исправим нашу предыдущую программу так, чтобы она сохраняла статическую переменную:<br />
<pre class="brush:java">import java.io.*;
class A implements Serializable{
private static int n=0;
private int i;
A(int i){
this.i=i;
n=i;
}
public String toString(){
return i+" "+n;
}
public static void serializeStatic(ObjectOutputStream oos) throws IOException{
oos.writeInt(n);
}
public static void deserializeStatic(ObjectInputStream ois) throws IOException{
n=ois.readInt();
}
}
public class Temp{
public static void main(String []args) throws IOException,ClassNotFoundException {
A a = new A(5);
System.out.println(a);
String path = "serial.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
A.serializeStatic(oos);
oos.writeObject(a);
a = new A(10);
System.out.println(a);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
A.deserializeStatic(ois);
a = (A)ois.readObject();
System.out.println(a);
}
}</pre>
Вывод:<br />
5 5<br />
10 10<br />
5 5<br />
<br />
Как видите, теперь все в порядке. Мы просто добавили и вызвали два статических метода: для сериализации и десериализации статической переменной.<br />
Всего хорошего!dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-89459328087251472232011-12-01T01:33:00.001+03:002011-12-01T02:13:05.209+03:00Конструкции .this и .newЕсли вам понадобится получить ссылку на объект внешнего класса, запишите имя внешнего класса, за которым следует точка, а затем ключевое слово this. Полученная ссылка автоматически относится к правильному типу, известному и проверяемому на стадии компиляции, поэтому дополнительные издержки на стадии выполнения не требуются. Следующий пример показывает, как использовать конструкцию .this:<br />
<a name='more'></a><br />
<pre class="brush:java">public class Outer{
void f(){ System.out.println("Outer.f()"); }
public class Inner{
public Outer outer(){
return Outer.this;
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args){
Outer o = new Outer();
Outer.Inner oi = o.inner();
oi.outer().f();
}
}</pre>
результатом будет:<br />
Outer.f()<br />
<br />
Иногда бывает нужно приказать другому объекту создать объект одного из его внутренних классов. Для этого перед .new указывается ссылка на другой объект внешнего класса: <br />
<pre class="brush:java">public class Outer{
public class Inner{}
public static void main(String[] args){
Outer o = new Outer();
Outer.Inner oi = o.new Inner();
}
}</pre>
При создании объекта внутреннего класса указывается не имя внешнего класса Outer, а имя <i>объекта</i> внешнего класса. Это также решает проблему видимости имен для внутреннего класса, поэтому мы не можем использовать запись вида o.new Outer.Inner().<br />
Невозможно создать объект внутреннего класса, не имея ссылки на внешний класс. Но если создать вложенный класс(статический внутренний класс), то ссылка на объект внешнего класса не нужна.dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-3965741575209677502011-11-20T16:59:00.001+03:002011-11-21T04:02:52.574+03:00МодификаторыВ Java интерфейсы, классы и их члены могут быть объявлены с одним или несколькими модификаторами. Их можно разделить по категориям:<br />
<b>модификаторы класса:</b><br />
public private(для внутренних классов) protected(для внутренних классов) abstract static final strictfp<br />
<b>модификаторы полей:</b><br />
public protected private static final transient volatile<br />
<b>модификаторы методов:</b><br />
public protected private abstract static final synchronized native strictfp<br />
<b>модификаторы конструкторов:</b><br />
public protected private<br />
<br />
Давайте рассмотрим назначения каждого из этих модификаторов.<br />
<a name='more'></a><br />
Модификаторы доступа: public protected private - устанавливают область видимости элемента.<br />
<b>public</b> - элемент доступен из любого класса.<br />
<b>protected</b> - элемент доступен для классов-наследников и классов в пределах пакета.<br />
<b>private</b> - элемент доступен только внутри класса.<br />
В случае отсутствия этих модификаторов используется доступ по умолчанию(<b>default, package private</b>) - элемент доступен только в пределах пакета.<br />
<br />
Некоторые модификаторы имеют специфические значения в зависимости от того, к какому элементу они применяются.<br />
<br />
<b>final</b><i> </i><br />
<i>класс</i>: нельзя наследовать; <i> </i><br />
<i>поле:</i> после инициализации не может изменяться(в случае объектов не может изменяться <i>ссылка</i> на объект, а состояние самого объекта - может); <i> </i><br />
<i>метод:</i> нельзя переопределять.<br />
<b>static</b><br />
<i>вложенный класс:</i> не имеет доступа к нестатическим элементам внешнего класса;<br />
<i>поле: </i>существует на уровне класса, а не объекта;<br />
<i>метод:</i> существует на уровне класса и не может вызывать нестатические методы.<br />
<b>strictfp</b><br />
<i>метод: </i>вычисления с плавающей точкой будут соответствовать стандарту IEEE 754;<br />
<i>класс: </i>все методы работают по стандарту IEEE 754.<br />
<b>abstract</b><br />
<i>класс:</i> нельзя создавать объекты абстрактного класса(наличие модификатора обязательно, если есть хотя бы 1 абстрактный метод);<br />
<i>метод: </i>состоит лишь из объявления(без тела).<br />
<b>transient</b><br />
<b> </b><i>поле: </i>не сериализуется.<br />
<b>volatile</b><br />
<i>поле: </i>говорит виртуальной машине, что поле может использоваться в других потоках и кэшировать его не надо.<b> </b><br />
<b>native</b><br />
<i>метод: </i>метод реализован на другом языке.<br />
<b>synchronized</b><br />
<i>метод: </i>метод синхронизирован(если задача выполняется внутри одного из объявленных как synchronized методов, все остальные потоки не смогут зайти <u>ни в какой</u> synchronized метод.<b><br /></b>dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-73236564418809037502011-11-15T04:28:00.001+03:002011-11-15T15:46:17.383+03:00Коллекции. Краткий обзорВ языке Java существует довольно-таки много классов для хранения группы объектов, поэтому, чтобы не запутаться, следует разобраться, что из них и когда стоит использовать.<br />
Начнём с такой вот хорошей таблицы:<br />
<table border="1" cellspacing="0" summary="General-purpose-implementations"><tbody>
<tr><th id="h1" width="15%">Интерфейс</th>
<th id="h2">Hash table реализация</th>
<th id="h3">Resizable array реализация</th>
<th id="h4">Tree реализация</th>
<th id="h5">Linked list реализация</th>
<th id="h6">Hash table + Linked list реализация</th>
</tr>
<tr>
<td headers="h1"><code>Set</code></td>
<td headers="h2"><code>HashSet</code></td>
<td headers="h3"><br /></td>
<td headers="h4"><code>TreeSet</code></td>
<td headers="h5"><br /></td>
<td headers="h6"><code>LinkedHashSet</code></td>
</tr>
<tr>
<td headers="h1"><code>List</code></td>
<td headers="h2"><br /></td>
<td headers="h3"><code>ArrayList</code></td>
<td headers="h4"><br /></td>
<td headers="h5"><code>LinkedList</code></td>
<td headers="h6"><br /></td>
</tr>
<tr>
<td headers="h1"><code>Queue</code></td>
<td headers="h2"><br /></td>
<td headers="h3"><br /></td>
<td headers="h4"><br /></td>
<td headers="h5"><code>LinkedList</code></td>
<td headers="h6"><br /></td>
</tr>
<tr>
<td headers="h1"><code>Map</code></td>
<td headers="h2"><code>HashMap</code></td>
<td headers="h3"><br /></td>
<td headers="h4"><code>TreeMap</code></td>
<td headers="h5"><br /></td>
<td headers="h6"><code>LinkedHashMap</code></td></tr>
</tbody></table>
<br />
<br />
<a name='more'></a>Из этой таблицы очень хорошо видны основные интерфейсы и реализации коллекций в Java. Также существуют интерфейсы SortedSet и SortedMap, имеющие только TreeSet и TreeMap реализации соответственно. Интерфейс Queue (очередь) имеет также специфическую реализацию PriorityQueue (приоритетная очередь, куча). А теперь пройдемся по основным интерфейсам и их реализациям более подробно.<br />
<b>Set:</b><br />
Set - есть ни что иное, как множество(логично). Хранит только уникальные значения.<br />
<i>HashSet - </i>элементы не упорядочены. Это объясняется тем, что используется хэширование для ускорения выборки. Так что используйте HashSet если порядок элементов не важен, т.к. поиск в нём самый быстрый.<br />
<i>LinkedHashSet - </i>элементы хранятся в порядке добавления. Добавление элемента, эквивалентного хранящемуся во множестве, не изменяет порядка.<br />
<i>TreeSet</i> - элементы упорядочены в естественном порядке.<br />
<b>List:</b><br />
<i>ArrayList - </i>аналог обычного массива, но с динамически изменяемым размером. Используйте, если нужен доступ к элементу по индексу и добавление в конец списка или удаление из конца.<br />
<i>LinkedList</i> - список. Используется, если необходимо добавление/удаление в произвольном месте списка. Однако поиск медленней, чем в ArrayList.<br />
<b>Queue:</b><br />
<i>LinkedList - </i>очередь, на основе списка. Структура данных "очередь", работает по принципу FIFO(First-In-First-Out) - "первый пришёл - первый вышел", т.е. добавление элемента происходит в конец очереди, а выборка из начала, причем при выборке элемент удаляется.<br />
<b>Map:</b><br />
Map - ассоциативные контейнеры.<b> </b>В Map'е хранится ключ и связанное с ним значение.<br />
Характеристика реализаций аналогична множеству.<br />
Ну и конечно же, примеры использования всего этого добра:<br />
<pre class="brush:java">import java.util.*;
public class CollectionsExample {
public static void main(String []args){
Set<Integer> hSet = new HashSet<Integer>();
Set<Integer> tSet = new TreeSet<Integer>();
Set<Integer> lhSet = new LinkedHashSet<Integer>();
Random rand = new Random(38);
for (int i = 0; i < 10; ++i){
int t = rand.nextInt(100);
hSet.add(t);
tSet.add(t);
lhSet.add(t);
System.out.print(t + " ");
}
System.out.println("\nHashSet: " + hSet);
System.out.println("TreeSet: " + tSet);
System.out.println("LinkedHashSet: " + lhSet);
System.out.println("hSet.contains(25) " + hSet.contains(25));
List<Integer> aList = new ArrayList<Integer>();
List<Integer> lList = new LinkedList<Integer>();
for (int i = 0; i<10; ++i){
int t = rand.nextInt(100);
aList.add(t);
lList.add(t);
}
lList.add(2,rand.nextInt(100)); //index,element
System.out.println("ArrayList: " + aList);
System.out.println("LinkedList: " + lList);
System.out.println("aList.get(4) " + aList.get(4));
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(2); queue.add(5); queue.add(1);
System.out.println("Queue: " + queue);
System.out.println("queue.element() " + queue.element());
System.out.println("Queue: " + queue);
System.out.println("queue.remove() " + queue.remove());
System.out.println("Queue: " + queue);
Map<Integer,String> map = new HashMap<Integer, String>();
map.put(1,"one");
map.put(2,"two");
System.out.println("HashMap: " + map);
System.out.println("map.containsKey(1) " + map.containsKey(1));
System.out.println("map.containsValue(\"three\") " + map.containsValue("three"));
System.out.println("map.get(2) " + map.get(2));
}
}
</pre>dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-75948108420834137932011-11-11T20:34:00.001+03:002011-11-11T21:49:18.796+03:00finalize() и сборщик мусораВсе знают и помнят о важности инициализации, но многие забывает о значимости приборки за собой. Конечно, в Java есть сборщик мусора(garbage collector), который выполняет за вас грязную работу и освобождает память от ненужных объектов. Но если, например, ваш объект выделяет память каким-нибудь специфическим способом(без использования new), то тут сборщик мусора вам не поможет. Для таких случаев в Java и предусмотрен метод finalize(), который вы можете определить в вашем классе. Когда сборщик мусора захочет освободить память, занимаемую ненужным объектом, он сначала вызовет метод finalize() этого объекта, и только потом удалит сам объект. Но(!) следует помнить, что ваши объекты могут быть и не переданы сборщику мусора.<br />
<a name='more'></a><br />
Так что если перед тем, как объект станет ненужным, необходимо выполнить некоторые завершающие действия, то делайте это собственноручно, не стоит полагаться на finalize().<br />
Может случиться так, что память объекта никогда не будет освобождена, потому что программа даже не приблизиться к точке критического расхода ресурсов. Помните, что ни сборка мусора, ни финализация не гарантированы.<br />
И немного об этом загадочном сборщике мусора.<br />
Как бы ни странно это звучало, но использование сборщика мусора даёт немалый эффект по <i>ускорению</i> создания объектов. Любой существующий объект прослеживается до ссылки находящейся в стеке или статической памяти. Таким образом, если начать проверку со стека и статического хранилища, мы обязательно доберемся до всех используемых объектов. Для каждой найденной ссылки надо взять объект, на который она указывает, и отследить все ссылки этого объекта, при этом выявляются все другие объекты, на которые они указывают, и так далее. Таким образом будет проверена вся структура ссылок, берущая начало в стеке и статической памяти. Каждый объект, обнаруженный в ходе поиска, всё ещё используется. Работа программы временно приостанавливается, затем все найденные используемые объекты копируются из одной кучи в другую, а мусор остается в первой. При копировании объектов в новую кучу они размещаются в виде компактной непрерывной цепочки. При копировании все ссылки переопределяются.<br />
Существует два фактора, из-за которых такой механизм обладает низкой эффективностью. Во-первых, существует две кучи, и вы перекидываете всё то туда, то сюда между двумя кучами, и при этом половина памяти тратится впустую. Во-вторых, копирование в фазе стабильной работы программы, когда отходов становится мало, очень невыгодно. Некоторые JVM определяют, что новых отходов появляется очень мало, и переключаются в другой режим сборки мусора. Тут точно так же находятся используемые и неиспользуемые объекты, но копирования в другую кучу не происходит, и если сборщик мусора захочет уплотнить фрагментированную кучу, то делается это перемещением объектов внутри неё.<br />
Виртуальная машина постоянно следит за эффективностью сборки мусора, и, если надо, переключает режим. Таким образом, куча после сборки мусора достаточно фрагментированна, и выделение новой памяти происходит не поиском свободного места, а смещением указателя начала кучи, почти как в стеке.<br />
<br />dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-49270505573337484762011-11-10T03:33:00.000+03:002011-11-11T01:17:48.378+03:00Коротко о clone()Метод clone() в Java используется для(подожди-подожди...) клонирования объектов. Т.к. Java работает с объектами с помощью ссылок, то простым присваиванием тут не обойдешься, ибо в таком случае копируется лишь адрес, и мы получим две ссылки на один и тот же объект, а это не то, что нам нужно. Механизм копирования обеспечивает метод clone() класса Object.<br />
clone() действует как конструктор копирования. Обычно он вызывает метод clone() суперкласса и т.д. пока не дойдет до Object.<br />
<a name='more'></a> <br /><br />
Метод clone() класса Object создает и возвращает копию объекта с такими же значениями полей. Object.clone() кидает исключение CloneNotSupportedException если вы пытаетесь клонировать объект не реализующий интерфейс Cloneable. Реализация по умолчанию метода Object.clone() выполняет неполное/поверхностное (shallow) копирование. Если вам нужно полное/глубокое (deep) копирование класса то в методе clone() этого класса, после получения клона суперкласса, необходимо скопировать нужные поля.<br />
Синтаксис вызова clone() следующий:<br />
<pre class="brush:java">Object copy = obj.clone();</pre>
<br />
или чаще:<br />
<pre class="brush:java">MyClass copy = (MyClass) obj.clone();</pre>
<br />
Один из недостатков метода clone(), это тот факт, что возвращается тип Object, поэтому требуется нисходящее преобразование типа. Однако начиная с версии Java 1.5 при переопределении метода вы можете сузить возвращаемый тип.<br />
Пару слов о clone() и final полях.<br />
Метод clone() несовместим с final полями. Если вы попробуете клонировать final поле компилятор остановит вас. Единственное решение - отказаться от final.<br />
Ну и пример использования clone():<br />
<pre class="brush:java">class MyClass implements Cloneable{
public Integer i = 10;
public MyClass clone() throws CloneNotSupportedException{
MyClass obj=(MyClass)super.clone();
obj.i = i;
return obj;
}
public String toString(){
return i.toString();
}
}
public class Temp {
public static void main(String []args) throws CloneNotSupportedException{
MyClass a = new MyClass();
a.i = 11;
MyClass b = a.clone();
MyClass c = a;
System.out.println("a: " + a + " b: " + b + " c: " + c);
a.i=12;
System.out.println("a: " + a + " b: " + b + " c: " + c);
}
} </pre>
<br />
Консоль:<br />
a: 11 b: 11 c: 11<br />
a: 12 b: 11 c: 12<br />
<br />
Как видите, изменение объекта <i>a </i>повлекло за собой изменение объекта <i>c, </i>а вот с <i>b </i>всё в порядке.dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-34808739483229353672011-11-08T17:20:00.000+03:002011-11-11T01:18:27.828+03:00String, StringBuilder и StringBuffer: что использовать?Самое важное отличие String от StringBuilder/StringBuffer - это то, что String immutable, в то время как StringBuilder/StringBuffer mutable.<br />
Что же это значит? А значит это то, что значение String <b>не может</b> изменяться. Но вы ведь много раз так делали, скажите вы. Всё дело в том, что при изменении значения String в действительности создается новый объект с новым значением. И, конечно же, создание новых объектов при каждом изменении - операция неэффективная. <br />
<a name='more'></a>В действительности, такой код:<br />
<pre class="brush:java">String s = "a";
s += "b";</pre>
равносилен этому коду:<br />
<pre class="brush:java">String s = "a";
s = new StringBuilder(s).append("b").toString();</pre>
А вот StringBuilder/StringBuffer являются mutable. У них нет такой проблемы. Но в чем же между ними разница? Разница в том, что StringBuffer синхронизирован, а StringBuilder - нет. Так что в однопоточном приложении лучше использовать класс StringBuilder - он быстрей.<br />
Итак, подводя итог, критерии выбора между этими классами:<br />
String: если значение не изменяется.<br />
StringBuilder: если значение изменяется, и доступ к строке имеет только один поток (класс был введен в Java 1.5)<br />
StringBuffer: если значение изменяется и требуется мультипоточность.<br />
На этом всё! <br />
<br />dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-45181500444057283182011-11-07T18:39:00.000+03:002011-11-11T01:19:37.012+03:00Маленький сюрприз от toLowerCase()<div dir="ltr" style="text-align: left;" trbidi="on">
Наверняка все вы пользовались таким прекрасным методом, как toLowerCase(). Да, очень удобный метод для перевода символов в нижний регистр. Но есть один нюанс о котором вы должны знать.<br />
toLowerCase() выполняет преобразования относительно вашей локали. При вызове toLowerCase() в действительности вызывается toLowerCase(Locale.getDefault()).<br />
<a name='more'></a><br />
Давайте рассмотрим следующий пример:<br />
<br />
<pre class="brush:java">import java.util.Locale;
public class Temp {
public static void main(String args[]){
Locale.setDefault(new Locale("lt")); //Литва
String str = "\u00cd";
System.out.println("str: "+str+" "+str.length());
String lowStr = str.toLowerCase();
System.out.println("lowStr: "+lowStr+" "+lowStr.length());
}
}</pre>
<br />
И что у нас на выходе? А вот что:<br />
str: Í 1<br />
lowStr: i̇́ 3<br />
Вы это видите? Длина строки увеличилась с 1 до 3! Это может стать причиной трудноуловимой ошибки, если вы не знаете об этой особенности toLowerCase(). Но теперь-то вы в курсе. ;)<br />
Удачи!</div>dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0tag:blogger.com,1999:blog-4331963339966002988.post-23891903132191518632011-11-05T23:36:00.004+03:002011-11-11T01:19:50.924+03:00Переопределение(override) статического метода<div dir="ltr" style="text-align: left;" trbidi="on">
Можно ли переопределить(override) статический метод? И да, и нет.<br />
Да - потому, что никто вам не запрещает этого делать, в том числе и компилятор. Переопределяйте, пожалуйста. И нет - потому, что сколько бы вы не переопределяли статический метод, выполнятся все равно будет базовый.<br />
<a name='more'></a><br />
Рассмотрим пример:<br />
<br />
<pre class="brush:java">class A{
static void f(){ System.out.println("A");}
}
class B extends A{
static void f(){ System.out.println("B");}
}
public class Test{
public static void main(String []args){
A aa = new A();
A ab = new B();
B bb = new B();
aa.f();
ab.f();
bb.f();
}
}</pre>
<br />
Итак, что имеем на выходе? А имеем мы следующее:<br />
A<br />
A<br />
B<br />
Нас интересует вторая строка, ведь мы, переопределяя метод, ожидали увидеть в ней "B".<br />
А происходит это потому, что выбор вызываемого <b>статического</b> метода происходит при раннем связывании(на этапе компиляции, а не выполнения).<br />
Так что будьте внимательней, ибо (ещё раз) компилятор вам ничего на этот счёт не скажет.<br />
Удачи!<br />
<br /></div>dimochttp://www.blogger.com/profile/05338887998249163225noreply@blogger.com0