본문 바로가기
Java/이것이 자바다

참조 타입

by k-mozzi 2022. 10. 7.
반응형
Preface

 

이번 장에선 데이터 타입의 종류를 공부했다.

 

숫자의 타입 변환은 조금 익숙해졌다 싶었는데, 이번엔 배열을 생성하는 방법이 헷갈린다.

 

배열을 생성함과 동시에 값을 할당하는 방법, 선언한 후 값을 할당하는 방법, 배열의 크기만 설정한 후 값을 할당하는 방법 등 배열 객체를 생성하는 방법이 너무 다양하다.

 

또, 숫자형에서 문자열로, 문자열에서 숫자형으로 데이터 타입을 변환하는 방법도 계속 잊어버린다.

 

이 외에도 배열의 값을 출력하면 "[I@6bf2d08e"과 같은 이상한 값이 출력되어 올바른 값을 출력하는 방법도 따로 찾아봤다.

 

자바를 공부하다 보니 초보자는 자바와 C같은 언어보다 파이썬을 먼저 공부하라는 말이 100% 이해된다.


 

1. 데이터 타입 분류

 

 

- 데이터 타입

1) 기본(원시: primitive) 타입: 정수, 실수, 문자, 논리 리터럴을 저장하는 타입

→ 실제 값을 변수 안에 저장한다.

2) 참조(reference) 타입: 객체의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스 타입 등

→ 변수가 메모리의 번지를 값으로 갖는다.

 

 

- 변수는 스택 영역에, 객체는 힙 영역에 생성된다.

 


 

2. 메모리 사용 영역

 

 

- 자바 메모리 영역의 분류

1) 메소드 영역

2) 힙 영역

3) JVA 스택 영역

 

 

- 메소드 영역: 코드에서 사용되는 클래스들을 클래스 로더로 읽어 클래스별로 런타임 상수풀, 필드 데이터, 메소드 데이터, 메소드 코드, 생성자 코드 등을 분류해서 저장한다.

→ JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역이다.

 

 

- 힙 영역: 객체와 배열이 생성되는 영역

1) JVM 스택 영역의 변수나 다른 객체의 필드에서 참조한다.

2) 쓰레기 객체를 힙 영역에서 자동으로 제거한다.

 

 

- JVM 스택 영역: 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 할당된다.

1) 메소드를 호출할 때마다 프레임(frame)을 추가(push)하고 메소드가 종료되면 해당 프레임을 제거(pop)하는 동작을 수행한다.

2) 예외 발생 시 printStackTrace( ) 메소드로 보여주는 Stack Trace의 각 라인은 하나의 프레임으로 표현한다.

 

 

- 프레임: 메소드 상태 정보를 저장하는 곳

1) Local Variables

2) Operand Stack: 메소드 내의 계산을 위한 작업 공간

3) Constant Pool Reference

 

 

- 스택과 큐 비교

1) stack: Last In First Out

2) que: First In First Out

 

 

- 자바에서는 배열을 객체로 취급한다.

 

 

- 참조 타입 변수는 null 값을 가질 수 있다.

1) null값도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성된다.

2) 변수 자체는 스택 영역에, 실질적인 값은 힙 영역에 생성된다.

 

 

- 예외(exception): 프로그램 실행 도중에 발생하는 오류

 

 

- NullPointerException: 예외가 발생된 곳에서 객체를 참조하지 않은 상태로 참조 타입 변수를 사용할 때 발생하는 예외

 


 

3. String 타입

 

 

- 자바는 문자열 리터럴이 동일하면 String 객체를 공유한다.

→ 동일한 문자열이라도 new 연산자로 생성한 문자열은 다른 객체를 참조한다.

 

 

- 일반적으로 변수에 문자열을 저장할 땐 문자열 리터럴을 사용한다.

 

 

- new 연산자: 힙 영역에 새로운 객체를 만들 때 사용하는 연산자

→ 객체 생성 연산자와 동의어이다.

 

 

- == 연산자는 변수에 저장된 객체의 번지가 동일한지를 검사한다.

→ 문자열 자체를 비교할 땐 String 객체의 equals( ) 메소드를 사용해야 한다.

 

 

- 특정 변수가 객체를 참조하는 상태에서, null을 대입함으로써 더 이상 객체를 참조하지 않도록 할 수 있다.

→ 쓰레기 객체로 취급되어 메모리에서 자동으로 제거된다.

 


 

4. 배열 타입

 

 

- 배열: 같은 타입의 데이터를 연속된 공간에 나열시키고, 각 데이터에 인덱스를 부여한 자료구조

1) 같은 타입의 데이터만 저장할 수 있다.

2) 한 번 생성된 배열은 길이를 늘리거나 줄일 수 없다.

 

 

- 배열 변수를 선언할 땐 대괄호([ ])를 사용하는데, 이는 타입 뒤에 붙을 수도 있고 변수 뒤에 붙을 수도 있다.

타입[ ] 변수;
타입 변수[ ];
타입[ ] 변수 = null; // 참조할 배열 객체가 없는 경우

 

 

- 값 목록으로 배열을 생성하는 코드

package ch5;

public class arrayCreateByValueList1 {

	public static void main(String[] args) {

		int[] scores = { 83, 90, 87 };

		System.out.println("scores[0]: " + scores[0]);
		System.out.println("scores[1]: " + scores[1]);
		System.out.println("scores[2]: " + scores[2]);

		int sum = 0;
		for (int i = 0; i < 3; i++) {
			sum += scores[i];
		}
		System.out.println("sum: " + sum);
		double avg = (double) sum / 3;
		System.out.println("avg: " + avg);

	}

}

 

 

- 배열 변수를 이미 선언한 후에 다른 실행문에서 중괄호를 사용한 배열 생성은 불가능하다.

→ new 연산자를 사용하면 가능하다.

String[] names = null;
names = new String[] { "a", "b", "c" };

 

 

- 배열을 생성하며 값을 할당하면 new 키워드가 필요 없지만, 배열 생성 후 값을 할당할 땐 new 키워드를 사용해야 한다.

 

 

- 배열 자체는 "Array.toString(변수명)" 형식을 사용해야 출력된다.

→ 배열의 값을 for문을 통해 다른 변수에 담아서 출력할 수도 있다.

1) toString: 일차원 배열 출력

2) deepToString: 다차원 배열 출력

 

 

- 메소드의 매개값이 배열일 경우: 값 목록으로 배열을 생성함과 동시에 add( ) 메소드의 매개값으로 사용하고자 할 때는 반드시 new 연산자를 사용해야 한다.

package ch5;

public class arrayCreateByValueList2 {

	public static void main(String[] args) {

		int[] scores;
		scores = new int[] { 83, 90, 87 };
		int sum1 = 0;
		for (int i = 0; i < 3; i++) {
			sum1 += scores[i];
		}
		System.out.println("sum: " + sum1);

		int sum2 = add(new int[] { 83, 90, 87 });
		System.out.println("sum: " + sum2);
		System.out.println();

	}

	public static int add(int[] scores) {
		int sum = 0;
		for (int i = 0; i < 3; i++) {
			sum += scores[i];
		}
		return sum;
	}

}

 

 

- 값의 목록은 없지만, 향후 값들을 저장할 배열을 만드는 방법

타입[] 변수 = new 타입[길이];


타입[] 변수 = null;
변수 = new 타입[길이];

 

 

- 타입별 배열의 초기값

1) byte[ ]: 0

2) char[ ]: \u0000

3) short[ ]: 0

4) int[ ]: 0

5) long[ ]: 0L

6) float[ ]: 0.0f

7) double[ ]: 0.0

8) boolean[ ]: false

9) 클래스[ ]: null

10) 인터페이스[ ]: null

 

 

- 배열을 생성한 후 새로운 값을 지정할 땐 대입 연산자를 사용한다.

 

 

- 필드(field): 객체 내부의 데이터

 

 

- main( ) 메소드의 매개변수를 사용하는 코드

package ch5;

public class mainStringArrayArgument {

	public static void main(String[] args) {

		if (args.length != 2) {
			System.out.println("How to use this program?");
			System.out.println("java mainStringArrayArhument num1 num2");
			System.exit(0);
		}

		String strNum1 = args[0];
		String strNum2 = args[1];

		int num1 = Integer.parseInt(strNum1);
		int num2 = Integer.parseInt(strNum2);

		int result = num1 + num2;
		System.out.println(num1 + " + " + num2 + " = " + result);

	}

}

→ System.exit(0): 프로그램 강제 종료

 

 

- 배열의 종류

1) 1차원 배열: 값 목록으로 구성된 배열

2) 2차원 배열: 값들이 행과 열로서 구성된 배열

→ 자바에선 중첩 배열 방식으로 구현한다.

 

 

- 2행 3열의 배열을 생성하는 방법

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

 

 

- 배열 속의 배열

package ch5;

public class arrayInArray {

	public static void main(String[] args) {

		int[][] mathScores = new int[2][3];
		for (int i = 0; i < mathScores.length; i++) {
			for (int k = 0; k > mathScores[i].length; k++) {
				System.out.println("mathScores{" + i + "][" + k + "]=" + mathScores[i][k]);
			}
		}
		System.out.println();

		// 값 할당하고 출력하는 코드는 생략 
		
	}

}

 

 

- 배열 간의 항목 값들을 복사하는 방법

1) for문 사용

2) System.arraycopy( ) 메소드 사용

package ch5;

public class arrayCopyByFor {

	public static void main(String[] args) {

		int[] oldIntArray = { 1, 2, 3 };
		int[] newIntArray = new int[5];

		for (int i = 0; i < oldIntArray.length; i++) {
			newIntArray[i] = oldIntArray[i];
		}

		for (int i = 0; i < newIntArray.length; i++) {
			System.out.print(newIntArray[i] + ", ");
		}

	}

}
package ch5;

public class arrayCopyByMethod {

	public static void main(String[] args) {

		String[] oldStrArray = { "a", "b", "c" };
		String[] newStrArray = new String[5];

		System.arraycopy(oldStrArray, 0, newStrArray, 0, oldStrArray.length);
		// 원본 배열, 원본 배열에서 복사할 항목의 시작 인덱스, 새 배열, 새 배열에서 붙여넣을 시작 인덱스, 복사할 개수 

		for (int i = 0; i < newStrArray.length; i++) {
			System.out.print(newStrArray[i] + ", ");
		}

	}

}

 

 

- 복사의 종류

1) 얕은 복사: 새 배열의 항목이 이전 배열의 항목이 참조하는 객체와 동일

2) 깊은 복사: 참조하는 객체도 별도로 생성

 


 

5. 향상된 for문

 

 

- 향상된 for문: 배열 및 컬렉션 항목의 개수만큼 반복하고 자동으로 for문을 빠져나간다.

1) 카운터 변수와 증감식을 사용하지 않는다.

2) 괄호 안에는 배열에서 꺼낸 항목을 저장할 변수 선언, 콜론, 배열을 나란히 작성한다.

→ for문의 반복 횟수는 배열의 항목 수가 된다.

package ch5;

public class advancedFor {

	public static void main(String[] args) {

		int[] scores = { 95, 71, 84, 93, 87 };

		int sum = 0;
		for (int score : scores) {
			sum += score;
			System.out.println(score);
			System.out.println(sum);
			System.out.println();
		}
		System.out.println("sum of score: " + sum);

		double avg = (double) sum / scores.length;
		System.out.println("avg of score: " + avg);
	}

}

 


 

6. 열거 타입

 

 

- 열거(enumeration) 타입: 한정된 값만을 갖는 데이터 타입

→ 몇 개의 열거 상수 중 하나의 상수를 저장하는 데이터 타입

 

 

- 열거 타입 선언 방법: 열거 타입의 이름을 정하고 열거 타입 이름으로 소스 파일을 생성한다.

1) 열거 타입의 이름은 첫 문자를 대문자로 하고 나머지는 소문자로 한다.

2) 여러 단어로 구성된 이름이라면 단어 첫 문자는 대문자로 한다.

3) 열거 상수는 모두 대문자로 작성한다.

4) 열거 상수가 여러 단어로 구성될 경우엔 단어 사이를 언더바로 연결한다.

 

 

- public enum: 열거 타입을 선언하기 위한 키워드

1) 소문자로 작성해야 한다.

2) 열거 타입 이름과 소스 파일명이 정확히 일치해야 한다.

 

 

- 열거 타입 선언

package ch5;

public enum Week {
	MONDAY,
	TUESDAY,
	WEDNESDAY,
	THURSDAY,
	FRIDAY,
	SATURDAY,
	SUNDAY
}

 

 

- 열거 상수는 단독으로 사용할 수 없고 "열거타입.열거상수" 형식으로 사용된다.

열거타입 변수 = 열거타입.열거상수;

 

 

- 열거 타입 변수는 null 값을 저장할 수 있고, 열거 상수는 열거 객체로 생성된다.

 

 

- Calendar: 날짜와 시간을 얻을 수 있는 클래스

1) Calendar 변수를 선언한다.

2) Calendar.getInstance( ) 메소드가 리턴하는 Calendar 객체를 얻는다.

3) get( ) 메소드를 이용해 원하는 값을 얻는다.

package ch5;

import java.util.Calendar;

public class enumWeekExample {

	public static void main(String[] args) {

		Week today = null; // 열거 타입 변수 선언 

		Calendar cal = Calendar.getInstance();
		int week = cal.get(Calendar.DAY_OF_WEEK); // 일(1)~토(7)까지의 숫자를 리턴 

		switch (week) {
		case 1:
			today = Week.SUNDAY; // 열거 상수 대입 
			break;
		case 2:
			today = Week.MONDAY;
			break;
		case 3:
			today = Week.TUESDAY;
			break;
		case 4:
			today = Week.WEDNESDAY;
			break;
		case 5:
			today = Week.THURSDAY;
			break;
		case 6:
			today = Week.FRIDAY;
			break;
		case 7:
			today = Week.SATURDAY;
			break;
		}

		System.out.println("today: " + today);

		if (today == Week.SUNDAY) {
			System.out.println("today is SUNDAY");
		} else {
			System.out.println("today is not SUNDAY");
		} //sd

	}

}

 

 

- 모든 열거 타입은 컴파일 시 Enum 클래스를 상속한다.

 

 

- 열거 객체의 메소드

1) name( ): 열거 객체가 가지고 있는 문자열을 리턴한다.

2) ordinal( ): 전체 열거 객체 중 몇 번째 열거 객체인지 알려준다.

→ 열거 타입을 정의할 때 주어진 순번

3) compareTo( ): 매개값으로 주어진 열거 객체를 기준으로 전후로 몇 번째 위치하는지를 비교한다.

→ 열거 객체가 매개값보다 순번이 빠르면 음수, 늦으면 양수가 리턴된다.

4) valueOf( ): 매개값으로 주어지는 문자열과 동일한 문자열을 가지는 열거 객체를 리턴한다.

5) values( ): 열거 타입의 모든 열거 객체들을 배열로 만들어 리턴한다.

package ch5;

public class enumMethodExample {

	public static void main(String[] args) {

		// name(): 열거 객체의 문자열을 리턴
		Week today = Week.SUNDAY;
		String name = today.name();
		System.out.println(name);

		// ordinal(): 열거 객체의 순번을 리턴
		int ordinal = today.ordinal();
		System.out.println(ordinal);

		// compareTo(): 열거 객체를 비교해서 순번 차이를 리턴
		Week day1 = Week.MONDAY;
		Week day2 = Week.WEDNESDAY;
		int result1 = day1.compareTo(day2);
		int result2 = day2.compareTo(day1);
		System.out.println(result1);
		System.out.println(result2);

		// valueOf(): 주어진 문자열의 열거 객체를 리턴
		if (args.length == 1) {
			String strDay = args[0];
			Week weekDay = Week.valueOf(strDay);
			if (weekDay == Week.SATURDAY || weekDay == Week.SUNDAY) {
				System.out.println("It's a weekend");
			} else {
				System.out.println("It's a weekday");
			}
		}

		// values(): 모든 열거 객체들을 배열로 리턴
		Week[] days = Week.values();
		for (Week day : days) {
			System.out.println(day);
		}

	}

}

 

728x90
반응형

'Java > 이것이 자바다' 카테고리의 다른 글

클래스  (2) 2022.10.13
타입 변환 메소드  (2) 2022.10.07
조건문과 반복문  (0) 2022.10.02
연산자  (0) 2022.09.30
자바 시작하기, 변수와 타입  (0) 2022.09.28

댓글