Примитивни типове и променливи.
Основна градивна единица на езиците за програмиране са променливите. Известни от математиката, а и от С, променливите служат за временно съхранение на данни в дадена програма. В частност – в Java променливите се делят на два типа – примитивни и референтни. Едните се различават от другите главно по това къде стоят в паметта, както и по сложността и многозначителността си. Примитивните типове данни в езика Java не се различават съществено от тези в езика С. Както е известно всички примитивни типове данни се характеризират с име, размер и стойност по подразбиране. Езикът разполага със следните типове:
- byte, short, int, long – целочислени типове;
- float, double – реални типове с плаваща запетая;
- boolean – булев (логически) тип;
- char – символен тип;
- Object – обектен тип ;
- String – символни низове.
Последните два типа са референтни. Основната разлика между примитивните и референтни типове данни е начина по който са организирани в паметта. Примитивните типове данни се съхраняват в стека. Важно е да се знае, че те съществуват само в областта им на видимост . За по –голяма яснота относно съхранението на данни, ще дадем следния пример.
ПРИМЕР:
byte x= 68; int i = 123456; char ch = ‘W'; boolean result = false; Object obj = 172; String str = “Java is easy to learn";
От дадения пример много ясно се вижда разликата между двата типа променливи. При референтния тип в стека се съхранява адрес, в хийпа на който се намира даденият обект. Този адрес се нарича референция, анологично на указателите в С.
Обектният е най-специалният тип- той се явява родител на всички останали, но това ще бъде изяснено на по-късен етап. Важно е да се знае, че символният тип е референтен тип, за да се ползва като такъв, а не като примитив.
В долната таблица са дадени стандартните обхвати на примитивните типове в Java:
Както се вижда от таблицата, всички примитивни типове се „обгръщат“ от по един съответен референтен. Тоест за един тип данни, Java разполага както с примитив(прост тип), така и с референтен нему еквивалент.
Важни моменти:
Винаги, когато може да се използва тип, заемащ по-малко памет, е по-добре.
Внимание за числа с плаваща запетая и загуба на точност.
Символният тип представлява поредица от 16 битови Unicode символи и е алтернатива на познатия от C char[]
Оператори и изрази:
Операторите в Java са следните:
1. Унарни – изискват само един операнд:
a) ++ – инкрементиране с 1;
b) – – декрементиране с 1;
c) + – положително число, например +3;
d) – – отрицателно число, например -3;
e) ~ – побитово инвертиране, например 00001111 става 11110000;
f) ! – логическо отрицание;
g) (<тип>) – преобразуване на тип данни, например ако x е от тип int, то можем да направим double d = (double)x.
2. Аритметични:
a) + – събиране (използва се и за конкатенация на обекти от тип String);
b) – – изваждане;
c) * – умножение;
d) / – деление;
e) % – остатък от деление при целочислените типове.
3. Сравнение:
a) < – по-малко;
b) <= – по-малко или равно;
c) > – по-голямо;
d) >= – по-голямо или равно;
e) == – равно;
f) != – не равно.
4. Логически:
a) && – логическо „и“;
b) || – логическо „или“.
5. Побитови:
a) & – побитово „и“;
b) | – побитово „или“;
c) ^ – побитово „изключващо или“;
d) << – изместване вляво;
e) >> – изместване вдясно;
f) >>> – изместване вдясно без знак (нов оператор, който не присъства в C/C++, но на който няма да се спираме).
Цикли в Java:
Както във всички езици, циклите се използват за повторение на съвкупност от операции.
for- цикъл:
Пример:
for(int i=0; i < 10; i++) { System.out.println("i is: " + i); }
while и do while
Разлика: при while първо се проверява условието, после се изпълнява тялото (цикъл с предусловие). При do while се изпълнява тялото и след това се проверява дали условието е изпълнено (цикъл с постусловие).
Пример:
int counter = 0; while(counter < 10) { System.out.println("counter: " + counter); counter++; }
for each – цикъл:
С този цикъл Java се различава от С(в С го няма). Нарича се още съкратен for. Появява се с Java 5. Пример:
String[] strings = {"one", "two", "three" }; for(String aString : strings) { System.out.println(aString); }
Обобщен синтаксис:
for(Type t : collection){ //do something with t; }
Внимание с команди break и continue.
Масиви в Java:
Дефиниране:
Масивът е най-традиционната структура данни. Масивът е референтен тип. Следователно се съхранява не в стека, а в heap-а. Синтактично, декларирането му както в С е напълно възможно:
int arr1[]; //останал и наследен от С стил на дефиниране.
В допълнение, масив в Java по стандарт се декларира така :
int[] arr2; //по Oracle стандарт на дефиниране.
Инициализиране:
Инициализацията представлява запълването на елементите на масива със стойности.
int[] arr2; представлява декларация на масив. Когато се декларира променлива от тип масив(arr2), ние декларираме просто променлива(референция), която сочи към самия масив. Така че декларацията не създава реален масив. Следният код създава масив от 10 елемента, които са от тип int:
arr2= new int[10];
Ако веднъж е създаден масив, то размерът му не може да бъде променян. В някои езици това е възможно. Java решава този проблем с въвеждането на динамични масиви(ще бъде разгледано в следващо упражнение.).
Освен масив от примитивни типове данни, можем да създаваме и масиви от референтни такива:
String[] stringArray = new String[10];
Елементите на така създадените масиви се инициализират със съответните стойности по подразбиране на типовете, които съхраняват. Съответно за int e 0, а за String e null. Всички референтни типове, които са декларирани, но не са инициализирани все още имат стойности null, което означава че референциите им не сочат на никъде (празни).
Нека иницилизираме елементите на масива с различни от стойностите по подразбиране. Това може да стане по следния начин:
int[] ints2 = new int[]{ 1,2,3,4,5,6,7,8,9,10 };
Или съответно:
String[] strings = {"one", "two", "three"};
Стойностите, с които искаме да инициализираме елементите на масива се подават в {…..}.
В последната версия на Java можем да пропуснем new int[], а просто да напишем:
int[] ints2 = { 1,2,3,4,5,6,7,8,9,10 };
Частта след знака за равенство се нарича array literal.
Достъп до елементите на масив:
Например за да достъпим 6-тия елемент на масива arr2 ще използваме:
arr[6] = 0; // в него записваме стойност 0; int sixthInt = arr[6] ; //в променлива sixthInt записахме стойността на 6-тия елемент.
Можете да използвате елементите на масив точно като обикновена променлива – да и прочетете стойността, да и присвоите нова стойност, да я накарате да участва в изрази или пък да я придадете като аргумент на функция. Както в С, трябва да се внимава с особеностите на индексната аритметика – елементите започват винаги от 0.
Различни Java – методи за работа с масиви:
Array Length – дължина на масив. Можете да вземете дължината на масива като използвате следния код:
int[] intArr = new int[10]; int arrayLength = intArr.length;
Обхождане на масив:
Масив можете да обходите по няколко начина в Java. Традиционният начин е с използване на цикъл:
String[] stringArray = new String[10]; for(int i=0; i < stringArray.length; i++) { stringArray[i] = "String no " + i; } for(int i=0; i < stringArray.length; i++) { System.out.println( stringArray[i] ); }
Какво прави първият и какво прави вторият цикъл?
Многомерни масиви
Подобно на други езици, многомерните масиви са такива масиви, при които всеки елемент се достъпва чрез повече от 1 индекс. Размерност(дименсия) към нормален масив се добавя като се добави още една двойка скоби []. Например:
int[][] intArray = new int[10][20];
За да достъпим елементите на този масив използваме същият синтаксис както по-горе, само че са ни необходими 2 индекса :
intArray[0][2] = 129;
Стандартен вход и стандартен изход:
Стандартен изход:
Стандартният изход представлява конзолата, а стандартен вход – клавиатуата.
За да иползвате стандартния изход (да принтирате на конзолата) се иползва следната конструкция:
System.out.print(“Some text.”); // принтира: Some text. System.out.println(“Some text.”); // принтира: Some text. и минава на нов ред.
Символните низове, които искаме да принтираме се конкатенират с „+“.
System.out.println(“text 1 ” +“text 2 ”);
Конкетенация на различни типове данни.
int x=5; System.out.println((“x = ” + x);
Една особеност, която трябва да се отбележи е разликата между операторa събиране и конкaтениране.
Пример:
String string1="I am"; String string2="years old" int a,b; a=2; b=5; System.out.println(string1+" "+a+b+" "+string2); // I am 25 years old System.out.println(string1+" "+(a+b)+" "+string2); // I am 7 years old
Можете да иползвате и алтернативата на printf() от C – System.out.format(). Например:
System.out.format("%s", "Hello World\n");
println(), print(), format() и в Java се наричат методи, за разлика от С, където това са функции.
Стандартен вход:
Подобно на стандартния изход стандартния вход дефинира метод – read() в System.in.
Методът чете байт по байт и връща int. Нека онагледим това с пример:
Пример:
package example; import java.io.IOException; public class myFirstProgram { public static void main(String[] args) throws IOException { int input; do{ input=System.in.read(); System.out.print((char)input); }while(input!='\n'); } }
От създаването си Java претърпява доста промени. Една от тези промени се появява в Java 5, където се имплементира класа Scanner с няколко мощни метода в него.
За да достъпите стандартния вход (да четете от клавиатурата) се използва следният синтаксис
Scanner scanner = new Scanner(System.in); String input = scanner.next(); // чете стринг до празен интервал . String input = scanner.nextLine(); // чете стринг до нов ред . int input = scanner.nextInt(); // чете въведеното число от клавиатурата и го записва в променлива. double input = scanner.nextDouble(); // чете реални числа.
За повече информация – http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
Структура на Java програма:
Обикновеният Java проект представлява отделна директория, в която се съхраняват всички Java source файлове. Обикновено, логически обособените сорс файлове, които по-късно ще наречем класове, се разпределят в отделни пакети(package), като съответно всеки пакет формира отделна директория.
След компилация, компилаторът произвежда .class – файлове за всеки .java файл. .class –файлът представлява компилирана версия на .java –файла, или казано по друг начин – .class – файлът съдържа byte-кода на .java-файла. Както става ясно след като се компилира, всеки java клас се свежда до междинен код – байт код, а не до изпълним код!. Този байт код по-късно се превежда на съответната платформа до машинен (native) код и се изпълнява от т.нар java виртуална машина. По този начин създателите на езика – Sun, постигат идеята за платформена независимост. Един и същи байт код би могъл да се изпълни на напълно различни конфигурации(пларформи) по абсолютно идентичен начин, стига конкретната платформа да разполага с инсталирна виртуална машина.
Различни са средите за писане на Java код (IDE)– най разпространени са Eclipse, Net Beans, Dr Java, InteliJ и др. Стандартната java програма съдържа поне един клас, в който е деклариран един специален метод, наречен main. Както подсказва името му, той ще бъде отправна точка на елементарната java програма.
Всичко това би трябвало да изглежда така в InteliJ средата:
По стандарт main методът е публичен, статичен, не връща стойност и приема аргументи String[] args.
Този масив от String-ове представлява входен параметър. Лесно може да бъдат подадени през команден ред или по време на стартиране чрез опция Run Configuration… Подават се, разбира се, в случай, че програмата има нужда от външни аргументи. Повече за останалите атрибути на main метода ще разберем в следващите упражнения.
Как се създава проект?
File-> New Project ..-> Java Project {задавате име на проекта} -> Next..Next
Как се създава класът MyJavaApp?
File -> New Class {задавате име} -> Next…Next..
Как се стартира приложението?
Run-> Run as Java Application
Задачи за изпълнение:
- Създайте проект myFirstProject. Създайте клас myFirstClass , в който има main() метод. В main() метода да се прочетат име, години и рожденна дата на даден човек, въведени от клавиатурата, чрез използване на класа Scanner. Данните да се отпечатат на стандартния изход.
- Напишете програма, която по зададени две страни на правоъгълник изчислява и отпечатва неговото лице. Дължините на страните се въвеждат от стандартния вход.
- Напишете програма която получава от стандартния вход 5 низа, разделени с интервал и записва низовете в масив. Отпечатва низовете на екрана.
Явор Томов, Даниел Джолев
String strings = {“one”, “two”, “three” };
for(String aString : strings) {
System.out.println(aString);
}
Има грешка при инициализацията на масива от стрингове
Нямаше скобите, благодаря!
” arr[6] = 0; // в него записваме стойност 0;
int sixthInt = arr[6] ; //в променлива sixthInt записахме стойността на 6-тия елемент.”
Така всъщност не достъпваме ли 7мия елемент?
Достъпваме стойността на 6-ти елемент също е правилно – ако ги броим от 0 ще имаме нулев елемент, първи елемент, втори елемент и тн. Ако ги броим от 1, то ще стане 7-ми елемент, но само за нас. Компилаторът ги брои от 0, независимо от нашите предпочитания и това кое ни е по-удобно или ни се струва по-логично. 🙂