Programming Language/자바(JAVA)

[JAVA] 참조 타입 - 문자열, 배열

토자맨 2024. 11. 21. 03:36

JAVA에 데이터 타입은 크게 기본 타입과 참조 타입으로 나누어 진다.

참조 타입에 대해 알아보자

참조 타입(reference type)

참조 타입은 기본 타입과 다르게 값 자체가 아니라 객체가 생성된 메모리 번지를 저장한다.
변수들은 스택 영역에 저장되고 변수가 가리키는 객체는 힙 영역에 저장된다.

메모리 사용 영역

JVM이 구동되면 JVM은 운영체제에서 할당받은 메모리 영역(Runtime Data Area)을 다음과 같이 구분해서 사용한다.

메소드 영역

바이트코드 파일을 읽은 내용이 저장된다.

힙 영역

객체가 생성되는 영역이다.
객체의 번지(주소)는 메소드 영역의 상수와 스택 영역의 변수를 참조한다.

스택 영역

메소드를 호출할 때마다 생성되는 프레임이 저장되는 영역이다.
메소드 호출이 끝나면 프레임은 자동으로 삭제된다.
프레임 내부에는 로컬 변수 스택(기본 타입 변수, 참조 타입 변수)이 있다.
프레임이란

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

참조 타입은 객체의 번지를 의미한다.
따라서 참조 타입 변수를 비교하는 == , != 연산은 객체의 번지를 비교하는 것이다.

  • arr1과 arr2 배열에 저장된 항목은 같지만 서로 다른 객체이다. 두 객체의 번지가 다르므로 다른 변수이고, arr2와 arr3는 같은 번지를 참조하므로 같은 변수이다.
int[] arr1 = new int[] {1, 2, 3};
int[] arr2 = new int[] {1, 2, 3};
int[] arr3 = arr2;

null과 NullPointerException

참조 타입 변수를 null로 초기화한다면 참조 변수는 스택 영역에 생성되지만 힙 영역에 참조하는 객체는 생성되지 않는다.
NullPointerException은 변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려 할 때 발생한다.

  • intArr는 참조 하는 객체가 힙 영역에 존재하지 않기 때문에 해당 객체를 사용하려 하면 NullPointerException이 발생하고 str도 마찬가지이다.
int[] intArr = null;
intArr[0] = 10; // NullPointerException

String str = null;
System.out.println(str.length()); // NullPointerException
  • 참조 변수를 삭제하는 방법
    • 참조 변수에 null값을 대입하여 객체의 번지를 잃게 만든다.
    • 이렇게 하면 JAVA는 이러한 객체를 쓰레기로 취급하고, Garbage Collector를 실행시켜 해당 객체를 자동으로 삭제한다.
String hobby = "여행"; // "여행" 객체 삭제
hobby = null;
  • 참조 변수에 다른 객체를 삽입하는 경우
    • 원래 참조하던 객체를 Garbage Collector가 삭제한다.
String hobby = "여행"; // "여행" 객체 삭제
hobby = "운동";

문자열(String) 타입

문자열 비교 - new String(), equals()

  • 문자열 리터럴이 동일하다면 String 객체를 공유한다.
  • 이 경우 동일한 객체를 참조하므로
    • name1 == name2은 true가 나오고
    • name1.equals(name2)도 true가 나온다.

  • new 연산자로 직접 String 객체를 생성한 뒤 대입하면 서로 다른 객체를 참조한다.
  • new 연산자는 새로운 객체를 만드는 연산자로 객체 생성 연산자라고 한다.
  • 이 경우 서로 다른 객체를 참조하므로
    • name1 == name2은 false가 나오고
    • name1.equals(name2)은 true가 나온다.
String name1 = new String("홍길동");
String name2 = new String("홍길동");

일반적으로 문자열을 생성할 때 객체 생성 연산자를 사용하므로 equals() 메소드로 비교하도록 하자.

문자 추출 - charAt(index값)

//  0  1  2
// |김|자|반|
String name = "김자반";
char extraction = ssn.charAt(1);

문자열 길이 - length()

문자열 대체 - replace()

String 객체의 문자열은 변경할 수 없다.
따라서 replace() 메소드는 완전히 새로운 객체를 만드는 메소드이다.

String oldStr = "자바 프로그래밍";
String newStr = oldStr.replace("자바", "JAVA");

문자열 잘라내기 - substring()

  • substring(int 시작 인덱스)
    • 시작 인덱스부터 문자열의 마지막 인덱스까지 잘라내기
  • substring(int 시작 인덱스, int 끝 인덱스)
    • 시작 인덱스부터 지정된 끝 인덱스까지 잘라내기문자열 찾기 - indexOf()

String subject = "자바 프로그래밍";
int index = subject.indexOf("프로그래밍");

문자열 분리 - split()

String board = "번호,제목,내용,성명";
String[] arr = board.split(",");
// ["번호", "제목", "내용", "성명"]

배열(Array) 타입

  • 배열의 특징
    • 같은 타입의 값만 관리한다.
    • 한 번 지정한 배열의 길이는 늘리거나 줄일 수 없다.배열 변수 선언
  • 타입[] 변수; -> 관례적으로 이 방식 사용
  • 타입 변수[];

배열 생성

배열을 생성하는 방법은 값 목록으로 생성하는 방법과 new 연산자(객체 생성 연산자)로 생성하는 방법이 있다.

값 목록으로 생성 - {값1, 값2, 값3 ..}

배열 객체를 힙 영역에 생성하고 참조 변수에 번지를 리턴한다.

String[] season = {"봄", "여름", "가을", "겨울"};

이 방식은 배열을 먼저 생성한 뒤 나중에 삽입할 수 없다.

String[] season;
season = "봄", "여름", "가을", "겨울"}; // 컴파일 에러

new 연산자로 생성 - new String[길이]

  • 먼저 배열을 생성한 뒤 나중에 삽입할 수 있다.
  • 배열의 초기값: null
String[] season = new String[4];
season[0] = "봄";
season[1] = "여름";

배열 길이 - 배열.length

배열변수.length;

다차원 배열

변수[1차원인덱스][2차원인덱스]...[n차원인덱스]

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

int[][] scores = {
    {80, 90, 96}, // index: 0, 1, 2
    {76, 88} // index: 0, 1
}

scores[0][1] // 90

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

타입[][] 변수 = new 타입[1차원수][2차원수];

  • 초기값
    • 정수: 0
    • 실수: 0.0
    • 논리: false
    • 참조: null
  • 2차원 배열의 길이 다르게 주기
int[][] scores = new int[2][];
scores[0] = new int[3];
scores[1] = new int[2];
/**
{null, null, null}
{null, null}
**/

객체를 참조하는 배열

이전 문자열에서 배운 것처럼 문자열 리터럴이 같다면 같은 객체를 참조하고 new 연산자(객체 생성 연산자)로 생성한 경우 문자열의 값이 같더라도 참조하는 객체는 다르다.

String[] languages = new String[3];
languages[0] = "Java";
languages[1] = "Java";
languages[2] = new String("Java");
// languages[0]과 languages[1]은 같은 객체(힙 영역 존재) 참조
// languages[2]는 힙 영역의 "JAVA" 값을 가진 문자열 객체를 새롭게 생성하여 참조(languages[0]과 languages[1]이 참조하는 객체와 다른 객체 참조)
System.out.println(languages[0] == languages[1]);        // true
System.out.println(languages[0] == languages[2]);        // false
System.out.println(languages[0].equals(langauges[2]));    // true

배열 복사

배열을 복사하는 방법은 for 반복문을 이용한 방법과 System의 arraycopy() 메소드를 이용한 방법이 있다.

  • arraycopy()
    • System.arraycopy(원본 배열, 원본 복사 시작 인덱스, 새 배열, 붙여넣기 시작 인덱스, 복사 항목 수);
    • System.arraycopy( oldArr, 0, newArr, 0, oldArr.length);

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

인덱스로 배열 항목 하나하나 가져올 필요 없이 아래와 같은 방식으로도 for 문을 사용할 수 있다.

int sum = 0;
int[] scores = {1, 2, 3, 4, 5};
for (int score : scores) {
    sum += score;
}

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

자바 프로그램을 실행하기 위해 main() 메소드를 작성했다.

public class _20546_기적의_매매법 {
    public static void main(String [] args) {
        코드...
    }

여기서 String [] args 매개변수가 왜 필요한지 살펴보자.

  • 윈도우 명령 프롬프트나 맥OS 터미널에서 프로그램을 실행할 때 요구하는 값이 있을 수도 있다.
  • 값을 입력하면 args 문자열 배열에 입력한 값이 저장된다.
  • ex. Java Sum 10 20을 입력
// Java Sum 10 20 입력
// String[] args가 10과 20을 문자열로 취급하여 받는다.
args[0] <- "10";
args[1] <- "20";

String x = args[0]; // x == 10
String y = args[1]; // y == 20

열거(Enum) 타입

  • 열거 타입이란 한정된 값을 갖는 타입을 의미한다.
  • 예를 들어 요일은 월, 화, 수, 목, 금, 토, 일을 갖는 열거 타입이다.
  • 열거 타입 이름으로 소스 파일(.java)을 생성하고 한정된 값을 코드로 정의하여 사용한다.
  • 열거 타입 이름은 첫 문자를 대문자로 하고 캐멀(camel) 스타일로 지어주는 것이 관례이다.
  • public enum Week { // 열거 상수 - 대문자로 작성하고 여러 단어로 구성될 경우 언더바(_)로 이어주기 (ex.LOGIN_SUCCESS) MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } Week today = Week.SUNDAY; Week birthday = null; // 컴퓨터의 날짜, 요일, 시간 얻을 때는 Calendar 사용(즉, 현재 날짜, 요일, 시간) Calendar now = Calendar.getInstance(); int year = now.get(Calendar.YEAR); // 연 int month = now.get(Calendar.MONTH) + 1; // 월(1~12) int day = now.get(Calendar.DAY_OF_MONTH); // 일 int week = now.get(Calendar.DAY_OF_WEEK); // 요일(1~7) int hour = now.get(Calendar.HOUR); // 시간 int minute = now.get(Calendar.MINUTE); // 분 int second = now.get(Calendar.SECOND); // 초
  • 출처