Skip to content

Latest commit

 

History

History
241 lines (201 loc) · 14.3 KB

File metadata and controls

241 lines (201 loc) · 14.3 KB

배열

    public static void main(String[] args) {
        int student1 = 90;
        int student2 = 80;
        int student3 = 70;
        int student4 = 60;
        int student5 = 50;

        System.out.println("학생1 점수 : " + student1);
        System.out.println("학생2 점수 : " + student2);
        System.out.println("학생3 점수 : " + student3);
        System.out.println("학생4 점수 : " + student4);
        System.out.println("학생5 점수 : " + student5);
    }
  • 학생을 몇 명 더 추가해야 한다면 변수를 선언하는 부분과 점수를 출력하는 부분의 코드도 추가해야한다. 학생을 몇 명 더 추가하는 것은 개발자가 코딩으로 해결할 수 있겠지만, 학생을 수백 명 이상추가해야 한다면 코드가 상당히 많이 늘어날 것이다. 결국 학생 수가 증가함에 따라 코딩 야잉 비례해서 증가하는 문제가 발생한다.
  • 변수를 선언하는 부분을 보면 학생 수가 증가함에 따라 int형 변수를 계속해서 추가해야 한다. 학생 수가 5명이면 int형 변수를 5개 선언해야 하고, 학생 수가 100명이라면 int형 변수를 100개 선언해야 한다. 결국 비슷한 변수를 반복해서 선언하는 문제가 발생한다.
  • 반복문으로 해결할 수 있을 것 같지만, 점수를 출력하는 부분을 보면 변수의 이름이 다르기 때문에 반복문도 적용 할 수 없다.

이렇게 같은 타입의 변수를 반복해서 선언하고 반복해서 사용하는 문제를 해결하는 것이 바로 배열이다.

1. 배열 변수 선언

  1. int[] students; //배열 변수 선언
    • 배열을 사용하려면 int[] studnts; 와 같이 배열 변수를 선언한다.
    • 일반적인 변수와 차이점은 int[]처럼 타입 다음에 대괄호[]가 들어간다는 점이다.
    • 배열 변수를 선언한다고해서 아직 사용할 수 있는 배열이 만들어진 것은 아니다!
      • int a에는 정수를, double b 에는 실수를 담을 ㅅ ㅜ있다.
      • int[] students와 같은 배열 변수에는 배열을 담을 수 있다.(배열 변수에는 10,20같은 값이 아니라 배열이라는 것을 담을 수 있다.)

2. 배열 생성

  1. students = new int[5]// 배열 생성
    • 배열을 사용하려면 배열을 생성해야 한다.
    • new int[5]라고 입력하면 int형 변수 5개가 만들어진다.
    • new는 새로 생성한다는 뜻이고, int[5]는 int형 변수 5개라는 뜻이다. 따라서 int형 변수 5개를 다룰 수 있는 배열을 새로 만든다는 뜻이다.
    • 앞서 int student1, int student2 ... int student5까지 총 5개의 변수를 직접 선언했다. 배열을 사용하면 이런 과정을 한번에 깔끔하게 처리할 수 있다.

배열과 초기화

  • new int[5]라고 하면 총 5개의 int형 변수가 만들어진다. 자바는 배열을 생성할 때 그 내부값을 자동으로 초기화한다.
  • 숫자는 0, boolean은 false, String은 null(없다는 뜻)로 초기화 된다.

3. 배열 참조값 보관

  1. students = x001; //배열 참조값 보관
    • new int[5]로 배열을 생성하면 배열의 크기만큼 메모리를 확보한다. *int형을 5개 사용하면 4byte * 5 -> 20byte를 확보한다.
    • 배열을 생성하고 나면 자바는 메모리 어딘가에 있는 이 배열에 접근할 수 있는 참조값(주소)(x001)을 반환한다.
      • 여기서 x001이라고 표현한 것이 참조값이다.
    • 앞서 선언한 배열 변수인 int[] students에 생성된 배열의 참조값(x001)을 보관한다.
    • int[] students 변수는 new int [5]로 생성한 배열의 참조값을 가지고 있다.
      • 이 변수는 참조값을 가지고 있다. 이 참조값을 통해 배열을 참조할 수 있다. 쉽게 이야기해서 참조값을 통해 메모리에 있는 실제 배열에 접근하고 사용할 수 있다.
      • 참고로 배열을 생성하는 new int[5] 자체에는 아무런 이름이 없다. 그냥 int형 변수를 5개 연속으로 만드는 것이다. 따라서 생성한 배열에 접근하는 방법이 필요하다. 따라서배열을 생성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다. 앞서 int[] students변수에 참조값 (x001)을 보관해 두었다. 이 변수를 통해서 이 배열에 접근할 수 있다.

위 부분을 풀어서 설명하면 다음과 같다.

int[] students = new int[5]; //1. 배열 생성
int[] students = x001; //2. new int[5]의 결과로 x001 참조값 변환
students = x001 //3, 최종 결과

참조값을 확인하고 싶으면 다음과 같이 배열의 변수를 출력해보면 된다.

System.out.println(students); //[I@4617c264 @앞의 [I는 int형 배열을 뜻한다. @뒤에 16진수는 참조값을 뜻한다.

배열 사용

인덱스

배열은 변수와 사용법이 비슷한데, 차이점이 있다면 다음과 같이 []사이에 숫자 번호를 넣어주면 된다. 배열의 위츠를 나타내는 숫자를 인덱스(index)라 한다.

//변수 값 대입
students[0] = 90;
students[1] = 80;

//변수 값 사용
System.out.println("학생1 점수 : " + students[0]);
System.out.println("학생2 점수 : " + students[1]);

배열은 0부터 시작한다.

new int [5]와 같이 5개의 요소를 가지는 int형 배열을 만들었다면 인덱스는 0, 1, 2, 3, 4가 존재한다. 여기서 주의해야 할 점이 있는데 인덱스는 0부터 시작한다는 것이다. 배열의 요소를 5개로 생성했지만, 인덱스는 0부터 시작한다. 따라서 사용 가능한 인덱스의 범위는 0 ~ (n-1)이 된다. 그래서 students[4]가 배열의 마지막 요소이다.

인덱스 허용범위를 넘어설 때 발생하는 요류

만약 student[5]와 같이 접근 가능한 배열의 인덱스 범위를 넘어가면 다음과 같은 오류가 발생한다.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsExceoption : Index 5 out of bounds for length 5 at array.Array1Ref1.main(ArrayRef1.java:14)

1. 배열에 값 대입

배열에 값을 대입하든 배열의 값을 사용하든간에 일반적인 변수와 사용법은 같다. 추라로 []를 통해 인덱스만 넣어주면 된다.

students[0] = 90; //1. 배열에 값을 대입
x001[0] = 90; //2. 변수에 있는 참조값을 통해 실제 배열에 접근, 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입
students[1] = 80; //1. 배열에 값을 대입
x001[1] = 80; //2. 변수에 있는 참조값을 통해 실제 배열에 접근, 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입

2. 배열 값 읽기

//1. 변수 값 읽기
System.out.println("학생1 점수 : " + students[0]);
//2. 변수에 있는 참조값을 통해 실제 배열에 접근, 인덱스를 사용해서 해당 위치의 요소에 접근
System.out.println("학생1 점수 : " + x001[0]);
//3. 배열의 값을 읽어옴
System.out.println("학생1 점수 : " + 90);

기본형 vs 참조형

자바의 변수 데이터 타입을 가장 크게 보면 기본형과 참조형으로 분류할 수 있다. 사용하는 값을 직접 넣을 수 있는 기본형, 그리고 방금 본 배열 변수와 같이 메모리의 참조값을 넣을 수 있는 참조형으로 분류할 수 있다.

  • 기본형(Primitive Type) : 우리가 지금까지 봤던 int, long, double, boolean처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형(Primitive Type)이라 한다.
  • 참조형(Referencee Type): int[] students[]와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입을 참조형(Reference Type)이라 한다.

참고

기본형은 모두 사이즈가 명확하게 정해져있다. 그런데 배열은 다음과 같이 동적으로 사이즈를 변경할 수 있다.

int size = 1000; //사용자가 입력한 값을 넣었다고 가정해보자.
new int[size]; //이 코드가 실행되는 시점에서 배열의 크기가 정해진다.
  • 기본형은 선언과 동시에 크기가 정해진다. 따라서 크기를 동적으로 바꾸거나 할 수는 없다. 반면에 앞서본 배열과 같은 참조형은 크기를 동적으로 할당할 수 있다. 예를 들어서 Scanner를 사용해서 사용자 입력에 따라 size변수의 값이 변하고, 생성되는 배열의 크기도 달라질 수 있다. 이런 것을 동적 메모리 할당이라고 한다. 기본형은 선언과 동시에 사이즈가 정적으로 정해지지만, 참조형을 사용하면 이처럼 동적으로 크기가 변해서 유연성을 제공할 수 있다.
  • 기본형은 사용할 값을 직접 저장한다. 반면에 참조형은 메모리에 저장된 배열이나 객체의 참조를 저장한다. 이로 인해 참조형은 더 복잡한 데이터 구조를 만들고 관리할 수 있다. 반면 기본형은 더 빠르고 메모리를 효율적으로 처리한다.

리펙토링

리펙토링(Refactoring)이란 기존의 코드 기능은 유지하면서 내부 구조를 개선하여 가독성을 높이고, 유지보수를 용이하게 하는 과정을 뜻한다. 이는 중복을 제거하고, 복잡성을 줄이며, 이해하기 쉬운 코드로 만들기 위해 수행된다. 리펙토링은 버그를 줄이고, 프로그램의 성능을 향상시킬 수도 있으며, 코드의 설계를 개선하는 데에도 도움이 된다. 쉽게 이야기해서 작동하는 기능은 똑같은데, 코드를 개선하는것을 리펙토링이라 한다.

배열 초기화

  1. 첫 번째 방법
    int [] students;
    students = new int[]{90, 80, 70, 60, 50};
  1. 두 번째 방법
int[] students = new int[]{90, 80, 70, 60, 50}; // 배열 변수 선언, 배열 생성과 초기화
  1. 세 번째 방법
int[] students = {90, 80, 70, 60, 50};

2차원 배열

2차원 배열은 int[][] arr = new int[2][3]와 같이 선언하고 생성한다. 그리고 arr[1][2]와 같이 사용하는데, 먼제 행 번호를 찾고, 그 다음에 열 번호를 찾으면 된다.

행은 영어로 row(로우), 열은 영어로 column(컬럼)이라 한다.

arr[행][열], arr[row][column]

2차원 배열 초기화

public static void main(String[] args) {
        // 2X3 2차원 배열을 만든다.
        int [][] arr = {
                {1,2,3,},
                {4,5,6}
        };

        for(int row = 0; row < arr.length; row++) {
            for(int column = 0; column < arr[row].length; column++) {
                System.out.print(arr[row][column] + " ");
            }
            System.out.println();
        }

    }

초기화

1차원 배열은 다음과 같이 초기화 한다.

{1, 2, 3}

2차원 배열은 다음과 같이 초기화 한다. 밖이 행이되고, 안이 열이 된다. 그런데 이렇게 하면 행열이 잘 안느껴진다.

{{1, 2, 3}, {4, 5, 6}}

이렇게 라인을 적절하게 넘겨주면 행과 열이 명확해진다. 따라서 코드를 더 쉽게 이해할 수 있다.

{

{1, 2, 3},

{4, 5, 6}

}

배열의 길이

  • arr.length 는 행의 길이를 뜻한다. 위 코드에서는 2가 출력된다.
    • {{},{}}를 생각해보면 arr 배열은, {},{} 2개의 배열 요소를 가진다.
  • arr[row].length는 열의 길이를 뜻한다. 여기서는 3이 출력된다.
    • arr[0]은 {1, 2, 3} 배열을 뜻한다. 이 배열에는 3개의 요소가 있다.
    • arr[1]은 {4, 5, 6} 배열을 뜻한다. 이 배열에는 3개의 요소가 있다.

향상된 for문

각각의 요소를 탐색한다는 의미로 for-each문 이라고도 많이 부른다. 향상된 for문은 배열을 사용할 때 기존 for문 보다 더 편리하게 사용할 수 있다.

향상된 for문 정의

    for(변수 : 배열 또는 컬렉션) {
        //배열 또는 컬렉션의 요소를 순회하면서 수행할 작업
        }
        //일반 for문
        for (int i = 0; i < numbers.length; i++) {
            int number = numbers[i];
            System.out.print(number + " ");
        }
        
        //향상된 for문, for-each문
        System.out.println();
        for (int number : numbers) {
            System.out.print(number + " ");
        }

일반 for문

먼저 일반 for문을 살펴보자. 배열에 있는 값을 순서대로 읽어서 number 변수에 넣고, 출력한다. 배열은 처음부터 끝까지 순서대로 읽어서 사용하는 경우가 많다. 그런데 배열의 값을 읽으려면 int i와 같은 인덱스를 탐색할 수 있는 변수를 선언해야 한다. 그리고 i < number.length와 같이 배열의 끝 조건을 지정해주어야 한다. 마지막으로 배열의 값을 하나 읽을 때 마다 인덱스를 하나씩 증가해야 한다.

개발자 입장에서는 그냥 배열을 순서대로 처음부터 끝까지 탐색하고 싶은데, 너무 번잡한 일을 해주어야 한다. 그래서 향상된 for문이 등장했다.

향상된 for문

for(int number : numbers) {
    System.out.println(number);
        }
  • 앞서 일반 for문과 동일하게 작동한다.
  • 향상된 for문은 배열의 인덱스를 사용하지 않고, 종료 조건을 주지 않아도 된다. 단순히 해당 배열을 처음부터 끝까지 탐색한다.
  • :의 오른쪽에 numbers와 같이 탐색할 배열을 선택하고, : 의 왼쪽에 int number와 같이 반복할 때마다 찾은 값을 저장할 변수를 선언한다. 그러면 배열의 값을 하나씩 꺼내서 왼쪽에 있는 number에 담고 for문을 수행한다. for문의 끝에 가면 다음 값을 꺼내서 number에 담고 for문을 반복 수행한다. numbers 배열의 끝에 도달해서 더 값이 없으면 for문이 완전히 종료된다.
  • 향상된 for문은 배열의 인덱스를 사용하지 않고도 배열의 요소를 순회할 수 있기 때문에 코드가 간결하고 가독성이 좋다.

향상된 for문을 사용하지 못하는 경우

향상된 for문에는 증가하는 인덱스 값이 감추어져 있다. 따라서 int i 와 같은 증가하는 인덱스 값을 직접 사용해야 하는 경우에는 향상된 for문을 사용할 수 없다.

    int i = 0;
    for(int number : numbers) {
        System.out.println("number" + i + "번의 결과는 : " +  number);
        i++;    
    }