배열((Array)란?
하나의 이름(배열명)으로 '같은 자료형' 데이터를 여러개 저장할 수 있는 메모리 구조이며 이때의 메모리는 연속적으로 생성된다.
배열은 크게 선형(Line)으로 생긴 1차원 배열, 1차원과 1차원이 합쳐진 2차원, 그리고 3차원 배열이 있다.
<1차원(선형) 배열>
1) 배열 선언
배열은 변수를 선언하는 방법에서 대괄호([ ])를 추가해주면 배열을 선언하는 구조로 이루어진다.
▲ 변수를 선언하는 방식에서 대괄호를 중간에 또는 끝에 삽입하는 식으로 넣어주면 배열을 선언하게 된다.
이때 arrNum이라는 배열명으로 int형의 배열을 선언하는 것으로 Stack영역에 arrNum이라는 이름으로 주소를 저장할 수 있는 메모리가 생기게 된다. 여기서 주소를 저장한다는 것은 실제 값을 저장하는 것이 아닌 실제 값이 저장되어 있는 곳의 주소를 저장한다는 것이다.
▲ 변수처럼 배열에 값을 바로 저장할 수 없다.
2) 메모리 할당
배열에 데이터를 넣기위해서는 메모리를 할당해주어야 하는데
메모리 할당이란? 실제 값을 저장할 수 있는 메모리를 heap영역에 생성하는 것을 말한다.
▲ new연산자를 사용하게 되면 heap영역에 실제 데이터를 저장할 수 있는 메모리를 생성하게되고 위의 경우 그 메모리는 각각 int형 메모리이다. 메모리 할당 시 대괄호안의 인자는 메모리의 크기(갯수)가 된다. 이후 heap영역에 생성된 int형 메모리는 고유의 주소를 가지게 되고 그 주소를 arrNum이라는 Stack영역에 생성된 메모리에 담기게 된다.
이때 arrNum은 주소를 통해 heap영역의 메모리를 '참조(reference)한다' 라고 하게된다.
이후 아래와 같이 코드를 찍어보면
아래와 같은 고유의 주소가 arrNum에 저장된 것을 볼 수 있다.
▲ 대괄호로 시작하는 것은 배열을 뜻하고 I는 int형, @는 at 으로 뒤의 나머지 주소를 참조한다는 뜻이다.
이제 배열의 선언과 메모리 힐당까지 했으면 heap영역의 메모리에 있는 데이터값으로 0이 저장되어 있을 것이다. 왜냐하면 배열은 초기화를 하지 않아도 해당 자료형의 기본값으로 설정이 되기 때문이다. 위에서 우리는 자료형으로 int를 사용했으니 기본값으로 0이 저장되어 있다.
실제 데이터값을 출력해보도록 하자.
▲ 보다시피 각각의 메모리에 데이터 값으로 0이 출력된다. 이는 int형이기 때문이고 만약 다른 종류의 자료형이라면
double은 0.0, boolean은 false, char는 ' '(빈값), 참조형은 null이 각각 기본값으로 저장이 될 것이다.
위에서 '배열명[숫자]'의 구조를 '배열요소명'이라고 하고 숫자는 배열의 index 즉, 위치를 나타내는 요소이다.
그러니까 arrNum[0]은 첫번째 메모리, arrNum[1]은 두번째 메모리, arrNum[2]는 세번째 메모리... 이런식으로 나간다.
배열에서 index는 항상 0부터 시작한다는 것을 인지하자. 또한 배열명[숫자] 즉, 배열요소명은 변수처럼 사용가능하다.
이제는 배열요소명을 변수처럼 사용하여 초기화 즉, 원하는 값을 넣어보도록 하자.
▲ 각각의 배열요소명을 변수처럼 사용하여 데이터 값을 넣어주었다. 즉, 초기화가 된 것이다. 꼭 순서대로 초기화 하지 않아도 되고, 기본값이 저장되어 있기때문에 꼭 초기화를 하지 않아도 된다. 확인을 해보면
▲ 원하는 데이터 값이 잘 입력된 것을 볼 수 있다.
만약 우리가 할당한 메모리의 크기를 벗어나게 초기화를 하면 어떻게 될까? 아래와 같이 초기화를 해보면
▲ complie error는 나지 않지만 실행 시 Run-Time error가 나게된다. 우리는 4번방까지밖에 만들지 않았기 때문에 5번방이 존재하지 않고 따라서 데이터 값을 저장할 수 없는 것이다.
배열은 서랍과 같은 개념이다. 하나의 서랍에는 하나의 데이터만을 저장할 수 있다. 하지만 우리가 항상 서랍이 몇개인지 알 수는 없을 것이다. 오히려 알지못하거나 바뀌는 경우가 더 많을 것이다. 학교의 학생수가 매년 바뀌고 우리는 그것을 미리 정확하게 알기 힘든 것과 마찬가지이다. 따라서 이럴때는 length라는 property를 이용할 수 있다.
▲ length를 이용해서 만일 배열의 크기가 달라지더라도 최초 메모리 할당부분의 값만 바꿔주면 나머지 코드에서 자동으로 변경되기 때문에 유지보수가 훨씬편해진다.
이제는 배열의 선언과 동시에 메모리 할당, 초기화를 해보자.
- 배열선언과 동시에 메모리 할당
▲ String형의 strArray라는 배열을 선언함과 동시에 메모리3개 즉, 크기가 3인 메모리를 할당하였다. 그리고 자동초기화 되었다. 위 예제의 배열은 String형이기 때문에 자동초기화되면서 각각의 index에 데이터값은 null이 저장된다.
- 배열선언과 동시에 초기화
▲ 중괄호({ })를 '배열 초기화자'라고 하고 heap에 있는 메모리에 바로 값을 넣게된다.
- 배열선언, 메모리할당 그리고 초기화를 동시에
▲ double형 배열 dbArr을 선언하고 new 를 사용해 메모리할당, 그리고 중괄호를 이용하여 초기화까지 한번에 시킬 수 있다.
이제 예제를 보면서 이해를 해보자. 그 전에 사전지식(?)을 깔고 진행하자.
- Scanner클래스의 메소드 정리 -
사용자의 입력을 받는 메소드에서 사용자에게 값을 받는다면 어떤 메소드를 사용했는가에 따라 동작방식이 다르다.
Ex) 사용자가 12(엔터)치면 버퍼에 1|2|'\r'|'\n'가 저장된다.
nextInt( ) : 버퍼에 있는 엔터값(\r\n)은 읽지 않는다. nextInt()는 숫자만 읽는다. 즉, 숫자 12만 반환.
nextLine( ) : 엔터값도 읽는다 하지만 엔터값을 제외한 부분만 반환한다.
= > nextLine( )은 무조건 '문자열'로 돌려준다.
즉 문자열 "12"반환 버퍼에는 엔터값이 존재하지 않는다
이제 사전지식을 깔고 예제를 보자.
예제1)
▲ 입력 받은 값을 변수에 저장하였다.
▲ 처음 학생수를 입력받을 때 sc.nextInt();로 입력받은 후 stream에 /r/n이 남아있기 때문에 sc.enxtLine();을 이용해서 버려준 다음 string형 names배열을 선언과 동시에 할당시켜주었다. 할당할 시 배열의 크기는 학생수가 저장되어 있는 변수를 사용하므로써 학생수가 변동될 경우에도 코드가 작동되도록 하였다.
예제2)
▲ int형의 jumsu라는 배열을 선언함과 동시에 초기화를 하였고, for문을 사용하여 총합과 평균을 구할 수 있다.
예제2-1)
▲ 배열과 for문, if문을 이용하여 배열에 저장된 값 중 최대값을 구할 수도 있다.
▲ class 기능을 사용하면 훨씬 간단하지만 class없이 오직 배열과 for문, if문으로만 코드를 짜보았다.
여기서도 이중 for문을 사용했으며 이유는 행렬과 같은 형태의 규칙이 보였기 때문이다. 또한 가장 큰 값을 배열 좌측으로 밀어내는 과정에서 각 배열데이터의 위치를 바꿔줘야하는데 jumsu[i]에다 jumsu[i+1]의 값을 옮겨버리면 jumsu[i]의 데이터가 사라지게 된다. 때문에 여기서는 임시로 데이터를 옮겨놓는 변수 temp을 사용하였다.
결과값을 출력해보면 아래와 같다.
'Java' 카테고리의 다른 글
[Java]method - type1(void형) (0) | 2022.03.02 |
---|---|
[Java]배열(Array) - 2차원 배열 (0) | 2022.03.02 |
[Java]break와 continue (0) | 2022.02.28 |
[Java]반복문(part.3- do~while문) (0) | 2022.02.28 |
[Java]반복문(part.2- while문) (0) | 2022.02.28 |