JAVA/기본 개념
[JAVA] 배열
soyeonisgood
2022. 7. 16. 13:44
배열의 선언과 초기화
- - C언어와 다르게 JAVA는 포인터 접근 불가.
- - 배열은 선언과 메모리 할당 후 사용 가능. 두 개 동시에 해도 됨.
- - 배열은 선언만 하면 안됨. 꼭 크기를 정해주거나, 초기화해주어야함.
- ex) int[] a = new int[] {} ; //오류
- - num[5] 초기화하면 오류 발생. 당연함. num[0]~num[4] 까지밖에 없음. (0~'x-1' 까지 사용)
- - 정수형 배열은 초기화 하지 않아도 메모리 할당 시 0으로 초기화됨.
- - 배열은 크기를 변경할 수 없음. 크기 변경되면 이전 배열은 위치를 참조할 수 없어서 garbage collector의 대상이 되어 새로운 배열을 만듬.
- - 선언과 동시에 초기화 가능. 초기화 하는 경우 초기값 개수가 배열 요소의 수가 됨.
int[] num; // 1) 배열 선언
num = new int[5]; // 2) 메모리 할당 (5개 저장할 수 있는 정수형 배열)
// num: 배열의 이름. 배열 첫번째 위치의 참조값(주소) 가짐.
int[] num = new int[5]; // 배열 선언과 메모리 할당
// 배열 요소 접근
// 첨자는 0 ~ "요소수-1" 까지 사용 가능
num[0]=1; num[1]=3; num[2]=5; num[3]=7; num[4]=9;
// 첨자가 "요소수-1"를 벗어나면 런타임 오류 발생
//num[5]=11; // ArrayIndexOutOfBoundsException
// 배열 요소의 수 : length 필드로 요소수를 알 수 있다.
System.out.println("배열 갯수: "+num.length);
for(int i=0; i<num.length; i++) {
s+=num[i];
}
int[] a = new int[3];
a[0]=10; a[1]=20; a[2]=30;
System.out.println("배열의 크기를 3개로 선언하고 값을 할당 후.");
for(int i=0; i<a.length; i++) {
System.out.print(a[i]+ " "); //10 20 30
}
System.out.println();
//garbage collector: 메모리 회수의 대상
a=new int[5];
a[3]=40; a[4]=50;
System.out.println("\n배열의 크기 5로 변경 후.");
for(int i=0;i<a.length;i++) {
System.out.print(a[i]+ " "); // 0 0 0 40 50
}
//두 래퍼런스 변수가 하나의 배열 공유
int [] a = new int[3];
a[0]=10; a[1]=20; a[2]=30;
int[] b = a;
b[0]+=5;
b[1]+=100;
System.out.println("\nb 배열...");
for(int n:b) {
System.out.print(n+" "); //15 120 30
// 배열 선언과 동시에 초기화
// 선언과 동시에 초기화하는 경우 아래처럼 new int[] 생략 가능.
int[] a = new int[] {2, 4, 6, 8, 10};
// 선언과 초기화 따로따로 한다면, new int[] 생략 불가.
int [] b;
// b = {1,3,5,7,9}; //컴파일 오류.
b = new int[] {1,3,5,7,9};
배열 - 향상된 for문
- for( 자료형 변수 : 배열명 ) {
- // 실행문
- }
int[] score = new int[5];
score[0] = 100; score[1] = 90; score[2] = 80; score[3] = 90;
score[4] = 90;
int tot=0, ave;
for(int n : score) {
tot += n;
}
배열을 이용한 난수 출력
- Math.random(): 0<=Math.random()<1 이므로, 1~100까지 난수 출력은 *100 후 +1.
- 복원 추출
- 중복 제거를 위해 이중for문 사용하여 i--;
/*
//복원 추출
int n;
for(int i=0; i<10; i++) {
n= (int)(Math.random()*100)+1;
System.out.print(n+" ");
}
System.out.println();
*/
// 중복 제거
int[] n = new int[10];
for(int i=0; i<10; i++) {
n[i] = (int)(Math.random()*100)+1;
for(int j=0; j<i; j++) {
if(n[i]==n[j]) {
i--;
break; //생략해도 문제는 없지만, 생략하면 불필요한 비교를 하게 됨.
}
}
}
1~10까지의 난수 100개 발생하여 한줄에 10개씩 출력하고, 횟수 카운트
int[] count = new int[10];
int n;
for(int i=0; i<100; i++) {
n = (int)(Math.random()*10)+1;
count[n-1]++;
System.out.printf("%3d", n);
if((i+1)%10==0) {
System.out.println();
}
}
System.out.println("\n숫자별 발생 횟수: ");
for(int i=0; i<count.length; i++) {
System.out.println((i+1)+" : "+count[i]);
}
로또 구매 프로그램
- 입력 받은 수 만큼 로또 구매
- 한 개가 끝나면 중복 초기화 후 다음 진행
- 만약 로또 번호를 정렬하고 싶다면, Arrays.sort(num); 추가. 정렬 포스팅 참고.
int[] num = new int[6];
int buy;
Scanner sc = new Scanner(System.in);
do {
System.out.print("구매 개수 [1-5] ? ");
buy = sc.nextInt();
}while(buy<1 || buy>5);
for(int i=0; i<buy; i++) { //i=0,j=0
for(int j=0; j<6; j++) {
num[j] = (int) (Math.random()*45)+1;
for(int k = 0; k<j; k++) {
if(num[k]==num[j]) {
j--;
break;
}
}
}
//Arrays.sort(num); //정렬
System.out.print((i+1)+"번째: ");
for(int n : num) {
System.out.printf("%5d", n);
}
System.out.println();
}
- Arrays의 sort는 바로 내림차순 정렬할 수 없음. Integer로 변환해서 정렬해야함.
int[] num = new int[10];
for(int i=0; i<num.length; i++) {
num[i] = (int)(Math.random()*100)+1;
}
System.out.print("발생된 난수 : ");
for(int n:num) {
System.out.print(n+" ");
}
System.out.println();
//오름차순 정렬
Arrays.sort(num);
System.out.print("오름차순 정렬 후 난수 : ");
for(int n:num) {
System.out.print(n+" ");
}
System.out.println();
// int를 Integer로 변환
Integer[] aa = Arrays.stream(num).boxed().toArray(Integer[]::new);
Arrays.sort(aa, Comparator.reverseOrder());
for(Integer n : aa) {
System.out.print(n+" ");
}
년, 월을 입력 받아 달력 출력
- 칸 수가 맞지 않을 수 있음. 요일칸은 조정이 힘들다.
Scanner sc = new Scanner(System.in);
int y, m, tot, w;
int[] days = new int[] {31, 28, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31};
do {
System.out.print("년도 ? ");
y = sc.nextInt();
}while(y<1);
do {
System.out.print("월 ? ");
m = sc.nextInt();
}while(m<1 || m>12);
// 입력 받은 년도의 2월 마지막 날짜
days[1] = y%4==0&&y%100!=0||y%400==0? 29 : 28;
//1.1.1 ~ y-1년 12월 31일까지 날 수
tot = (y-1)*365 + (y-1)/4 - (y-1)/100 + (y-1)/400;
// y년 m-1월 까지 날 수
for(int i=0; i<m-1; i++) {
tot += days[i];
}
// y냔 m월 1일까지 날 수
tot++;
w = tot % 7;
System.out.printf("\n\t%d년 %d월\n", y, m);
System.out.println(" 일 월 화 수 목 금 토");
System.out.println("----------------------------");
//1일 앞부분 공백처리
for(int i=0;i<w;i++) {
System.out.print(" ");
}
//1일부터 마지막날짜까지 출력하기
for(int i=1; i<days[m-1]; i++) {
System.out.printf("%4d", i);
if(++w%7 ==0) {
System.out.println();
}
}
if(w%7!=0) {
System.out.println();
}
System.out.println("----------------------------");
sc.close();
- 출력 결과
2차원 배열
- 자바는 2차원 배열이 존재하지 않고, 배열의 배열이 존재한다.
- 배열이 다른 배열의 레퍼런스를 참조하는 형태이다.
가변 배열
- 2차원배열도 가변배열로 초기화 가능
- 2차원배열 출력은 향상된 for문으로 잘 안쓴다.
int[][] a = new int[][] {{10,20,30}, {40,50,60}, {70,80,90}};
int[][] b = new int[][] {{1,2,3,4}, {5,6}, {7,8,9,10,11}};
System.out.println("a배열 행 수: "+a.length); // 3
System.out.println("a[1] 열 수: "+a[1].length); // 3
System.out.println("b배열 행 수: "+b.length); // 3
System.out.println("b[1] 열 수: "+b[1].length); // 2
System.out.println("a[1][2]: " + a[1][2]); //60
//System.out.println("b[1][2]: " + b[1][2]); // 런타임오류
// 2차원배열 향상된 for문
for(int[] rows :a) {
for(int n: rows) {
System.out.printf("%5d", n);
}
System.out.println();
}
5행 5열의 배열 ㄹ문자 형태로 출력
int[][] a = new int[5][5];
int n=0;
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
n++;
if(i%2==1) {
a[i][4-j] = n;
} else {
a[i][j] = n;
}
}
}
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
System.out.printf("%5d", a[i][j]);
}
System.out.println();
}
}
- 출력 결과
E J O T Y
D I N S X
C H M R W
B G L Q V
A F K P U
4행 4열에, 중복되지 않는 무작위 알파벳 출력
- label 사용해야함.
char [][]c = new char[4][4];
for(int i=0; i<4; i++) {
for(int j=0; j<4; j++) {
c[i][j] = (char)((Math.random()*26)+65);
gogo:
for(int a=0;a<=i;a++) {
for(int b=0;b<4;b++) {
if(a==i && j<=b) {
break gogo;
}
//중복문자 검사
if(c[i][j]==c[a][b]) {
j--;
break gogo;
}
}
}
}
}
for(int i=0; i<4; i++) {
for(int j=0; j<4; j++) {
System.out.printf("%3c", c[i][j]);
}
System.out.println();
}
}
- 출력 결과
H R M C
P Y B Q
O W N E
J G A S
배열의 값 복제 arraycopy()
- arraycopy ( 원본배열, 원본시작위치, 복사할배열, 복사시킬위치, 복사갯수)
int[] a = new int[] { 10, 20, 30 };
int[] b;
b = a; // a와 b는 같은 배열. 주소 공유.
b[1]=2000;
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
System.out.println(a==b); //동일한 주소
int[] a = new int[] { 10, 20, 30 };
int[] b = new int[a.length];
// 배열의 내용 다른 배열에 복사
// 원본배열, 원본시작위치, 복사할배열, 복사시킬위치, 복사갯수
System.arraycopy(a, 0, b, 0, a.length);
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
System.out.println(a==b); // false. 다른 주소
String[] s1 = new String[] {"java", "oracle", "html"};
String[] s2 = new String[6];
// 숫자배열은 0으로 초기화
// 객체는 null로 초기화. String은 클래스
System.arraycopy(s1, 0, s2, 1, s1.length-1);
// s2 => | null | java | orcle | null | null | null
System.out.println("s1...");
for(String s: s1) {
System.out.print(s+" ");
}
System.out.println();
System.out.println("s2...");
for(String s: s2) {
System.out.print(s+" ");
}
System.out.println();
2차원 배열의 array.copy() 사용 시 주의할 점
- - 2차원배열에서는 값이 아닌 주소가 복사됨.
- - a배열
- a<-0x100 0x100|0x110| ---> 10 20 30
- |0x150| ---> 40 50 60
- - arraycopy 후 b배열
- b<-0x200 0x200|0x110|
- |0x150|
- - 값의 주소를 복사해야함.
int[][] a = new int[][] {{10,20,30},{40,50,60}};
int[][] b = new int[a.length][a[0].length];
// new int[2][3]
System.arraycopy(a, 0, b, 0, a.length);
// 2개만 복사. 2차원 배열은 주소를 복사.
System.out.println("a 배열...");
for(int i=0; i<a.length; i++) {
for(int j=0; j<a[i].length; j++) {
System.out.print(a[i][j]+" ");
}
System.out.println();
}
System.out.println("b 배열...");
for(int i=0; i<b.length; i++) {
for(int j=0; j<b[i].length; j++) {
System.out.print(b[i][j]+" ");
}
System.out.println();
}
b[1][1] = 200;
System.out.println(a[1][1] + ":" + b[1][1]); // 200 : 200
- 아래 코드와 같이 수정하여 for문을 사용해 값의 주소를 복사해야함.
// for문 사용하여 값의 주소 복사
for(int i=0; i<a.length; i++) {
System.arraycopy(a[i], 0, b[i], 0, a[i].length);
}