Книга е още в много ранна фаза на написване



страница27/73
Дата25.07.2016
Размер13.53 Mb.
#6732
1   ...   23   24   25   26   27   28   29   30   ...   73

Инициализация на масиви


Инициализирането на масиви в C често е съпроводено с грешки и е досадно. C++ използва инициализация на агрегати за много по-бързо.6 Java няма “агре­га­ти” като C++, понеже всичко е обекти в Java. Има масиви и те се инициа­ли­зи­рат чрез "инициализация на масиви".

Масивът е просто последователнот от или примитиви или обекти, всички от един тип и опаковани заедно под едно име. Масивите се декларират и използват с оператор от квадратни скоби наречен индексиращ оператор [ ]. За да се дефи­ни­ра масив просто слагате след типа празни квадратни скоби:

int[] a1;

Може да ги сложите след името със същия резултат:

int a1[];

Това отговаря на очакванията на C и C++ програмистите. Първия пример ка­то­че­ли има по-смислен синтаксис, понеже говори за “масив от int.” Този стил ще се използва в тази книга.

Компилаторът не дава да му казвате колко голям е масивът. Това ни връща пак към въпроса за “манипулаторите.” Всичко което до тук имате е манипулатор към масив и не е алокирана памет за масива. За да се вземе памет за масива тряб­ва да напишете израз за даване на начални стойности. За масивите ини­циа­ли­зацията може да се появи навсякъде в програмата, но също може да из­полз­ва­те специален синтаксис в точката, където се декларира масивът. Тази спе­циал­на инициализация е множество начални стойности, разделени със запетаи и огра­дени с големи скоби. Алокирането на памет (еквивалентът на използване на new) е обект на грижите на компилатора в този случай. Например:

int[] a1 = { 1, 2, 3, 4, 5 };

Защо въобще ще дефинираме манипулатор на масив без масива?

int[] a2;

Ами възможно е да се присвояват един масив на друг в Java, така че да се на­пи­ше:

a2 = a1;


Фактически се копира манипулатор, както е демонстрирано тук:

//: c04:Arrays.java

// Arrays of primitives.
public class Arrays {

public static void main(String[] args) {

int[] a1 = { 1, 2, 3, 4, 5 };

int[] a2;

a2 = a1;

for(int i = 0; i < a2.length; i++)

a2[i]++;

for(int i = 0; i < a1.length; i++)

prt("a1[" + i + "] = " + a1[i]);

}

static void prt(String s) {



System.out.println(s);

}

} ///:~



Може да видите че a1 му се дава начална стойност докато на a2 не се дава; a2 му се приравнява по-късно – в този случай към друг масив.

Има нещо ново тука: всички масиви имат вграден член (без значение дали са ма­сиви от примитиви или обекти) който може да четете – но не да променяте – за да видите колко елемента има масивът. Този член е length. Тъй като масивите в Java, подобно на C и C++, започват от елемент нула, най-големият номер на еле­мент който може да стои като индекс е length - 1. Ако излезете от масива C и C++ тихичко приемат това позволявайки ви да шарите из цялата памет, което е из­точник на много безславни бъгове. Java обаче ви предпазва от такива неща чрез грешка по време на изпълнение (изключение, тема на глава 9) ако при­стъ­пи­те извън масива. Разбира се, проверките при всеки достъп до масива струват вре­ме и код и не може да се изключат, което значи че достъпът до масивите мо­же да стане източник на неефективност за вашата програма, ако става в кри­ти­чен момент. За сигурност в Internet и продуктивност на програмиста проек­тан­ти­те на Java са счели че това си струва цената.

Ако не знаете колко елемента ще има масивът докато пишете програмата? Про­сто използвате new за създаване на елементите в масива. Тук new работи въ­преки че се създава масив от примитиви (new не би създал примитив извън ма­сив):

//: c04:ArrayNew.java

// Creating arrays with new.

import java.util.*;


public class ArrayNew {

static Random rand = new Random();

static int pRand(int mod) {

return Math.abs(rand.nextInt()) % mod + 1;

}

public static void main(String[] args) {



int[] a;

a = new int[pRand(20)];

prt("length of a = " + a.length);

for(int i = 0; i < a.length; i++)

prt("a[" + i + "] = " + a[i]);

}

static void prt(String s) {



System.out.println(s);

}

} ///:~



Понеже дължината на масива е случайно избрана (с използване на pRand( ) ме­то­да срещан и преди), ясно е че наистина създаването на масива става по вре­ме на изпълнение. В добавка се вижда от извежданото от програмата, че еле­мен­тите се инициализират с ”празни” стойности. (За числата това е нула, за char е null, за boolean е false.)

Разбира се, масивът може да се декларира и инициализира на едно място:

int[] a = new int[pRand(20)];

Ако имате работа с масив от непримитивни обекти, винаги трябва да из­полз­ва­те new. Тук въпросът с манипулаторите се проявява отново понеже това, което фак­тически се създава е масив от манипулатори. Да вземем об­хва­ща­щия/заместващия клас Integer, който е клас и не е примитив:

//: c04:ArrayClassObj.java

// Creating an array of non-primitive objects.

import java.util.*;
public class ArrayClassObj {

static Random rand = new Random();

static int pRand(int mod) {

return Math.abs(rand.nextInt()) % mod + 1;

}

public static void main(String[] args) {



Integer[] a = new Integer[pRand(20)];

prt("length of a = " + a.length);

for(int i = 0; i < a.length; i++) {

a[i] = new Integer(pRand(500));

prt("a[" + i + "] = " + a[i]);

}

}



static void prt(String s) {

System.out.println(s);

}

} ///:~


Тука даже след като е извикан new да създаде масива:

Integer[] a = new Integer[pRand(20)];

Това е само масив от манипулатори и докато не се инициализира самия ма­ни­пу­ла­тор чрез създаване на нов Integer обект инициализацията не е за­вър­ше­на:

a[i] = new Integer(pRand(500));

Ако забравите да създадете обекта ще получите грешка по време на из­пъл­не­ние, когато се опитате да четете празното място на масива (по-точно не­съ­ще­ству­ващото място на масива, понеже манипулаторът му ще остане инициа­ли­зи­ран с "нула", което за манипулатори е "никъде" - бел.прев.).

Хвърлете поглед на формирането на String обект вътре в операторите за из­веж­да­не. Може да се види че манипулаторът на Integer обект автоматично се пре­връ­ща в String представящ стойността в обекта.

Възможно е също да се инициализират масиви от обекти чрез затворен в го­ле­ми скоби списък. Има две форми, първата от които е единствената позволена в Java 1.0. Втората (еквивалентна) е позволена от Java 1.1 нататък:

//: c04:ArrayInit.java

// Array initialization
public class ArrayInit {

public static void main(String[] args) {

Integer[] a = {

new Integer(1),

new Integer(2),

new Integer(3),

};
// Java 1.1 only:

Integer[] b = new Integer[] {

new Integer(1),

new Integer(2),

new Integer(3),

};

}



} ///:~

Това е полезно понякога, но е по-ограничено понеже дължината на масива се опре­деля по време на компилация. Завършващата запетая в списъка на ини­циа­ли­заторите е незадължителна. (Тази черта помага за поддръжката на дълги списъци.)

Втората форма, въведена в Java 1.1, дава удобен начин да се пишат и викат ме­то­ди, които произвеждат същия ефект като променливите аргументни списъци (известни още като “varargs”) в C. Това включва неопределен брой аргументи и с неизвестен тип. Тъй като всички класове сигурно са наследници на общ клас Object, може да създадете метод който приема масив от Object и да го викате та­ка:

//: c04:VarArgs.java

// Using the Java 1.1 array syntax to create

// variable argument lists


class A { int i; }
public class VarArgs {

static void f(Object[] x) {

for(int i = 0; i < x.length; i++)

System.out.println(x[i]);

}

public static void main(String[] args) {



f(new Object[] {

new Integer(47), new VarArgs(),

new Float(3.14), new Double(11.11) });

f(new Object[] {"one", "two", "three" });

f(new Object[] {new A(), new A(), new A()});

}

} ///:~



На този етап няма много какво да правите с тези неизвестни обекти и тази про­гра­ма използва автоматична String конверсия за да направи нещо полезно с Object. В глава 11 (run-time type identification или RTTI) ще научите как да на­ми­ра­те точния тип по време на изпълнение, за да може да правите по-интересни не­ща.

Многомерни масиви


Java позволява лесно да се създават многомерни масиви:

//: c04:MultiDimArray.java

// Creating multidimensional arrays.

import java.util.*;


public class MultiDimArray {

static Random rand = new Random();

static int pRand(int mod) {

return Math.abs(rand.nextInt()) % mod + 1;

}

public static void main(String[] args) {



int[][] a1 = {

{ 1, 2, 3, },

{ 4, 5, 6, },

};

for(int i = 0; i < a1.length; i++)



for(int j = 0; j < a1[i].length; j++)

prt("a1[" + i + "][" + j +

"] = " + a1[i][j]);

// 3-D array with fixed length:

int[][][] a2 = new int[2][2][4];

for(int i = 0; i < a2.length; i++)

for(int j = 0; j < a2[i].length; j++)

for(int k = 0; k < a2[i][j].length;

k++)

prt("a2[" + i + "][" +



j + "][" + k +

"] = " + a2[i][j][k]);

// 3-D array with varied-length vectors:

int[][][] a3 = new int[pRand(7)][][];

for(int i = 0; i < a3.length; i++) {

a3[i] = new int[pRand(5)][];

for(int j = 0; j < a3[i].length; j++)

a3[i][j] = new int[pRand(5)];

}

for(int i = 0; i < a3.length; i++)



for(int j = 0; j < a3[i].length; j++)

for(int k = 0; k < a3[i][j].length;

k++)

prt("a3[" + i + "][" +



j + "][" + k +

"] = " + a3[i][j][k]);

// Array of non-primitive objects:

Integer[][] a4 = {

{ new Integer(1), new Integer(2)},

{ new Integer(3), new Integer(4)},

{ new Integer(5), new Integer(6)},

};

for(int i = 0; i < a4.length; i++)



for(int j = 0; j < a4[i].length; j++)

prt("a4[" + i + "][" + j +

"] = " + a4[i][j]);

Integer[][] a5;

a5 = new Integer[3][];

for(int i = 0; i < a5.length; i++) {

a5[i] = new Integer[3];

for(int j = 0; j < a5[i].length; j++)

a5[i][j] = new Integer(i*j);

}

for(int i = 0; i < a5.length; i++)



for(int j = 0; j < a5[i].length; j++)

prt("a5[" + i + "][" + j +

"] = " + a5[i][j]);

}

static void prt(String s) {



System.out.println(s);

}

} ///:~



Кодът за извеждането използва length и не зависи от фиксирана дължина на ма­си­вите.

Първият пример показва многомерен масив от примитиви. Отделяме всеки век­тор с големи скоби:

int[][] a1 = {

{ 1, 2, 3, },

{ 4, 5, 6, },

};

Всяко множество в големи скоби ви придвижва в следващото ниво на масива.



Следващият пример показва тримерен масив, алокиран с new. Тук челият масив се алокира наведнъж:

int[][][] a2 = new int[2][2][4];

Но в третия пример се вижда че всеки вектор в масива, който съставя ма­три­ца­та, може да бъде с произволна дължина:

int[][][] a3 = new int[pRand(7)][][];

for(int i = 0; i < a3.length; i++) {

a3[i] = new int[pRand(5)][];

for(int j = 0; j < a3[i].length; j++)

a3[i][j] = new int[pRand(5)];

}

Първият new създава масив със първи елемент-случайна дължина и другите нео­пределени. Вторият new вътре във for цикъла запълва елементите но оставя тре­тият индекс неопределен до третия new.



Ще видите от римера, че масивите се инициализират с нула, ако не ги инициализирате вие.

За масивите от не-примитиви е същото, както е показано в четвъртия пример, де­монстриращ възможността да се съберат много new изрази с големи скоби:

Integer[][] a4 = {

{ new Integer(1), new Integer(2)},

{ new Integer(3), new Integer(4)},

{ new Integer(5), new Integer(6)},

};

Петият пример показва как масив от непримитиви може да бъде построен пар­че по парче:



Integer[][] a5;

a5 = new Integer[3][];

for(int i = 0; i < a5.length; i++) {

a5[i] = new Integer[3];

for(int j = 0; j < a5[i].length; j++)

a5[i][j] = new Integer(i*j);

}

i*j е само за да сложи интересна стойност в Integer.




Сподели с приятели:
1   ...   23   24   25   26   27   28   29   30   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница