on my way

이것이 자바다 Chapter05. 참조 타입 본문

Computer Science/JAVA

이것이 자바다 Chapter05. 참조 타입

wingbeat 2024. 4. 1. 22:02
반응형

Part02. 객체 지향 프로그래밍

개념, 코드가 왜 이런 의미를 갖는지 유의하며 보자.

 

5.1 데이터 타입 분류

자바는 기본 타입, 참조 타입으로 분류 된다.

배열, 열거, 인터페이스, (클래스)에 집중하자.

5장에서는 이런 특징을 이해하자.

참조타입이란 객체의 번지를 이용하는 것이다. (메모리가 어디있는지)

객체란? 데이터와 메소드로 구성된 덩어리.

메모리 어딘가에 객체가 생성되어 있고, 이를 참조하는 것이 '참조 타입'이다.

 

변수가 하나의 값을 저장하는 이름

그 메모리에 값이 직접 들어가는 것 - 기본 타입

변수안에 메모리 안에 다른 메모리의 번지를 갖고 있는 것이 '참조 타입' => 이 번지로 가서 무언가를 하라.

100번지에 있는 변수를 참조한다.

 

기본 타입 변수는 int age = 25; //age가 25을 갖고 있음

참조 타입 변수는 String name = "홍길동"; 

 

name 변수에 name이 없다. 스택, 힙 영역 모두 메모리이다.

name의 100 번지를 참조하면 특정 문자열이 있다.

변수는 stack영역에 생성된다. 참조 타입 변수인 name과 hobby같은 객체는 힙 메모리 영역에 생성이 되고, 그 번지가 참조타입 변수에 저장된다.

 

 

5.2 메모리 사용 영역

메모리는 RAM을 의미한다.

메모리 영역은 메소드, 힙, 스레드 세개로 나눠져서 쓴다.

메소드 영역에는 바이트 코드(자바 코드) 파일의 내용이 저장 된다!!! -> 클래스 별로 상수, 정적 필드, 메소드 코드, 생성자 코드 등이 저장됨.

힙 영역에는 객체들이 저장이 된다!!!! -> 객체의 번지는 메소드 영역과 스택 영역의 상수 변수에서 참조 가능.

변수스택 영역에 생성이 된다!!!!! -> 메소드를 호출할 때 마다 생성되는 프레임이 저장된다. 메소드 호출이 끝나면 프레임은 자동 제거 된다. 프레임 내부에는 로컬 변수 스택이 있고, 여기서 기본 타입 변수와 참조 타입 변수가 생성 및 제거된다.

 

5.3 참조 타입 변수의 ==, != 연산

값이 같은지 다른지를.

참조타입은 변수의 저장 번지끼리를 비교하게 된다. 그래서 그 연산자를 사용해서 비교하면 데이터를 비교한다고 생각할 수도 있다.

r1 == r2 주소끼리 비교 (false)

r2 != r3 주소끼리 비교 (true) : 동일한 객체2를 참조하고 있으므로

 

배열은 참조 타입이다.

대괄호로 선언된 변수는 배열 변수이다.

이는 번지를 갖고 있는 참조 타입이다.

배열을 힙에 생성하고 new int[] {1, 2, 3} , 힙에 생성된 번지를 arr1에 저장한다. 

package ch05.sec03;

public class ReferenceVariableCompareExample {
	public static void main(String[] args) throws Exception {
		int[] arr1; // 배열 변수 arr1 선언
		int[] arr2;
		int[] arr3;

		arr1 = new int[] { 1, 2, 3 }; // 배열 {1,2,3}을 생성하고 arr1 변수에 대입
		arr2 = new int[] { 1, 2, 3 }; // 배열 {1,2,3}을 생성하고 arr2 변수에 대입
		arr3 = arr2; // 배열변수 arr2 값을 배열변수 arr3에 대입

		System.out.println(arr1 == arr2);
		System.out.println(arr2 == arr3);
	}
}

스택은 객체의 번지를 갖고 있는 것이다. 

즉 비교를 하는 것은 번지끼리 비교를 하는 것이다.

 

 

5.4 null과 NullPointerException

참조 타입 변수는 아직 번지를 저장하고 있지 않단 뜻으로 null을 가질 수 있다.

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

참조 타입 변수로 null 연산 가능

자바 프로그램 실행 중 오류를 Exception이라 한다.

참조 변수를 사용하며 많이 발생하는 예외 중 하나가 NulPointerException이다.

변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려 할 때 예외 발생함.

 intArray에 참조할 배열 객체가 없어서 10을 저장할 수 없기 때문

str 변수에 null을 대입한 상태에서 문자열 길이를 얻기 위해 length() 메소드를 호출하면 NullPointerException 발생.

이는 str변수가 참조하는 String 객체 없으므로 문자열 길이를 구할 수 없기 때문.

 

NullPointerException이 발생하면, 예외가 발생된 곳에서 null 상태인 참조 변수가 사용되는 것을 알아야 한다.

이것을 해결하려면 참조 변수가 객체를 정확히 참조하도록 번지를 대입해야 한다.

 

경우에 따라서 참조 타입 변수에 일부러 null을 대입하기도 함.

프로그램에서 객체를 사용하려면 해당 객체를 참조하는 변수를 이용해야 하는데, 변수에 null을 대입하면 번지를 잃게 되므로 더이상 객체를 사용할 수 없게 된다.

힙 메모리에는 있지만, 위치 정보를 모르기에 사용할 수 없고. Java는 이런 객체를 쓰레기 수집기를 실행시켜 자동으로 제거한다.

자바는 코드를 이용해 객체를 제거하는 방법을 제공하지 않는다. 객체를 제거하는 유일한 방법은 객체의 모든 참조를 없애는 것이다.

여행에 해당하는 String 객체는 쓰레기가 된다. hobby에 영화가 대입되며 String 객체의 번지가 대입되어 이전 번지를 잃어버리기 때문이다.

 

5.5 문자열(String) 타입

자바의 문자열은 String 객체로 생성된다.

name 변수와 hobby 변수에 문자열 리터럴이 대입되면 문자열은 String 객체로 생성되고, 객체의 번지가 각각 대입된다.

 

문자열 비교

new String이 더 일반적임.

즉, 번지가 다르다.

동일 객체를 가리킴

새로운 String 객체 번지를 갖게 된다.

 

문자열 자체를 비교하려면 String 객체의 equals() 메소드를 사용해서 비교해야 한다.

 

=!

 

문자열 비교는 equals를 써라

package ch05.sec05;

public class EqualsExample {

	public static void main(String[] args) {
		String strVar1 = "홍길동";
		String strVar2 = "홍길동";
		System.out.println(strVar1 == strVar2); // true
		System.out.println(strVar1.equals(strVar2)); // true

		String strVar3 = new String("홍길동");
		String strVar4 = new String("홍길동");
		System.out.println(strVar3 == strVar4); // false
		System.out.println(strVar3.equals(strVar4)); // true

	}

}

 

 

문자 추출

charAt() : 인덱스를 찾는다.

replace(A,B): A를 B로 바꾼, 새로운 문자열을 객체를 만들어서 리턴

 

문자열 길이

length() 메소드 사용.

 

문자열 대체

replace() 메소드 사용

기존 문자열은 두고 대체한 새로운 문자열을 리턴

문자열 자르기

substring(0,6); : 0부터 5까지 자른다

substring(7); : 7부터 끝까지

 

문자열 찾기

특정 문자열의 위치 : indexOf("특정문자열")

 

fileName.lastIndexOf(".") : 뒤에서 서치. 있으면 열이 시작하는 번호를, 없으면 -1 리턴

contain() : 포함하면 true 없으면 false

 

검색 방법 : java(언어) 문자열 찾기 

String contents = "hi jkewiwejoweifwoei";

System.out.println(contents.contains("바보"));

if (contents.indexOf("바보") > -1) { 

    // 있으면 0보다 크다.

}

 

문자열 분리

split() // 문자열을 내가 원하는 값(구분자)으로 쪼개서 배열로 만들어 준다.

String[] str2Arr = str2.split(" "); // 무조건 String[] 스트링 배열 타입으로 선언되어야 한다.

 

Tip

참조타입 변수는 대부분 첫자가 대문자이다. (배열 제외)

. 뒤는 메서드 아니면 필드이다.

Int[].length / String.length()

배열의 length는 메서드가 아니고, string의 length는 메서드이다.

메서드는 ()가 있다. -> 실행을 하는 것. 즉 실행할 수 있다.

=> math.random()하면 랜덤값이 나오는 것 처럼 name.length()하면 string의 length를 return

배열은 ()가 없다. 실행할 수 없기 때문.

//변수는 값을 그냥 return?

 

5.6 배열(Array) 타입

저장해야 할 값이 많아지면? 타입이 같고, 동일한 유형의 값을 갖는다면 배열로 관리하자.

배열은 연속된 공간에 값을 나열시키고, 각 값에 인덱스를 부여한 구조이다. (0~)

 

배열의 특징

안에 전부 같은 타입이 들어가야함 (int, String....)

한 번 배열이 만들어지면 배열의 크기(길이)를 변경할 수 없다.

 

배열 변수 선언

배열 변수를 선언한다. 이를 선언하는 방식은 두가지가 있다.

대괄호는 배열 변수

int[] 변수;

int 변수[]; // 잘 안함S

 

배열 변수는 참조 변수이다. 객체이므로 힙 영역에 생성된다.

타입[] 변수 = null;

참조할 배열이 없다면 null으로 초기화할 수 있다.

기본 자료형은 0, 참조자료형은 null로 초기화 된다.

null 상태에서 변수[인덱스]로 값을 읽거나 저장하면 NullPointerException 이 발생한다.

 

값 목록으로 배열 생성

''

new 연산자로 배열 생성

값의 목록은 없지만 향후 값을 저장하기 위해

 

길이 5인 int[] 배열을 생성하고, 배열 번지를 intArray 변수에 대입한다.

int[] intArray = new int[5];

 

new 연산자로 배열을 처음 생성하면 배열 항목은 아래같은 기본값으로 초기화 된다.

 

배열 길이

배열변수.length

 

 

5.7 다차원 배열

배열 변수는 5번지의 1차원 배열을 참조하고, 변수[0]은 10번지 배열을 참조하고 변수[1]은 30번지 배열을 참조한다...

위와 같이 다차원 배열은 1차원 배열을 서로 연결한 것이다.

 

값 목록으로 다차원 배열 생성

array2d = new int[][] {{1,2,3},{4,5,6},{7,8,9}}

행렬을 사용하면 좌표로 생각할 수 있다.

 

new 연산자로 다차원 배열 생성

배열 변수 선언 시 타입 뒤에 대괄호를 [ ] 차원의 수만큼 붙이고, new에도 붙이면 된다.

5.8 객체를 참조하는 배열

기본 타입 (byte, char, short, int ,long ,float , double, boolean) 배열은 각 항목에 값을 직접 저장하지만,

참조타입(클래스, 인터페이스) 배열은 각 항목에 객체의 번지를 저장한다.

==, != 같은 산술 연산자를 사용하면 배열이 참조하는 객체가 같은 객체인지 다른 객체인지 확인할 수 있고, 문자열만 비교할 때는 equals() 메소드를 사용한다.

 

 

 

5.9 배열 복사

한 번 생성된 배열은 길이를 변경할 수 없고, 더 많은 저장 공간이 필요하면 더 큰 길이의 배열을 만들어 복사해야 한다.

새로운 변수에 담는것은 복사같지만 사실 "얕은 복사"이다.

참조 자료형이기 때문에 같은 주소를 가지고 있다. 

 

복사방법

1. 수작업으로 하나하나

복사되지 않은 인덱스의 값은 초기화된 항목 0이다.

 

2. system class의 arraycopy() 메소드 사용

System.arraycopy(array,0,array4,0, array.length))

 

Tip! ctrl + . + space 가능한게 들어온다. 대괄호 안에 쓸 거 같은 것을 추천해준다. (예를 들면 int안에는 int 추천해줌)

3. Arrays.copyOf(arr, arr.length)

 

 

5.10 배열 항목 반복을 위한 향상된 for문

인덱스 필요없고 값만 필요하다면.  

for (int ar: array5) {

}

사용하면 array5의 요소들을 ar에 하나씩 잡아준다.

ar은 for문 안에서만 돌아가는 지역변수이고, 밖에서 사용 불가능.

 

 

5.11 main() 메소드의 String[] 매개변수 용도

매개변수? (매개: 어떤 것과 어떤 것을 이어주는. 매개체 역할을 한다.)

하나는 매서드 안쪽, 하나는 매서드 실행문.

public static void main(String[] args) {

실행은 JVM이 한다. 그때 String[] args에 값을 넘겨준다.

넘겨주는 방법은 ...

run configration에서 순서대로 넘겨주면 된다.

 

 

명령 프롬프트나 터미널에서 입력값 주기

cmd창에서 java ch05.sec05.Main abc test 를 실행하면 그대로 실행된다. (매개변수 차례대로 넘겨주기)

 

5.12 열거(Enum) 타입

몇 가지로 한정된 값을 갖는 경우 (월~일, 봄~겨울....)을 열거 타입이라 한다.

파일 적으로는 enum 타입이 있다.

우리가 알고 있는 변수같기도, 아닌거 같기도. "열거 상수" -> 열거 타입이라고 하기도 한다.

Week이란 열거타입 안에 있는 값이다. 뒤에서 배울 상수 개념과 비슷하다. (항상 같은 수, 변하지 않음)

 

- 참조 타입, null 대입 가능

- 열거 변수를 비교할 때는 ==, !- 연산자 이용.

 


확인문제

 

9번

// 내가 짠 코드

package ch05.sec05;

import java.util.Scanner;

public class ScoreProgram {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int flag = 1;
		int student = 0;
		int[] score = null;

		while (true) {
			System.out.println("-------------------------------------");
			System.out.println("1.학생수|2.점수입력|3.점수리스트|4.분석|5.종료");
			System.out.println("-------------------------------------");
			System.out.print("선택> ");
			flag = Integer.parseInt(scanner.nextLine());
			if (flag == 5) {
				break;
			} else if (flag == 1) {
				System.out.print("학생수> ");
				student = Integer.parseInt(scanner.nextLine());
				score = new int[student];
			} else if (flag == 2) {
				for (int i = 0; i < student; i++) {
					System.out.print("scores[" + i + "]> ");
					score[i] = Integer.parseInt(scanner.nextLine());
				}
			} else if (flag == 3) {
				for (int i = 0; i < student; i++) {
					System.out.println("scores[" + i + "]: " + score[i]);
				}
			} else if (flag == 4) {
				int max = 0;
				int sum = 0;
				for (int i = 0; i < student; i++) {
					sum += score[i];
					if (max < score[i])
						max = score[i];
				}
				System.out.println("최고 점수: " + max);
				System.out.println("평균 점수: " + (double) Math.round(sum / student * 10) / 10);
			}
		}
		System.out.println("프로그램 종료");
	}
}
// 선생님 코드
package ch05.sec05;

import java.util.Scanner;

public class ScoreProgram {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		boolean flag = true;
		int student = 0;
		int[] score = null;

		while (flag) {
			System.out.println("-------------------------------------");
			System.out.println("1.학생수|2.점수입력|3.점수리스트|4.분석|5.종료");
			System.out.println("-------------------------------------");
			System.out.print("선택> ");
			String input = scanner.nextLine();
			
			if ("5".equals(input)) {
				flag = false;
//				break;
			} else if ("1".equals(input)) {
				System.out.print("학생수> ");
				student = Integer.parseInt(scanner.nextLine());
				score = new int[student];
			} else if ("2".equals(input)) {
				for (int i = 0; i < student; i++) {
					System.out.print("scores[" + i + "]> ");
					score[i] = Integer.parseInt(scanner.nextLine());
				}
			} else if ("3".equals(input)) {
				for (int i = 0; i < student; i++) {
					System.out.println("scores[" + i + "]: " + score[i]);
				}
			} else if ("4".equals(input)) {
				int max = 0;
				int sum = 0;
				for (int i = 0; i < student; i++) {
					sum += score[i];
					if (max < score[i])
						max = score[i];
				}
				System.out.println("최고 점수: " + max);
				System.out.println("평균 점수: " + (double) sum / student);
			}
		}
		System.out.println("프로그램 종료");
	}
}
반응형