KOSTA 3일차) 배열 / 배열 복사 / new연산자 / 메모리 구조 / 형변환

해버니·2023년 2월 19일
0

KOSTA

목록 보기
15/32
post-thumbnail

배열

배열은 집합데이터 처리를 수월하게 해줌
하나의 배열에 값을 여러개 저장이 가능
타입은 한 가지 (int면 int, float이면 float만 저장 가능)
배열의 크기는 고정
배열 지정해주지 않으면 기본값은 0이다.




배열 생성

int[] a=new int[5]
int[] arr = { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 1, 2, 3, 4 };	//	[] 안에 숫자를 넣으면 에러가 남

"new" 어디서 봤지? scanner에도 있었다.


Scanner sc = new Scanner(System.in);

scanner는 객체 타입이고 배열도 같은 맥락이다.
객체타입이기 때문에 new를 이용해서 생성을 해줘야 방이 만들어진다.




new 연산자

클래스 변수 = new 클래스();
인스턴스(객체)를 생성해주는 역할

  1. 힙영역에 객체를 생성한다.
  2. 생성자를 호출하여 생성한 객체를 초기화한다.
  3. 초기화까지 끝낸 객체의 주소를 반환한다.






❓ 힙 ❓

힙은 메모리 종류중 하나임
메모리는 구역구역 나눠서 쓴다 (Static, Heap, Stack)

힙은 변수로 접근은 못하고 주소로만 접근할 수 있다.
C++에서는 메모리 관리를 잘 못해서 메모리 누수가 발생하기도 했다.
하지만 자바는 메모리 관리를 자체로 처리/해제를 해준다.
메모리 관리를 위해 JVM(자바 가상머신)에 의해 알아서 해제된다.
이러한 기능을 가비지컬렉션(GC, 쓰레기 수집)이라고 한다.

그래서 c나 c++은 직접적으로 다이렉트 주소로 접근 가능하지만 자바는 주소로 접근을 한다.
자바는 다이렉트주소로 접근 불가능하고 참조값으로 접근 가능 (난수값을 만들어내서)


참조값은 4바이트
객체 이름은 4바이트 할당



예를들어

int[] c=new int[3]

위의 지역변수 c는
stack-main에 c 4바이트가 할당이 된다.












자바 메모리 구조

  1. Static Area
  2. Stack Area
  3. Heap Area

저장되는 메모리가 다르면 특성도 다르다. 예를 들어 언제 시작되고 언제 끝나는지, 자동으로 초기화가 되는지 등등 이런 특징이 결정되는 것이다.



static area

static : 정적 메모리

하나의 java 파일은 크게

① 필드(field)
② 생성자(constructor)
③메소드(method)

로 구성된다.


필드 부분에서 선언된 변수(전역변수)정적 멤버변수(static이 붙은 자료형)은 static 영역에 데이터를 저장한다.
static 영역의 데이터는 프로그램의 시작부터 종료가 될 때까지 메모리에 남아있게 된다.
다르게 말하면 전역변수가 프로그램이 종료될 때까지 어디서든 사용이 가능한 이유이기도 하다.
따라서 전역변수를 무분별하게 많이 사용하다보면 메모리가 부족할 수도 있다.




stack area

stack : 메서드가 사용
참조형 타입 변수는 참조값만 저장됨
참조값 : heap영역에 존재하는 인스턴스를 가리키는 역할

지역변수의 데이터 값이 저장되는 공간이 stack 영역이다.
해당 메소드가 호출될 때 메모리에 할당되고 종료되면 메모리가 해제된다.

int a=5, a=4, a=3, a=2;
System.out.println(a);	//	2

a라는 변수는 main 메소드가 호출될 때 Stack 영역에 할당되고 종료시 해제된다.
또한 a의 출력값은 2가 된다.
이전 데이터는 지워지는 것이고 2라는 값만 출력된다.
즉, Stack 영역은 LIFO의 구조를 갖고 새로운 데이터가 할당되면 이전 데이터는 지워진다는 것을 알 수 있다.



heap area

new : 힙에 메모리를 할당받는 연산자
new로 만드는 친구들은 다 heap에 할당을 받는다고 생각하면 된다.

heap : 배열 객체
참조형(Reference Type)의 데이터 타입을 갖는 객체, 배열 등은 heap 영역에 데이터가 저장된다.

이때 변수는 stack영역의 공간에서 실제 데이터가 저장된 heap 영역의 참조값을 new 연산자를 통해 리턴받는다.
다시 말하면 실제 데이터를 갖고 있는 heap 영역의 참조값을 stack 영역의 객체가 갖고있다.
이렇게 리턴받은 참조값을 갖고 있는 객체를 통해서만 해당 인스턴스를 핸들할 수 있다.













형변환

char[] name=new char[3];
char ch='a';

for(int i=0;i<name.length;i++) {
   name[i]=(char)(ch+i); 		// 형변환
   System.out.print(name[i]+"\t");
}



1) 자동 형변환

4 + 5.4 → 타입이 서로 다른 값을 연산할 때 자동으로
작은 타입을 큰 타입으로 변환. 연산자 필요 없음
(ch+i)
i는 4바이트 ch는 2바이트이므로 int형으로 변환


2) 강제 형변환

강제로 타입 변환
캐스팅 연산자를 작성해야 함
캐스팅 연산자: (타입)변수 (char)(ch+i)

문자열 연결도 가능하다.












배열 복사

깊은 복사(Deep Copy)는 '실제 값'새로운 메모리 공간에 복사하는 것
얕은 복사(Shallow Copy)는 '주소 값'을 복사한다는 것.



1) 얕은 복사

참조값 복사
요소를 변경하면 다른쪽에 영향을 줌
(배열에 있는 값 : 요소)



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

참조하고 있는 실제 값은 동일하고 복사한 객체가 변경된다면 기존의 객체도 변경이 되는 것.
동일한 주소를 참조하고 있기 때문에 original의 객체에도 영향을 끼치게 된다.
a와 b는 참조값(주소가)이 같음

new가 없다면 새로운 할당을 받은게 아니라 다른 메모리를 같이 끌어다 쓰는 상태.




2) 깊은 복사

배열의 요소는 동일하지만 다른 메모리에 복사
직접 구현할 수도 있고 api 메서드를 사용할 수도 있다.



① 직접 구현
똑같은 메모리의 크기로 할당을 받아서 값을 넣어주면 된다.

int[] a={1, 2, 3, 4, 5};
int[] b = new int[a.length];
for(int i=0; i<b.length; i++){
   b[i]=a[i];
}



② api 이용
arraycopy()를 활용

System.arraycopy(src, srcPos, dest, destPos, length);

src : 원본 배열
srcPos : 원본 배열의 복사 시작 위치
dest : 복사할 배열
destPost : 복사할 배열의 복사 시작 위치
legnth : 복사할 요소의 개수












2차원 배열

배열의 배열
요소로 배열을 갖는 배열


int[][] a = new int[2][3];

for(int i=0; i<a.length; i++){ // 줄수
   for(int j=0; j<a[0].length; j++){ // 각 줄의 칸수
      a[i][j]=3*i+j+1;  
   }
}
// 1 2 3 
// 4 5 6




가변 초기화

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

for(int i=0; i<c.length; i++){
   System.out.println("c["+i+"]의 크기 : "+ c[i].length);	// 4 2 
   for(int j=0; j<c[i].length; j++){
      System.out.print(c[i][j] + "\t");
   }
   System.out.println();
}






참고 : 자바 메모리 구조


0개의 댓글