For each (향상된 for문)
형태
for (요소를 담은 변수 : 배열(반복접근 가능한 객체)) {
//반복문의 내용
}
특히 배열에서 잘 사용한다. 배열을 공부하고 다시 언급해보겠다.
배열
- 동일 자료형의 묶음
- 메모리도 연결된 부분을 사용
** 길이가 n일때 마지막 인덱스는 n-1이다. (인덱스가 0부터 시작하기 때문)
배열은 다음과 같이 사용된다.
선언 → 할당 → 값대입 → 사용
int[] arr;
int arr[];
둘다 가능하나 java에서는 위에것을 더 많이 사용한다.
배열의 할당은 배열 객체를 생성 후 변수에 주소값을 할당하는 것을 의미한다.
변수이름 = new 자료형 [저장 데이터 수];
ex) arr=new int[5];
위와 같은 규칙을 지닌다.
배열 초기화
- 배열 선언 및 할당, 값대입(요소) 를 한번에 처리하는 것을 의미한다.
char[] charArr = new char[] {'a', 'b', 'c'};
다음과 같은 코드를 배열 초기화 코드 라고 한다.
앞서 말한 for each문을 사용하자면, 배열의 요소인 'a','b', 'c'를 지정할 변수명이 필요하다.
for(char ch: charArr) { System.out.println(ch); }
변수명을 ch로 하고 , charArr의 배열에서 불러와서 for문을 진행할 것을 의미한다.
메모리에서의 배열
main과 test1 등의 메소드가 Stack에 쌓인다.
new int[5] ; 등 객체를 만든다는 것은 무조건 HEAP에 생성된다는 것을 의미한다.
heap은 메모리 공간에 이름을 부여할 수 없다. 주소값으로만 접근 가능 => Access by address
stack은 변수명(이름)으로 접근이 가능하다. 이름으로 접근 가능 => Access by name
stack 영역을 제외한 heap, static 영역은 변수공간이 생성될 경우, 타입별 기본값으로 초기화가 진행된다.
int 형 ) 0
double 형 ) 0.0
char 형 ) ' '
boolean 형 ) false
참조형 ) null
배열과 객체의 특징
배열의 특징
- 배열은 생성후에 크기변경이 불가하다.
- 크기를 처음부터 크게 잡는 경우, 메모리낭비가 불가피하다.
객체의 특징
- 객체마다 고유한 식별자(hashCode)를 가진다.
- 직접 삭제 불가능하고, 대신 참조형변수에 null을 대입하는 것을 삭제로 간주
(참조주소값을 삭제한 것은 heap영역 객체로 접근방법을 제거한 것.)
- 연결이 끊어진 객체는 Garbage Collector의 삭제대상이 되어 곧 삭제된다.
배열을 알아보자면 이정도 특징이 있겠다.
이해가 가는듯 마는듯..?!
String[] 참조형 배열
- 기본값으로 null을 가진다.
- int형이나 double 등 다른 형은 null 로 사용이 불가능하다.
String[] names = null; // 초기화
names = new String[3];
// int i = null; // 기본형의 값없음(null)은 사용불가
names[0] = "홍길동";
names[1] = "신사임당";
names[2] = "세종대왕";
for(int i = 0; i < names.length; i++) {
System.out.println(i + " : " + names[i]);
}
객체 삭제 진행해보기
int[] arr = new int[]{1,2,3,4,5};
System.out.println(arr);
System.out.println(arr.hashCode());
arr = new int[10];
System.out.println(arr.hashCode());
for(int i : arr)
System.out.println(i);
// 객체 삭제
arr = null;
// null여부 체크후 메소드실행...
if(arr != null) {
System.out.println(arr[0]);
// System.out.println(arr.hashCode());
// System.out.println(arr.length);// NullPointerException -> .앞이 null인지 체크
NullPointerException 에러가 발생하면, 점(.)앞의 배열이 null상태인지 체크하는것이 중요하다.
배열의 복사 (깊은 복사 / 얕은 복사)
- 얕은 복사(shallow copy)
배열 객체 주소 값을 복사한다. 같은 배열 객체를 공유한다.
- 깊은 복사(deep copy)
배열객체를 복사한다. 동일한 값을 가진 배열객체가 2개가 되는 것이다.
얕은복사
char[] arr1 = {'a', 'b', 'c'};
char[] arr2 = arr1; // 참조주소값 복사
arr1[1] += 2; // b -> d
System.out.println(arr1.hashCode());
System.out.println(arr2.hashCode());
for(int i = 0; i < arr1.length; i++) {
System.out.printf("%d : %c %c%n", i, arr1[i], arr2[i]);
}
주소값을 복사해서 사용했으므로, arr1 이나 arr2가 변경되면 다른 한가지도 변경되고, haseCode역시 같다.
깊은복사 1
직접 반복을 통해 값(요소) 복사하기
int[] arr1 = {10, 20, 30};
int[] arr2 = new int[arr1.length];
System.out.println(arr1.hashCode());
System.out.println(arr2.hashCode());
// 배열의 요소값 복사
for(int i = 0; i < arr1.length; i++) {
// 공간 = 값
arr2[i] = arr1[i];
}
// arr1의 요소값을 변경
arr1[1] *= 10; //깊은복사는 arr의 요소를 바꾸자 바뀌지 않았다.
// 결과확인
for(int i = 0; i < arr1.length; i++)
System.out.print(arr1[i] + " ");
System.out.println();
for(int i = 0; i < arr2.length; i++)
System.out.print(arr2[i] + " ");
깊은복사는 hashCode의 값이 다르며, arr1의 요소 값이 바뀌어도 arr2는 바뀌지 않는다.
이러한 깊은 복사 방법이 3가지나 존재한다.
깊은복사2
System.arraycopy
double[] darr1 = {3.3, 2.5, 7.1};
double[] darr2 = new double[darr1.length];
// static void java.lang.System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
System.arraycopy(darr1, 0, darr2, 0, darr1.length);
darr1[1] *= 10;
// 결과출력
for(int i = 0; i < darr1.length; i++) {
System.out.print(darr1[i] + " ");
}
System.out.println();
for(int i = 0; i < darr2.length; i++) {
System.out.print(darr2[i] + " ");
}
static void java.lang.System.arraycopy (Object src, int srcPos, Object dest, int destPos, int length)
양식을 가진다.
주로 배열을 복사할때, 합칠때 사용한다고 한다.
Object src ) 기존의 배열을 넣는다. 복사하고싶은 배열을 넣음.
int srcPos ) 기존배열의 어디부터 복사하고싶은지를 지정한다. (인덱스를 의미) 0을넣으면 처음부터 복사.
Object dest ) 저장하고 싶은 배열을 넣는다. 새로 만들어질 배열을 넣는다.
int destPos ) 저장하고 싶은 배열의 몇번째 인덱스부터 복사한 값을 넣고 싶은지 결정해서 숫자를 넣는다.
int length ) 기존 배열을 저장하고싶은 배열에 얼마나 긴 길이로 저장하고 싶은지 결정하여 숫자를 넣는다.
여기서는 전부 복사를 사용하므로 int srcPos와 destPos에 0을 넣었다.
깊은복사3
clone
아주간단하다. clone() 을 사용하면 된다.
boolean[] barr1 = {true, false, true, false};
boolean[] barr2 = barr1.clone();
System.out.println(barr1.hashCode());
System.out.println(barr2.hashCode());
barr1[1] = true;
for(int i = 0; i < barr1.length; i++) {
System.out.println(barr1[i] + ", " + barr2[i]);
}
그리고 과제를 하면서 알게된 String관련 함수들이 또 있다.
Split
String[] arr=스트링명.split("");을 할 경우 한글자씩 배열에 저장이 되고,
String[] arr=스트링명.split(" ");을 할 경우 split안이 기준이므로 띄어쓰기가 기준이 되어 단어별로 배열에 저장된다. 마찬가지로 쉼표를 기준으로도 할 수 있다.
String [] arr= 스트링명.split("",2); 라고 하면 최대 분할 갯수를 2개로 지정하여 2개만 저장하게 된다!
아주 유용한 함수인 것 같다
Substring
스트링명.substring(startIndex,endIndex) 로 선언하여 사용.
startIndex부터 lastIndex 전까지의 문자열을 잘라서 리턴한다.
스트링명. substring(startIndex)도 존재하기 때문에, 끝까지 필요한 경우 앞부분만 선언해서 사용할 수도 있다.
점점 모르는게 많이 나오고 어려워지고있다 ㅠㅠ
복습이 필수가 되어가고 수업에 집중을 점점 더 요하는중!!!
정처기랑 같이 병행할 수 있을지 .... 의문...ㅎ..