[이것이자바다] Chapter 05. 참조 타입

kims·2023년 11월 23일
0

이것이자바다

목록 보기
5/9

5.1 데이터 타입 분류

  • 자바의 데이터 타입은 기본 타입(primitive type)과 참조 타입(reference type)으로 분류된다.
  • 기본 타입값 자체를 저장하고, 참조 타입은 객체가 생성된 메모리 번지를 저장한다.
    • 변수들은 모두 스택 메모리 영역에 생성되는데 기본 타입은 직접 을 저장하고 있지만, 참조 타입은 힙 메모리 영역의 객체 번지를 저장하고 이 번지를 통해 객체를 참조한다.

출처👉[이것이자바다] 5.1 데이터 타입 분류

5.2 메모리 사용 영역

  • java 명령어로 JVM이 구동되면 JVM은 운영체제에서 할당받은 메모리 영역(Runtime Data Area)을 메소드, , 스택으로 구분해 사용한다.
구분설명
메소드 영역바이트코드 파일의 내용이 저장되는 영역, static 변수가 저장되며 모든 객체가 접근 가능하다.
힙 영역객체가 생성되는 영역, 가비지 컬렉션에 대상이 된다.
메소드 영역과 스택 영역의 상수와 변수에서 객체의 번지를 참조한다.
스택 영역메소드를 호출할 때마다 생성되는 프레임이 저장되는 영역, 메소드 호출이 끝나면 프레임은 자동 제거된다.
프레임 내부에 로컬 변수 스택이 있는데, 여기에 기본 타입 변수와 참조 타입 변수가 생성되고 제거된다.

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

  • ==!= 연산자는 변수의 값이 같은지 아닌지 비교한다.
  • 기본 타입을 비교한다면, 참조 타입은 객체의 번지를 비교한다.
  • 참조 타입의 경우 같은 값이 저장되더라도 서로 다른 객체로 번지는 다르다.
public class ReferenceType {
    public static void main(String[] args) {
        int x = 5;
        int y = 5;
        System.out.println(x == y);                   // true

        int[] arrayX = {1, 3, 5 ,7};
        int[] arrayY = {1, 3, 5, 7};
        System.out.println(arrayX == arrayY);         // false
        System.out.println(arrayX.equals(arrayY));    // false

        int[] arrayZ = arrayY;
        System.out.println(arrayZ == arrayY);         // true
        System.out.println(arrayZ.equals(arrayY));    // true
    }
}

💡 Object객체 equals( )

  • 메서드 내부에서 ==연산자를 사용해 객체의 번지가 같은지 비교한다.

5.4 null과 NullPointerException

  • 참조 타입 변수는 null 값을 가질 수 있다. 이 때, null로 초기화된 참조 변수는 스택 영역에 생성된다.
  • 프로그램 실행 도중 발생한 오류를 예외(Exception)이라 부른다.
  • 변수가 null인 상태에서 객체의 데이터나 메서드를 사용하려 할 때 NullPointerException 예외가 발생한다.
public class ReferenceType {
    public static void main(String[] args) {
        int[] lotto = null;
        System.out.println(lotto.length);  // Exception in thread "main" java.lang.NullPointerException: Cannot read the array length because "lotto" is null
    }
}

5.5 문자열(String) 타입

  • 자바의 문자열은 String 객체로 생성된다.
  • String 객체는 문자열 리터럴이 동일하면 서로 공유하도록 설계되어있다. 즉, 동일한 String 객체의 번지가 저장된다.
    단, new 연산자로 새로운 객체를 만들면 문자열 리터럴이 동일해도 서로 다른 String 객체의 번지를 가지게 된다.
  • ""빈 문자열만으로도 String 객체를 생성할 수 있다.

1) 문자열 비교

  • 내부 문자열이 동일한지 비교하고 싶다면 String 객체의 equals( ) 메서드를 사용하면 된다.
public class ReferenceType {
    public static void main(String[] args) {
        String food = "";
        System.out.println(food.length());            // 0

        String color1 = "red";
        String color2 = "red";

        System.out.println(color1 == color2);         // true

        String color3 = new String("red");
        System.out.println(color1 == color3);         // false
        System.out.println(color2 == color3);         // false

        System.out.println(color1.equals(color3));    // true
    }
}

💡 String객체 equals( )

  • 메서드 내부에서 조건문으로 ==연산자를 사용해 객체의 번지가 같은지 비교한다.
    같지 않다면,
    1) instanceof로 Argument(anObject)가 String 타입인지 확인(true 또는 false 반환)하고, 맞다면 해당 변수(aString)에 자동 캐스팅하여 할당한 값과
    2) COMPACT_STRINGS 상수 값과 coder(문자열 저장 방법 : 0(UTF-16인코딩) 또는 1(Latin-1 인코딩))의 값을 비교하고,
    3) 두 문자열의 길이와 각 각의 글자를 비교한다.

2) 문자 추출

  • 문자열에서 특정 위치의 문자를 얻고 싶다면 charAt( ) 메서드를 사용한다.
    주어진 인덱스의 문자를 리턴하는데, 인덱스란 0에서부터 시작해 '문자열의 길이 - 1'까지의 번호를 말한다.

3) 문자열 길이

  • 문자열에서 문자의 개수를 얻고 싶다면 length( ) 메서드를 사용한다.

4) 문자열 대체

  • 문자열에서 특정 문자열을 다른 문자열로 대체하고 싶다면 replace( ) 메서드를 사용한다.
  • 새로운 String 객체를 생성한다.

5) 문자열 잘라내기

  • 문자열에서 특정 위치의 문자열을 잘라내어 가져오고 싶다면 substring( ) 메서드를 사용한다.
  • 새로운 String 객체를 생성한다.
  • beginIndex ~ endIndex -1 까지 문자열을 잘라낸다.
public String substring(int beginIndex, int endIndex) { ... }

6) 문자열 찾기

  • 문자열에서 특정 문자열의 위치를 찾고자 할 때에는 indexOf( ) 메서드를 사용한다.
    문자열이 있다면 인덱스를, 없다면 '-1'을 리턴한다.
  • 문자열이 중복된 경우 처음으로 나타나는 위치의 인덱스를 리턴
  • 문자열이 단순 포함되어 있는지만 알고 싶다면 contains( ) 메서드를 사용한다.
    문자열이 포함되어 있다면 true, 없다면 false를 리턴한다.

7) 문자열 분리

  • 문자열이 구분자를 사용해 여러 개의 구성되어 있을 경우 split( ) 메서드를 사용하면 구분자 기준으로 분리된 문자열 배열을 얻을 수 있다.
import java.util.Arrays;

public class StringEx {
    public static void main(String[] args) {
        String food = "다코야키, 햄버거, 문어숙회, 해물누룽지탕, 문어튀김";

        System.out.println(food.length());                               // 29

        System.out.println(food.charAt(0));                              // 다
        System.out.println(food.charAt(3));                              // 키         
        System.out.println(food.charAt(29));                             // Exception in thread "main" java.lang.StringIndexOutOfBoundsException: index 29, length 29

        System.out.println(food.replace("문어", "오징어"));                // 다코야키, 햄버거, 오징어숙회, 해물누룽지탕, 오징어튀김
        System.out.println(food);                                        // 다코야키, 햄버거, 문어숙회, 해물누룽지탕, 문어튀김

        System.out.println(food.substring(3, 7));                        // 키, 햄
        System.out.println(food);                                        // 다코야키, 햄버거, 문어숙회, 해물누룽지탕, 문어튀김

        System.out.println(food.indexOf("문"));                          // 11
        System.out.println(food.indexOf("문어"));                        // 11

        System.out.println(food.contains("누룽지"));                     // true

        System.out.println(Arrays.toString(food.split(",")));           // [다코야키,  햄버거,  문어숙회,  해물누룽지탕,  문어튀김]

    }
}

5.6 배열(Array) 타입

  • 변수는 하나의 값만 저장할 수 있기에 저장해야 할 값이 많아지면 변수의 개수가 늘어난다.
  • 배열은 인덱스(Index)를 부여해 놓은 자료구조로 각 인덱스에 값을 저장한다.
  • 배열은 같은 타입의 값만 저장할 수 있고, 길이는 늘리거나 줄일 수 없다.

1) 배열 변수 선언 및 생성

  • 배열 변수는 참조 변수로 힙 영역에 생성되고 null로 초기화할 수 있다.
  • 배열 변수를 미리 선언했다면 new 타입[]을 사용해 값을 대입할 수 있다.
  • new 연산자를 사용하면 배열의 길이 지정이 가능하고, 데이터 타입의 기본값으로 초기화된다.
  • 메소드의 매개변수가 배열 타입이면, 매개값으로 중괄호{}로 감싼 값을 파라미터로 넘기면 컴파일 에러가 발생한다.
import java.util.Arrays;

public class ArrayEx {
    public static void main(String[] args) {
        int[] age;
        //age = {15, 20, 45}; // 컴파일 에러 발생 : illegal start of expression
        age = new int[]{15, 20, 45};
        System.out.println(Arrays.toString(age));       // [15, 20, 45]

        int[] year = {2021, 2022, 2023};
        String[] name = {"철수", "영희", "순자"};

        System.out.println(Arrays.toString(year));      // [2021, 2022, 2023]
        System.out.println(Arrays.toString(name));      // [철수, 영희, 순자]

        int[] height = new int[3];
        System.out.println(Arrays.toString(height));    // [0, 0, 0]

        String[] season = new String[4];
        season[0] = "봄";
        System.out.println(season[0]);                  // 봄
        System.out.println(season[2]);                  // null
        System.out.println(season.length);              // 4

        int[] month = {1, 2, 3, 4, 5};
        System.out.println(Arrays.toString(month));     // [1, 2, 3, 4, 5]
        System.out.println(month.length);               // 5

        int[] printArr = {2, 4, 6};                     // (i : 0 -  array[i] : 2) (i : 1 -  array[i] : 4) (i : 2 -  array[i] : 6)
        print(printArr);

        //print({2,4,6});  //컴파일 에러 발생 : illegal start of expression
    }

    public static void print(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.printf("(i : %d -  array[i] : %d) ", i, array[i]);
        }
    }
}

5.7 다차원 배열

  • 배열에 또 다른 배열이 대입되는 것을 다차원 배열이라 한다.
  • 2차원 배열이라면 타입 뒤에 대괄호[]2개를, 3차원 배열이라면 대괄호[]3개를 붙여 선언한다.
  • 다차원 배열 생성 시 차원의 수 만큼 중괄호를 중첩시키거나 new 연산자를 사용할 수 있다.
import java.util.Arrays;

public class ArrayEx {
    public static void main(String[] args) {
        int[][] soccerScore = new int[3][4];                      // 3행 4열의 다차원 배열
        System.out.println(soccerScore.length);                   // 3
        System.out.println(soccerScore[0].length);                // 4
        System.out.println(soccerScore[1].length);                // 4
        System.out.println(soccerScore[2].length);                // 4
        // System.out.println(score[3].length);                   // 런타임 에러 발생 : Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
        soccerScore[0][1] = 15;
        System.out.println(Arrays.toString(soccerScore[0]));      // [0, 15, 0, 0]
        System.out.println(Arrays.toString(soccerScore[1]));      // [0, 0, 0, 0]
        System.out.println(Arrays.toString(soccerScore[2]));      // [0, 0, 0, 0]
        // System.out.println(Arrays.toString(score[3]));         // 런타임 에러 발생 : Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

        int[][] basketballScores = {
                {20, 30, 40},
                {1, 3}
        };

        System.out.println(basketballScores.length);                  // 2
        System.out.println(Arrays.toString(basketballScores[0]));     // [20, 30, 40]
        System.out.println(Arrays.toString(basketballScores[1]));     // [1, 3]
        System.out.println(basketballScores[0][1]);                   // 3
        System.out.println(basketballScores[1][1]);                   // 3
    }
}

public class ArrayEx {
    public static void main(String[] args) {
        // Q. 주어진 배열 항목의 전체 합과 평균을 구해 출력하는 코드를 작성해보세요.(중첩 for문 이용)
        int[][] array = {
                {95, 86},
                {83, 92, 96},
                {78, 83, 93, 87, 88}
        };

        int count = 0;
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                sum += array[i][j];
                count++;
            }
        }
        System.out.printf("전체 합 : %d, 전체 평균 : %.1f", sum, (double) sum/count);      // 전체 합 : 881, 전체 평균 : 88.1
    }
}

5.8 객체를 참조하는 배열

  • 기본 타입 배열은 각 항목에 값을 직접 저장하지만, 참조 타입 배열은 각 항목에 대한 객체의 번지를 저장한다.
  • 리터럴이 같다면 동일한 번지에 저장된다.
    단, new 연산자로 새로운 배열을 생성하면 서로 다른 객체의 번지를 갖게 된다.
import java.util.Arrays;

public class ArrayEx {
    public static void main(String[] args) {
        String[] fruits = new String[5];
        fruits[0] = "apple";
        fruits[1] = "avocado";
        fruits[2] = "blackberry";
        fruits[3] = "avocado";

        String[] brand = {"apple"};

        String[] juice = new String[2];
        juice[0] = new String("apple");

        System.out.println(fruits.length);                 // 5
        System.out.println(Arrays.toString(fruits));       // [apple, avocado, blackberry, avocado, null]
        System.out.println(fruits[1] == fruits[3]);        // true
        System.out.println(fruits[0] == brand[0]);         // true
        System.out.println(fruits[0] == juice[0]);         // false
        System.out.println(brand[0] == juice[0]);          // false
        System.out.println(brand[0].equals(juice[0]));     // true
    }
}

5.9 배열 복사

  • 배열은 한 번 생성하면 길이를 변경할 수 없다.
  • 배열은 복사하면 기존 배열의 번지가 그대로 새로운 배열에 복사돼 저장된다.
import java.util.Arrays;

public class ArrayEx {
    public static void main(String[] args) {
        int[] firstArray = {1, 3, 5};
        int[] secondArray = new int[5];

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

        System.out.println(Arrays.toString(secondArray));    // [1, 3, 5, 0, 0]
        System.out.println(firstArray[0] == secondArray[0]); // true

        int[] newArray = new int[5];
        System.arraycopy(firstArray, 0, newArray, 0, firstArray.length);
        System.out.println(Arrays.toString(newArray));      // [1, 3, 5, 0, 0]
        System.out.println(firstArray[0] == newArray[0]);   // true
    }
}

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

public class ArrayEx {
    public static void main(String[] args) {
        String[] colors = {"FFFFFF", "CCFFCC", "FFCCFF", "E5FFCC"};
        for (String color : colors) {
            if (color.contains("5")) {
                System.out.println(color);  // E5FFCC
            }
        }

    }
}
  • 배열에서 가져올 항목(colors)이 있으면 변수(String color)에 항목을 저장하고,
    실행문(if (color.contains("5")) {...})을 실행한다.
    다시 반복하면서, 배열에서 가져올 항목이 존재하면 변수에 저장하고 실행문을 실행한다.
    더이상 가져올 항목이 없으면 for문을 종료한다.
public class ArrayEx {
    public static void main(String[] args) {
        // Q. 주어진 배열 항목에서 최대값을 출력하는 코드를 작성해보세요.(for문 이용)
        int[] array = {1, 5, 3, 8, 2};

        int max = 0;
        for (int num: array) {
            if (max < num) {
                max = num;
            }
        }

        System.out.println(max);    // 8
    }
}

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

  • main()메서드는 자바 프로그램의 시작점이다.
  • Java는 명령 프롬프트나 터미널에서 프로그램을 실행할 때 값을 요구할 수 있다.
    전달된 값은 문자열로 취급되어 String[] 배열의 항목 값으로 저장되고, main()메서드 호출 시 매개값으로 전달된다.
public class ArrayEx {
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("2개의 입력 값이 필요합니다.");
            System.exit(0);
        }

        System.out.println(Integer.parseInt(args[0]) + Integer.parseInt(args[1]));
    }
}

💡 인텔리제이에서 입력값을 주고 실행하는 방법
1) Edit Configurations... 클릭

2) Run/Debug Configurations 대화상자에서 Program arguments 입력란에 값을 입력한다.

5.12 열거(Enum) 타입

  • 한정된 값을 갖는 타입
  • 열거 상수는 열거 타입으로 사용할 수 있는 한정된 값을 말하며, 관례적으로 모두 대문자 알파벳으로 정의한다.
  • 열거 타입에는 열거타입.열거상수 형태로만 대입할 수 있다. 또한, 참조 타입이므로 null도 대입 가능하다.
public enum Rainbow {
    RED,
    ORANGE,
    YELLOW,
    GREEN,
    BLUE,
    INDIGO,
    PURPLE
}

public class EnumEx {
    public static void main(String[] args) {
        System.out.println(Rainbow.RED);    // RED

        Rainbow color = null;
        // color = "red";   // 컴파일 에러 : java: incompatible types: java.lang.String cannot be converted to Rainbow
        color = Rainbow.INDIGO;
        System.out.println(color);          // INDIGO
    }
}

profile
기술로 세상을 이롭게

0개의 댓글