AndroidSDK, JDK 64-bit и Windows 7 64-bit
Данная зверушка при попытке запуска SDK Manager или инсталятора ругается на отсутствие JDK, который на самом деле есть.
Решение:
Экспортируем и удаляем ветку реестра
[HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\]
И импортируем её в ветку
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\]
(путем редактирования путей в файле)
Вуаля, Ондроед находит Жабу.
[Java] Новый IntelliJ IDEA 12
Вышла новая, 12 версия замечательного IDE.
Офф сайт: http://www.jetbrains.com/idea/index.html
Потыкал пока поверхностно.
+ Новая цветовая схема очень приятная глазу.
+ Добавился редактор форм для Дроида, теперь можно не использовать внешние утилиты
- При переходе на редактор форм и обратно закрывается дерево проекта. Раздражает.
- Очень долго искал, как же переключить схему
Еще немного о классах
Класс - это упрощенное описание каких-нибудь реальных (чаще, правда, выдуманных) вещей.
Вот, например, точка. Единственное, что есть у точки - это её координаты в пространстве. Это её параметры.
Как задать точку на плоскости? Надо нарисовать точку и подписать её: M(1,2), т.е. точка с именем M и координатами х = 1, у = 2.
Это её "конструктор". Т.е. мы "сконструировали" конкретную точку М с конкретными координатами.
На языке Java это будет выглядеть так:
class Point { //общее описание точек private double x, y; //параметры точки Point(double ax, double ay) { //конструктор x = ax; y = ay; } }
Сконструируем точку
Point M = new Point(1, 2);
В данном классе задан один конкретный конструктор. Из-за этого каждая создаваемая точка будет ожидать, что при создании ей назначат координаты.
Т.е. данная строчка работать не будет:
Point M = new Point(); //пустые параметры //или Point M = new Point(1); //неполные параметры
Дальше. Класс включает в себя не только параметры, но и методы.
Что такое метод класса? Это вопрос, который мы можем задать или указание, что-либо сделать. Причем и вопрос и указания нужно адресовать уже конкретной сконструированной точке.
Научим точку сообщать свои координаты и перемещаться по одной из координатных осей:
class Point { //общее описание точек private double x, y; //параметры точки Point(double ax, double ay) { //конструктор x = ax; y = ay; } //запрос координаты Х double getX() { return x; } //запрос координаты Y double getY() { return y; } //указание сдвинуться по оси X на расстояние dx void moveX(double dx) { x = x + dx; } //указание сдвинуться по оси Y на расстояние dy void moveY(double dy) { y = y + dy; } } //использование public class Main { public static void main(String[] args) { //создаём точку Point M = new Point(1, 2); //спрашиваем у созданной точки - скажи нам, точка М свои координаты X и Y System.out.println("Текущие координаты точки М: x = " + M.getX() + ", у = " + M.getY()); System.out.println("Сдвинем точку по оси Х на 5 и по оси У на -1"); //просим точку М - точка М, сдвинься на 5 по оси X M.moveX(5); //просим точку М - точка М, сдвинься на -1 по оси Y M.moveY(-1); //спрашиваем у точки М - скажи нам, точка М свои координаты X и Y System.out.println("Новые координаты точки М: x = " + M.getX() + ", у = " + M.getY()); } }
Еще раз повторю - методы вызываются у конкретной точки - сконструированного объекта.
Класс - это просто заготовка, шаблон, описание.
Т.е. пока точка не создана - мы как бы задумываем её нарисовать.
А вот когда сказали new, это значит, что мы нарисовали конкретную точку в конкретном месте координатной плоскости.
Записи вида
Point.getX(); //или Point.moveX(5);
Не имеют смысла, потому что описание ничего не знает.
Это как если спросить у человека - "скажи мне координаты точки?"
Логично будет подумать, что он ответит - "какой именно?"
Также делает и компилятор.
[Java] this, super
1. Как-то я писал, что не понимаю, зачем вызывать конструктор в конструкторе через this.
Разобрался.
Это для укорачивания кода.
Типа можно так:
class Point { int х, у; Point(int х, int у) { this.x = х; this.у = у; } Point() { this.x = -1; this.у = -1; } }
А можно короче:
class Point { int х, у; Point(int х, int у) { this.x = х; this.у = у; } Point() { this(-1, -1); //конструктор вызывает другой конструктор } }
Есть одно ограничение на вызов одного конструктора из другого. Такой вызов должен быть первым оператором в вызывающем конструкторе.
2. super
Данная функция служит для вызова конструктора базового класса. Используется, если базовый класс, например, не имеет конструктора по умолчанию
Пример
class X { X(int a) { ... } ... } class Y extends X { Y() { super(0); ... } ... }
Также super может использоваться и для явного вызова методов базового класса. Это необходимо, если некоторый метод базового класса был переопределен в порожденном классе.
Пример
class Base { int x = 1; long y; Base(long y) { this.y = y; } Base() { this(0); // вызов конструктора Base(long y) } public long f() { return x*y; } } class Derived extends Base { String name = ""; Derived(String name, long par) { super(par); // вызов конструктора Base(long y) this.name = name; } public long g(int r) { return r+super.f(); // вызов метода f() класса Base } public long f() { x++; return 2*y; } }
[Java] Структуры данных. Список
Список, для начала, возьмем простой линейный односвязный.
Список есть динамическая структура данных.
Каждый элемент списка содержит в себе данные и указатель на следующий элемент.
Возьмем простой вариант данных в списке - просто целые числа.
Элемент списка:
class ListElement { ListElement next; // указатель на следующий элемент int data; // данные }
Сам список также будет классом.
Будет содержать в себе указатель на первый элемент списка и на последний - head и tail.
Также реализуем методы:
1. Добавление элемента в конец списка
2. Добавление элемента в начало списка
3. Удаление элемента по значению
4. Печать всего списка
class List { private ListElement head; // указатель на первый элемент private ListElement tail; // указатель последний элемент void addFront(int data) //добавить спереди { ListElement a = new ListElement(); //создаём новый элемент a.data = data; //инициализируем данные. // указатель на следующий элемент автоматически инициализируется как null if(head == null) //если список пуст { //то указываем ссылки начала и конца на новый элемент head = a; //т.е. список теперь состоит из одного элемента tail = a; } else { a.next = head; //иначе новый элемент теперь ссылается на "бывший" первый head = a; //а указатель на первый элемент теперь ссылается на новый элемент } } void addBack(int data) { //добавление в конец списка ListElement a = new ListElement(); //создаём новый элемент a.data = data; if (tail == null) //если список пуст { //то указываем ссылки начала и конца на новый элемент head = a; //т.е. список теперь состоит из одного элемента tail = a; } else { tail.next = a; //иначе "старый" последний элемент теперь ссылается на новый tail = a; //а в указатель на последний элемент записываем адрес нового элемента } } void printList() //печать списка { ListElement t = head; //получаем ссылку на первый элемент while (t != null) //пока элемент существуе { System.out.print(t.data + " "); //печатаем его данные t = t.next; //и переключаемся на следующий } } void delEl(int data) //удаление элемента { if(head == null) //если список пуст - return; //ничего не делаем if (head == tail) { //если список состоит из одного элемента head = null; //очищаем указатели начала и конца tail = null; return; //и выходим } if (head.data == data) { //если первый элемент - тот, что нам нужен head = head.next; //переключаем указатель начала на второй элемент return; //и выходим } ListElement t = head; //иначе начинаем искать while (t.next != null) { //пока следующий элемент существует if (t.next.data == data) { //проверяем следующий элемент if(tail == t.next) //если он последний { tail = t; //то переключаем указатель на последний элемент на текущий } t.next = t.next.next; //найденный элемент выкидываем return; //и выходим } t = t.next; //иначе ищем дальше } } }
Тонкости Java-реализации:
Освобождать память не надо - достаточно чтобы на выделенные по new
участок не было указателей и тогда сборщик мусора сам её почистит.
Все переменные являются ссылками на объекты, так что нет заморочек с разыменование указателей и передачи адресов.
Испоьзование:
public class Main { public static void main(String[] args) { List ml = new List(); ml.addBack(1); ml.addBack(2); ml.addBack(3); ml.addFront(6); ml.printList(); System.out.println(); ml.delEl(6); ml.delEl(5); ml.delEl(12); ml.delEl(2); ml.printList(); System.out.println(); } }
Распечатает:
6 1 2 3 1 3
А теперь немного магии :)
С целочисленным списком скучно. Сделаем элемент списка универсальным!
Это можно сделать при помощи "шаблонизации"
Причем какой именно тип - будет автоматически определяться при сборке!
class ListElement<E> { ListElement next; E data; } class List<E> { private ListElement head; // указатель на первый элемент private ListElement tail; // указатель последний элемент void addFront(E data) //добавить спереди { ListElement a = new ListElement(); //создаём новый элемент a.data = data; //инициализируем данные. // указатель на следующий элемент автоматически инициализируется как null if(head == null) //если список пуст { //то указываем ссылки начала и конца на новый элемент head = a; //т.е. список теперь состоит из одного элемента tail = a; } else { a.next = head; //иначе новый элемент теперь ссылается на "бывший" первый head = a; //а указатель на первый элемент теперь ссылается на новый элемент } } void addBack(E data) { //добавление в конец списка ListElement a = new ListElement(); //создаём новый элемент a.data = data; if (tail == null) //если список пуст { //то указываем ссылки начала и конца на новый элемент head = a; //т.е. список теперь состоит из одного элемента tail = a; } else { tail.next = a; //иначе "старый" последний элемент теперь ссылается на новый tail = a; //а в указатель на последний элемент записываем адрес нового элемента } } void printList() //печать списка { ListElement t = head; //получаем ссылку на первый элемент while (t != null) //пока элемент существуе { System.out.print(t.data + " "); //печатаем его данные t = t.next; //и переключаемся на следующий } } void delEl(E data) //удаление элемента { if(head == null) //если список пуст - return; //ничего не делаем if (head == tail) { //если список состоит из одного элемента head = null; //очищаем указатели начала и конца tail = null; return; //и выходим } if (head.data == data) { //если первый элемент - тот, что нам нужен head = head.next; //переключаем указатель начала на второй элемент return; //и выходим } ListElement t = head; //иначе начинаем искать while (t.next != null) { //пока следующий элемент существует if (t.next.data == data) { //проверяем следующий элемент if(tail == t.next) //если он последний { tail = t; //то переключаем указатель на последний элемент на текущий } t.next = t.next.next; //найденный элемент выкидываем return; //и выходим } t = t.next; //иначе ищем дальше } } }
Изменения минимальны.
Вместо int
пишем E
. И к имени класса добавляем
<E>
Зато теперь можно сделать вот так:
public class Main { public static void main(String[] args) { List ml = new List(); ml.addBack(1.0); ml.addBack(2); ml.addBack("brrr"); ml.addFront(6); ml.printList(); System.out.println(); } }
В выводе будет:
6 1.0 2 brrr
[Java] Проект с пакетами
Предыдущий пример получился страшным и сложным.
Сделаем проще.
1. Создаём обычный проект.
2. Правой кнопкой мыши на папку src - New->Package. Пишем alg
3. Правой кнопкой на alg - New->Java Class. Пишем sort
4. Правой кнопкой мыши на папку src - New->Package. Пишем Hello
5. В файле с классом Hello пишем
import alg.sort;
Всё. Пакет создан и импортирован.
[Java] Библиотеки и пакеты
Библиотека Java — это сборник классов. Если программе нужен какой-то класс, то нужно подключить библиотеку, в которой этот класс находится.
Пакеты — это механизм, который служит как для работы с пространством имен, так и для ограничения видимости. У каждого файла .java есть 4 внутренних части.
Общая форма исходного файла Java:
- одиночный оператор package (необязателен)
- любое количество операторов import (необязательны)
- одиночное объявление открытого (public) класса
- любое количество закрытых (private) классов пакета (необязательны)
Оператор package
Сообщает транслятору, в каком пакете должны определяться содержащиеся в данном файле классы. Пакеты задают набор раздельных пространств имен, в которых хранятся имена классов. Если оператор package не указан, классы попадают в безымянное пространство имен, используемое по умолчанию. Если объявляется класс, принадлежащий определенному пакету, например,
package java.awt.image;
то и исходный код этого класса должен храниться в каталоге java/awt/image
Трансляция классов в пакетах
При попытке поместить класс в пакет, вы сразу натолкнетесь на жесткое требование точного совпадения иерархии каталогов с иерархией пакетов. Нельзя переименовать пакет, не переименовав каталог, в котором хранятся его классы. Эта трудность видна сразу, но есть и менее очевидная проблема.
Оператор import
После оператора package, но до любого определения классов в исходном Java-файле, может присутствовать список операторов import. Общая форма оператора import такова:
import пакет1 [.пакет2].(имякласса|*);
Здесь пакет1 — имя пакета верхнего уровня, пакет2 — это необязательное имя пакета, вложенного в первый пакет и отделенное точкой. И, наконец, после указания пути в иерархии пакетов, указывается либо имя класса, либо метасимвол звездочка. Звездочка означает, что, если Java-транслятору потребуется какой-либо класс, для которого пакет не указан явно, он должен просмотреть все содержимое пакета со звездочкой вместо имени класса.
import java.util.Date import java.io.*;
Замечание: Использование * может существенно увеличить время трансляции программы. На скорость работы и размер программы не влияет.
Если в двух пакетах, подключаемых с помощью формы оператора import со звездочкой, есть классы с одинаковыми именами, однако вы их не используете, транслятор не отреагирует. А вот при попытке использовать такой класс, вы сразу получите сообщение об ошибке, и вам придется переписать операторы import, чтобы явно указать, класс какого пакета вы имеете ввиду.
class MyDate extends Java.util.Date { }
Уровни доступа
В языке Java имеется три уровня доступа, определяемых ключевыми словами: private (закрытый), public (открытый) и protected (защищенный).
private | модификатор отсутствует | private protected | protected | public | |
тот же класс | да | да | да | да | да |
подкласс в том же пакете | нет | да | да | да | да |
независимый класс в том же пакете | нет | да | нет | да | да |
подкласс в другом пакете | нет | нет | да | да | да |
независимый класс в другом пакете | нет | нет | нет | нет | да |
- Элемент, объявленный public, доступен из любого места
- Все, что объявлено private, доступно только внутри класса, и нигде больше
- Если у элемента вообще не указан модификатор уровня доступа, то такой элемент будет виден из подклассов и классов того же пакета. (по умолчанию)
- Чтобы элемент был доступен извне пакета, но только подклассам того класса, которому он принадлежит, нужно объявить такой элемент protected
- Чтобы элемент был доступен только подклассам, причем независимо от того, находятся ли они в данном пакете или нет — используйте комбинацию private protected
Небольшой пример
Создаём новый проект и добавляем в папку src новый Пакет "alg" (New -> Package)
В папке пакета создаем класс sort (New -> Java Class)
В новом классе пишем наши уже знакомые функции сортировки с обязательным модификатором доступа public.
В итоге должно получиться следующее:
package alg; public class sort { public void gnom(int[] mas) { int p = 2; int i = 1; for (; i < mas.length; ) { if (mas[i - 1] <= mas[i]) { p++; i = p; } else { int a = mas[i]; mas[i] = mas[i - 1]; mas[i - 1] = a; i--; if (i == 0) { p++; i = p; } } } } public void gnom(double[] mas) { int p = 2; int i = 1; for (; i < mas.length; ) { if (mas[i - 1] <= mas[i]) { p++; i = p; } else { double a = mas[i]; mas[i] = mas[i - 1]; mas[i - 1] = a; i--; if (i == 0) { p++; i = p; } } } } }
Сохраняем. Создаём еще один проект. Или открываем старый.
Добавляем созданый модуль alg также как описывалось в предыдущей статье
Делаем новый класс и пишем туда первой строчкой:
import alg.sort;
Всё. Мы подключили наш пакет с функциями сортировки!
Дописываем функцию main
В итоге:
import alg.sort; class Hello { public static void main(String args[]) { int masI[] = {5, 5, 9, 8, 0, -5, 9, 10}; double masD[] = {5.9, 5.7, 9.6, 8.9, 0.7, -5.6, 9.9, 10.0}; sort s1 = new sort(); s1.gnom(masI); s1.gnom(masD); }
Java API
Очень полезная ссылка.
Документация по всем стандартным классам языка
http://docs.oracle.com/javase/7/docs/api/index.html
Навигация как всегда на высоте.
Искать либо в индексе по имени функции/класса/пакета (справа вверху Index)
Либо по имени класса (слева All Classes)
[Java] Подключаем чужие исходники в IntelliJ IDEA
По следам статьи
В статье предлагается попробовать себя в роли разработчика Рогалика (Rogue-like) - игрушки, в которых вместо графики используется ASCII символы.
Разберем, как же подключить правильно сторонние библиотеки, чтобы всё работало.
Необходимо скачать две (а не одну, как сказано в статье) библиотеки: jcurses и libjcsi
Для скачивания исходников для libjcsi понадобится SVN клиент (надо будет написать про них немного)
Или можно взять тут: http://axis.bplaced.net/wp-content/uploads/2012/10/libjcsi.zip
Качаем исходники (Source) и распаковываем их куда-нибудь. У меня это C:\JavaLib\jcurses и C:\JavaLib\libjcsi
Создаём новый модуль (или открываем старый) и добавляем туда новый класс Rogalic
.
Заходим в File -> Project Structure
Раздел Module, вкладка Dependencies.
Выбираем Create module from existing sources и жмем "..."
Жмем Next до упора и потом Finish (всё по умолчанию, все окна практически пустые)
Повторяем тоже самое для libjcsi
Теперь добавляем зависимости.
Жмем на модуль Net
и затем справа на "+" -> Module dependency
Теперь выбираем наш родной модуль и повторяем операцию. Только теперь выбираем Net
Закрываем всё. Должно получиться как-то вот так
Теперь пишем в классе Rogalic
следующее:
import java.util.ArrayList; import java.util.Properties; import net.slashie.libjcsi.CSIColor; import net.slashie.libjcsi.CharKey; import net.slashie.libjcsi.ConsoleSystemInterface; import net.slashie.libjcsi.wswing.WSwingConsoleInterface; public class Rogalic { private static Rogalic instance; private static ConsoleSystemInterface csi; private boolean stop; private int x,y; public static void main(String[] args) { Properties text = new Properties(); text.setProperty("fontSize", "15"); text.setProperty("font", "roguelike.ttf"); csi = new WSwingConsoleInterface("RogueLike", text); instance = new Rogalic(); instance.run(); } public void run() { stop = false; x = 0; y = 0; while (!stop) { csi.cls(); csi.print(x,y,'@', CSIColor.WHITE); // отрисовка игрока csi.refresh(); handleKeys(); // обработка клавиатуры } System.exit(0); } private void handleKeys(){ CharKey dir = csi.inkey(); if(dir.isUpArrow()&& (y-1 >= 0)){ y--; } if(dir.isDownArrow() && (y+1 < 25)){ y++; } if(dir.isLeftArrow() && (x-1 >= 0)){ x--; } if(dir.isRightArrow() && (x+1 < 80)){ x++; } if(dir.code == CharKey.Q){ stop = true; } } }
Запускаем!
Если всё сделано правильно, то должно появиться окно с довольной "собакой (@) - главным героем всех Рогаликов. Ну, почти всех :)
Им можно шаволить курсорными стрелками.
[Java] Консольный ввод/вывод
Любимое занятие - написание консольных диалоговых приложений :)
Во время работы метода System.in.read возможно возникновение исключений. Поэтому заключаем фрагмент кода, выполняющий эту функцию, в блок try-catch.
import java.util.StringTokenizer; //добавляем класс для обработки строк public class ioTest { public static void main(String args[]) { byte bKbd[] = new byte[256]; // буфер String szStr = ""; // итоговая строка StringTokenizer st; // преобразователь System.out.print("Print here: "); try { // Метод read считывает символы с клавиатуры и записывает // их в массив байт с именем bKbd. Этот метод возвращает // управление, когда пользователь закончил ввод и нажал // клавишу <Enter>. При этом в переменную iCnt записывается // количество прочитанных символов. int iCnt = System.in.read(bKbd); // Строка String содержит 16-разрядные символы Unicode. // Чтобы преобразовать массив байт в строку Unicode, мы // задаем значение старшего байта во втором параметре // конструктора, равное нулю. szStr = new String(bKbd, 0, iCnt); // Удаление символов возврата каретки и перевода строки // выполняется при помощи класса StringTokenizer, предназначенного // для разбора текстовых строк. Создавая объект этого класса, // мы передаем конструктору через второй параметр список // символов-разделителей st = new StringTokenizer(szStr, "\r\n"); // Метод nextElement возвращает первый элемент строки до разделителя, // то есть в нашем случае всю строку до символов возврата каретки и // перевода строки. szStr = new String((String)st.nextElement()); } catch(Exception ex) { System.out.println(ex.toString()); } //чисто для красоты - разделяем строку на слова String v[] = szStr.split(" "); for(int j = 0; j < v.length; j++) { System.out.println(j + "-е слово: " + v[j]); } } }
Как пользоваться:
Запускаем, внизу в консоли тыкаем в белое поле и набираем строку. Ввод заканчиваем нажатием клавиши
Как-то вот так:
Print here: Это странная консольная программа! 0-е слово: Это 1-е слово: странная 2-е слово: консольная 3-е слово: программа! Process finished with exit code 0