이것이 자바다 ch05 (5.1~5.5)

dev·2022년 10월 12일
1

이것이 자바다

목록 보기
1/7

5.1 데이터 타입 분류

자바의 데이터 타입은 2종류
1. 기본타입: 값 자체를 저장
2. 참조타입: 객체가 생성된 메모리 번지를 저장

참조타입
객체의 번지(주소값)를 참조하는 타입
-> 타입 종류: 배열, 열거, 클래스, 인터페이스

변수들은 모두 스택(stack) 이라는 메모리 영역에 생성된다.
기본타입은 값을 직접 저장하지만, 참조 타입 변수(예를 들어 String)는 힙 메모리 영역의 String 객체 주소를 저장하고 이 주소를 통해 String 객체를 참조한다.

=> 스택 영역: 기본타입의 값 저장, 참조타입의 주소값 저장
=> 힙 영역: 참조타입의 주소가 가리키는 실제 값 저장


사진출처: https://steady-coding.tistory.com/305

5.2 메모리 사용 영역

java 명령어로 JVM이 구동되면 JVM은 운영체제에서 할당받은 메모리영역을 구분해서 사용한다.
아래는 JVM의 메모리 구조이다. 중요하므로 잘 볼것

메소드 영역

바이트코드 파일 내용이 저장되는 영역.
클래스 별로 상수, 정적 필드, 메소드 코드, 생성자 코드 등이 저장된다.

힙 영역

객체가 생성되는 영역.
객체의 번지는 메소드 영역과 스택 영역의 상수와 변수에서 참조할수 있음
(스택 영역에서 힙 영역의 주소값을 가지고 있음)

스택 영역

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

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

==, != 연산자는 변수의 값이 같은지, 아닌지 조사한다.
참조타입 변수의 값은 객체의 주소값이므로 참조타입 변수의 ==, != 연산자는 주소값을 비교하는것이 된다.
주소값이 같으면 동일 객체를 참조하는 것이고,
다르면 다른 객체를 참조하는 것이다.

package ch05.sec03;

public class ReferenceVariableCompareExample {
    public static void main(String[] args) {
        int[] arr1;
        int[] arr2;
        int[] arr3;

        arr1 = new int[] {1,2,3};
        arr2 = new int[] {1,2,3};
        arr3 = arr2;

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

5.4 null과 NullPointerException

참조타입 변수는 null값을 가질수 있다. (아직 주소를 저장하지 않고 있다는 뜻)
null을 초기값으로 사용할수 있기때문에 null로 초기화된 참조변수는 스택영역에 생성된다.

package ch05.sec03;

public class ReferenceVariableCompareExample {
    public static void main(String[] args) {
        int[] arr1;
        int[] arr2;
        int[] arr3;

        arr1 = new int[] {1,2,3};
        arr2 = new int[] {1,2,3};
        arr3 = arr2;

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

참조타입 변수가 null값인지 확인하려면 !=, == 연산자 사용하면 된다.

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

  • NullPointerException: 변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려 할때 발생, 참조변수 사용하면서 많이 발생한다.

package ch05.sec04;

public class NullPointerExceptionExample {
    public static void main(String[] args) {
        int[] intArray = null;
//        intArray[0] = 10;//NullPointerException

        String str = null;
//        System.out.println(str.length()); //NullPointerException
    }
}

일부러 null을 대입하는 경우
객체를 사용하려면 참조변수를 이용해야하는데, 참조변수에 null을 대입하면 주소값을 잃게 되므로 더이상 객체를 사용할 수 없다.
즉, 스택 영역에 있던 주소가 null이 되면서, 힙 영역에 있던 객체는 위치정보를 모르는 사용불가 객체가 된다.
자바는 가비지콜렉터를 실행시켜 이런 쓰레기 객체를 자동 제거한다.
자바는 코드로 객체를 삭제하는 방법이 없기때문에, 객체를 제거하려면 객체의 모든 참조를 없애면 된다. => 중요함!!!!

package ch05.sec04;

public class GarbageObjectExample {
    public static void main(String[] args) {
        String hobby = "수영";
        hobby = null; //"수영"에 해당하는 String객체를 쓰레기객체로 만듦

        String kind1 = "자동차";
        String kind2 = kind1;
        kind1 = null; //kind2가 여전히 참조하고 있어서 "자동차"에 해당하는 String 객체가 쓰레기가 되지 않음
        System.out.println("kind2 : " + kind2); //kind2 : 자동차
    }
}

어느 하나라도 참조하고 있다면 삭제 되지 않음

5.5 문자열(String) 타입

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

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

  • 리터럴이란?
    변하지 않는 데이터 그 자체
    원시타입, String 두가지 리터럴 종류가 있다.

문자열 비교

자바는 문자열 리터럴이 동일하면 String객체를 공유한다.
name1과 name2 변수에 "홍길동"을 대입할경우, name1과 name2 변수에는 동일한 String객체의 주소가 저장된다.

String name1 = "홍길동";
String name2 = "홍길동";

//name1과 name2는 같은 객체를 참조하고있다. (같은 주소)

String 변수에 문자열 리터럴을 대입하는게 일반적이지만,
new 연산자로 직접 String 객체를 생성/대입할 수도 있다.

  • new 연산자: 새로운 객체를 만드는 연산자로 객체 생성 연산자
    즉, new 키워드를 쓸때마다 새로운 객체가 하나 만들어지는것
String name1 = new String("홍길동");
String name2 = new String("홍길동");

//name1과 name2는 서로 다른 String 객체를 참조하고 있다. (다른 주소)

equal()
동일한 String객체든, 다른 String객체든 상관없이 내부 문자열만 비교할때 사용하는 메소드(대소문자 구분)

boolean result = str1.equal(str2); //문자열이 같은지 검사 (str1이 원본, str2가 비교문자열)
boolean result != str1.equal(str2); //문자열이 다른지 검사

예시

package ch05.sec05;

public class EqualsExample {
    public static void main(String[] args) {
        String strVal1 = "홍길동";
        String strVal2 = "홍길동";

        if(strVal1 == strVal2) {
            System.out.println("strVal1, strVal2 는 같은 String 객체 참조");
        } else {
            System.out.println("strVal1, strVal2 는 다른 String 객체 참조");
        }

        if(strVal1.equals(strVal2)) {
            System.out.println("strVal1, strVal2 는 같은 문자열임");
        }

        System.out.println("--------------------------------------");

        String strVal3 = new String("김개똥");
        String strVal4 = new String("김개똥");

        if(strVal3 == strVal4) {
            System.out.println("strVal3, strVal4 는 참조가 같음");
        } else {
            System.out.println("strVal3, strVal4 는 참조가 다름");
        }

        if(strVal3.equals(strVal4)) {
            System.out.println("strVal3, strVal4 는 같은 문자열임");
        }
    }
}
//        strVal1, strVal2 는 같은 String 객체 참조
//        strVal1, strVal2 는 같은 문자열임
//                --------------------------------------
//        strVal3, strVal4 는 참조가 다름
//        strVal3, strVal4 는 같은 문자열임

String 변수에 빈문자열("")을 대입하면 빈문자열도 String객체로 생성된다. 변수가 빈문자열을 참조하는지 확인하려면 equals() 메소드를 사용해야한다.

package ch05.sec05;

public class EmptyStringExample {
    public static void main(String[] args) {
        String hobby = "";
        if(hobby.equals("")) { //true
            System.out.println("hobby 변수가 참조하는 String 객체는 빈문자열");
        }
    }
}

문자 추출

charAt() 메소드
문자열에서 특정 위치의 문자를 얻고자할때 사용
매개값으로 주어진 인덱스의 문자를 리턴한다.

  • 인덱스: 0부터 문자열의 길이-1 까지
//주민번호에서 성별에 해당하는 7번째 문자를 읽고 남자인지 여자인지 출력
package ch05.sec05;

public class CharAtExample {
    public static void main(String[] args) {
        String ssn = "9506241230123";
        char sex = ssn.charAt(6);
        switch (sex) {
            case '1':
            case '3':
                System.out.println("남자입니다.");
                break;
            case '2':
            case '4':
                System.out.println("여자입니다.");
                break;
        }
        
        //결과: 남자입니다. 
    }
}

문자열 길이

length() 메소드
문자열에서 문자의 개수를 얻고자 할때 사용
이때 띄어쓰기(공백)도 문자 개수 하나를 차지한다.
문자열.length();

package ch05.sec05;

public class LengthExample {
    public static void main(String[] args) {
        String ssn = "9506241230123";
        int length = ssn.length();
        if(length == 13) {
            System.out.println("주민번호 13자리가 맞음");
        } else {
            System.out.println("주민번호 13자리가 아님");
        }
        //결과: 주민번호 13자리가 맞음
    }
}

문자열 대체

replace() 메소드
문자열에서 특정 문자열을 다른 문자열로 대체하고자 할때 사용
기존 문자열은 그대로 두고, 대체한 새로운 문자열을 리턴한다.

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

String객체의 문자열은 변경이 불가한 특성을 갖기때문에 replace()메소드가 리턴하는 문자열은 원래 문자열을 수정한게 아니라 대체하는 새로운 문자열이다. 따라서 oldStr과 newStr은 서로 다른 문자열을 참조하고있다.

package ch05.sec05;

public class ReplaceExample {
    public static void main(String[] args) {
        String oldStr = "자바 문자열은 불변입니다. 자바 문자열은 String 입니다.";
        String newStr = oldStr.replace("자바", "JAVA");

        System.out.println(oldStr);
        System.out.println(newStr);

//        자바 문자열은 불변입니다. 자바 문자열은 String 입니다.
//        JAVA 문자열은 불변입니다. JAVA 문자열은 String 입니다.
    }
}

문자열 잘라내기

substring() 메소드
문자열에서 특정 위치의 문자열을 잘라내기 하여 가져오고 싶을때 사용
substring(int 시작인덱스) : 시작인덱스부터 끝까지 잘라내기
substring(int 시작인덱스, int 끝인덱스): 시작인덱스부터 끝인덱스까지 잘라내기

package ch05.sec05;

public class SubStringExample {
    public static void main(String[] args) {
        String ssn = "880815-1234567";

        String firstNum = ssn.substring(0, 6);
        System.out.println(firstNum); //880815

        String secondNum = ssn.substring(7);
        System.out.println(secondNum); //1234567
    }
}

문자열 찾기

indexOf() 메소드
문자열에서 특정 문자열의 위치를 찾고자 할 때 사용
주어진 문자열이 시작되는 index를 리턴한다.
주어진 문자열이 포함되지 않은경우 -1을 리턴
문자열.indexOf('시작 인덱스를 찾고자하는 문자열');

contains() 메소드
주어진 문자열이 단순히 포함 되어있는지만 확인하고자 할때 사용
원하는 문자열이 포함되어있으면 true를 리턴, 포함되지 않았으면 false를 리턴
문자열.contains("포함되어있는지 확인할 문자열");

package ch05.sec05;

public class IndexOfContainsExample {
    public static void main(String[] args) {
        String subject = "자바 프로그래밍";

        int location = subject.indexOf("프로그래밍");
        System.out.println(location); //3
        String substring = subject.substring(location);
        System.out.println(substring); //프로그래밍

        location = subject.indexOf("자바");
        if(location != -1) {
            System.out.println("자바와 관련된 책이군"); //자바와 관련된 책이군
        } else {
            System.out.println("자바 책이 아니군");
        }

        boolean result = subject.contains("자바");
        if(result) {
            System.out.println("제목에 '자바'가 포함된 책이군"); //제목에 '자바'가 포함된 책이군
        } else {
            System.out.println("제목에 '자바'가 없는 책이군");
        }
    }
}

문자열 분리

split() 메소드
문자열이 구분자를 사용하여 여러개의 문자열로 구성되어 있을경우, 이를 따로 분리해서 얻고자 할때 사용

Sring board = "번호,제목,내용,글쓴이";
String[] arr = board.split(",");
//arr[0] = "번호";
//arr[1] = "제목";
//arr[2] = "내용";
//arr[3] = "글쓴이";
package ch05.sec05;

public class SplitExample {
    public static void main(String[] args) {
        String board = "1,자바 학습,참조 타입 String을 학습합니다.,홍길동";

        //문자열 분리
        String[] tokens = board.split(",");

        //인덱스별로 읽기
        System.out.println("번호 : " + tokens[0]);
        System.out.println("제목 : " + tokens[1]);
        System.out.println("내용 : " + tokens[2]);
        System.out.println("성명 : " + tokens[3]);
        System.out.println();

        //for문을 이용한 읽기
        for(int i=0; i<tokens.length; i++) {
            System.out.println(tokens[i]);
        }
        
//        번호 : 1
//        제목 : 자바 학습
//        내용 : 참조 타입 String을 학습합니다.
//        성명 : 홍길동
//
//        1
//        자바 학습
//        참조 타입 String을 학습합니다.
//        홍길동
    }
}

출처: 이것이 자바다 (개정판) : JAVA 프로그래밍의 기본서 - 신용권, 임경균 저

profile
hello world!

2개의 댓글

comment-user-thumbnail
2022년 10월 26일

좋은 정보 감사합니다~ 좋은하루보내세요^^

1개의 답글