배열
배열
은 한 가지 타입에 대해서, 하나의 변수에 여러 개의 데이터를 넣을 수 있다.
로또 번호와 같이 데이터의 개수가 정해져 있을 경우 기본 자리수 6개에 보너스 번호 1개를 포함하여 총 7개의 자리를 미리 만들어 놓고 사용하면 된다
➡️기본형 자료형의 배열 선언 형식
int [] lottoNumbers;
int[] lottoNumbers;
int lottoNumbers[];
※주의 : 배열 변수를 정의할 때 대괄호 안에는 아무것도 써주면 안된다.
- 대괄호는 타입과 변수 사이에 위치해도 되고, 변수명 뒤에 위치해도 된다.
- 보통 첫번째에 있는 것과 같이 타입과 변수명 사이에 대괄호를 넣는 것을 권장한다.
➡️배열의 초기화
int [] lottoNumbers = new int[7];
- 배열을 선언할 때는 new를 써 준 후 타입 이름을 명시
- 대괄호 안에 해당 배경의 크기를 지정해 준다.
- 배열도 참조 자료형의 객체를 생성할 때 처럼 반드시 new를 써야한다. 배열도 참조 자료형이기 때문이다.(참고 꼭 new를 사용하여 정의해야 하는 것은 아니다. 예외도 있다.
➡️배열의 특징
- 배열의 순서는 0부터 시작한다.
public class ArrayLotto {
public static void main(String[] args) {
ArrayLotto array = new ArrayLotto();
}
public void init(){
int [] lottoNumbers = new int[7];
}
}
lottoNumbers라는 배열
0번 방 | 1번 방 | 2번 방 | 3번 방 | 4번 방 | 5번 방 | 6번 방 |
---|---|---|---|---|---|---|
public class ArrayLotto {
public static void main(String[] args) {
ArrayLotto array = new ArrayLotto();
array.init();
}
public void init(){
int [] lottoNumbers = new int[7];
lottoNumbers [0] = 5;
lottoNumbers [1] = 12;
lottoNumbers [2] = 23;
lottoNumbers [3] = 25;
lottoNumbers [4] = 38;
lottoNumbers [5] = 41;
lottoNumbers [6] = 2;
lottoNumbers [7] = 9;
}
}
실행 결과 : Error 메시지
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 7
이 메시지의 끝 부분에는 ArrayIndexOutOfBoundsException
이라는 말과 7이라는 숫자가 있다.
ArrayIndexOutOfBoundsException
의 의미는 배열(Array)
의 위치(Index)
를 벗어난(OutOfBountd)
예외(Exception)
가 발생했다. 라는 의미이다.
ArrayIndexOutOfBoundsException
는 배열에 값에 할당할 때 발생, 값을 참조할 때에도 발생한다.
배열의 기본값
- 기본 자료형 배열의 기본값은 각 자료형의 기본값과 동
public class ArrayInitValue {
public static void main(String[] args) {
ArrayInitValue array = new ArrayInitValue();
array.primitiveTypes();
System.out.println();
array.referenceTypes();
}
public void primitiveTypes(){
byte []byteArray = new byte[1];
short []shortArray = new short[1];
int []intArray = new int[1];
long []longArray = new long[1];
float []floatArray = new float[1];
double []doubleArray = new double[1];
char []charArray = new char[1];
boolean []booleanArray = new boolean[1];
System.out.println("byteArray[0] = " + byteArray[0]);
System.out.println("shortArray[0]= " + shortArray[0]);
System.out.println("intArray[0] = " + intArray[0]);
System.out.println("longArray[0] =" + longArray[0]);
System.out.println("floatArray[0] = " + floatArray[0]);
System.out.println("doubleArray[0] = " + doubleArray[0]);
System.out.println("charArray[0]= " + "[" + charArray[0] + "]");
System.out.println("booleanArray[0] = " + booleanArray[0]);
}
public void referenceTypes(){
String[] strings = new String[2];
ArrayInitValue[] array = new ArrayInitValue[2];
System.out.println("string[0] = " + strings[0]);
System.out.println("array[0] = " + array[0]);
}
}
결과 :
byteArray[0] = 0
shortArray[0]= 0
intArray[0] = 0
longArray[0] =0
floatArray[0] = 0.0
doubleArray[0] = 0.0
charArray[0]= [ ]
booleanArray[0] = false
string[0] = null
array[0] = null
public void referenceTypesSetValue(){
String[] strings = new String[2];
ArrayInitValue[] array = new ArrayInitValue[2];
strings[0] = "Please visit www.GodOfJava.com";
array[0] = new ArrayInitValue();
System.out.println("strings[0] =" + strings[0]);
System.out.println("strings[1] = " + strings[1]);
System.out.println("array[0] = " + array[0]);
System.out.println("array[1] = " + array[1]);
}
결과 :
strings[0] =Please visit www.GodOfJava.com
strings[1] = null
array[0] = main.Chapter07.ArrayInitValue@68837a77
array[1] = null
String[] strings = null;
위와 같이 선언한 다음에 값을 사용할 때에는 반드시 초기화를 하여 사용해야 한다는 점 기억하자 !
**※참고
ArrayInitValue 객체를 출력한 결과는 타입의 이름과 함께 @가 붙은 수수께끼의 답이 나올까 ? 참조 자료형은 public String toString()이라는 메소드를 만들어 줘야만 이러한 암호 같은 내용이 출력되지 않는다. toString()이라는 메소드를 만들어 주지 않으면 “타입이름@고유번호”
순으로 내용이 출력된다.**
배열을 그냥 출력 할 때
배열을 참조조자료형
이다.
➡️예제) 배열 그냥 출력할 때
public class ArrayPrint {
public static void main(String[] args) {
ArrayPrint array = new ArrayPrint();
array.printString();
}
private void printString() {
System.out.println("string = " + new String[0]);
System.out.println("array = " + new ArrayPrint[0]);
}
}
결과 :
string = [Ljava.lang.String;@2f7a2457
array = [Lmain.Chapter07.ArrayPrint;@6108b2d7
의미 파악하기
- [L : 가장 앞의 “[”는 해당 객체가 배열이라는 의미이고, L은 해당 배열은 참조 자료형이라는 의미
- java.lang.String: 해당 배열이 어떤 타입의 배열인지를 보여줌
- @2f7a2457 : 해당 배열의 고유 번호
참조형 자료형(Reference) |
---|
L |
➡️기본 자료형의 배열을 그냥 출력할 경우
public class ArrayPrint {
public static void main(String[] args) {
ArrayPrint array = new ArrayPrint();
array.printString();
array.printPrimitiveArray();
}
private void printString() {
System.out.println("string = " + new String[0]);
System.out.println("array = " + new ArrayPrint[0]);
}
private void printPrimitiveArray() {
System.out.println("byteArray = " + new byte[1]);
System.out.println("shortArray = " + new short[1]);
System.out.println("intArray = " + new int[1]);
System.out.println("longArray = " + new long[1]);
System.out.println("floatArray = " + new float[1]);
System.out.println("doubleArray = " + new double[1]);
System.out.println("charArray =" + new char[1]);
System.out.println("booleanArray =" + new boolean[1]);
}
}
결과 :
byteArray = [B@1554909b
shortArray = [S@6cd8737
intArray = [I@13969fbe
longArray = [J@3498ed
floatArray = [F@3d8c7aca
doubleArray = [D@21bcffb5
charArray =[C@668bc3d5
booleanArray =[Z@7a5d012c
➡️ “[” 다음에 알파벳은 해당 타입을 대표하는 문자이다.
- [B : byte
- [S : short
- [I : int
- [F : float
- [D : double
- [C : char
- [J : long
- [Z : boolean
boolean은 byte가 먼저 B를 갖고 있어서 Z로 표현하게되었다.
boolean | byte | char | double | float | int | long | short |
---|---|---|---|---|---|---|---|
Z | B | C | D | F | I | J | S |
배열을 선언하는 다른 방법
private void otherInit() {
int[] lottoNumbers = {5, 12, 23, 25, 38, 41, 2};
//int[] lottoNumbers2;
//lottoNumbers2 = {5,12,23,25,38,41,2}; // compile error
}
배열을 선언과 함께 초기화하려면..
- 중괄호 안에 각 위치에 해당하는 값들을 콤마(,)로 구분하여 나열”하면 된다.
- 중괄호를 닫은 다음에는 반드시 세미콜론(;)을 써줘야한다.
주석 처리 되어있는 compile error를 발생한다. 왜 그럴까?
- 중괄호를 사용하여 초기화 할 경우 반드시 한번에 변수 선언 및 초기화가 이루어져야만 한다.
➡️배열의 데이터를 추가할 때 콤마 사이의 줄 바꿈은 문제가 되지 않는다.
public void otherInit(){
int[] lottoNumbers = {5,
12,23,
25,38,41,2};
}
위와같은 방법으로 사용될 때
모든 배열에 들어가는 값들이 처음부터 정할 수 있는 상황이 되지 않는다.
배열에 들어가는 값이 계속 바뀔 수도 있고, 언제든지 변경이 가능하기 때문에 보통 “절대 변경되지 않는 값”
을 지정할 때 이렇게 중괄호로 선언하여 사용한다.
➡️예시) month(월)로 표시하는 것에 있어서 활용할 때
public class ArrayInitialize {
public static void main(String[] args) {
ArrayInitialize array = new ArrayInitialize();
System.out.println(array.getMonth(3));
}
public String getMonth(int monthInt){
String[] month = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "Number", "Novemeber", "December"};
return month[monthInt + 1];
}
}
➡️ 보통 month(월) 처럼 변하지 않는 값은 메소드 내에서 선언하여 사용하는 것보다는, 클래스의 변수로 선언하여 재사용성을 높이는 것이 좋다.
public class ArrayInitialize {
String[] month = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "Number", "Novemeber", "December"};
}
➡️ 하지만 getMonth() 라는 메소드에서만 이 month라는 배열을 사용한다면 반드시 메소드 밖으로 빼낼 필요는 없다.
이유 : ArrayInitalize
라는 클래스의 객체를 생성할 때마다 month라는 배열이 생성되기 때문이다.
클래스의 인스턴스 변수로 사용할지? 메서드 안에서 선언으로 사용할지?
- 사용의 빈도
- 어디서 사용하는지
얼마나 자주 사용하는지, 어디에서 사용하는지를 확인하여 메소드에서 선언하여 사용할지, 클래스의 인스턴스 변수로 선언하여 사용할지 결정하면 된다.
하지만…. 이걸 극복하기 위해서 나온 예약어가 있다
static 예약어
➡️ static
예약어를 사용할 예제
public class ArrayInitialize {
static String[] month = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "Number", "Novemeber", "December"};
}
static
을 사용하면 ArrayInitialize 클래스의 객체를 생성할 때마다 month 배열을 새로 생성하지 않아도 된다.
static이 붙어서 “클래스 변수"
가 되었다.
→ 배열의 선언 끝
2차원 배열
2차원 배열 생성 방법
➡️ 2차원 배열 선언
public void twoDimensionArray() {
int[][] twoDim;
twoDim = new int[2][3];
}
방법1.
int[] twoDim[];
방법2.
int twoDim[][];
추천하는 방법은 1차원 배열처럼 타입과 배열 변수명 사이에 대괄호들을 넣는 방법이다.
2차원 배열은
“배열의 배열"
을 의미함
※중요
1차원 배열은 int로 선언했다면 twoDim[0]는 int 값이다. 하지만 2차원 배열에서는 twoDim[0]는 int 값이 아니라 배열이다.
즉, twoDim[0][0]의 값이 int 값이다.
2차원 배열의 개수 선언
twoDim = new int[2][3];
그림과같이 2차원 배열이 생성된다. 2층으로 되어있고 한층에 3개의 집이 있는 복도식 아파트 같은 공간이 만들어 진다. 총 안에서 거주 할 수 있는 공간은 6개의 공간이다.
선언이 불가능한 경우
- 1차원 배열 크기 저장하지 않고 2차원 배열만 지정할 경우 → 불가능.
twoDim = new int[][2]; // <-- 불가능. 컴파일 에러 발생!
- 1차원 배열 크기 지정 하지않고, 2차원 배열도 지정하지 않을 경우 → 불가능.
twoDim= new int[][2] // <-- 불가능. 컴파일 에러 발생!
선언이 가능한 경우
- 1차원 크기만 저장하고 2차원 크기를 지정하지 않는 경우 → 가능하다.
twoDim = new int[2][]; // <-- 선언 가능
twoDim[0]와 twoDim[1], 두 개의 배열만 선언해 놓은 것이다.
twoDim[0] 배열의 크기는 어떻게되는 것일까 ? 정해주지 않아도 되는 것일까?
정답은 반드시 정해줘야 한다
가 답이다.
twoDim = new int[3];
twoDim = new int[2];
처음 선언한 2차원 배열(twoDim = new int[2][3])은 1차원 2차원의 크기가 고정되어 있었다.
하지만, 아래와 같이 선언하면 2차원 배열의 공간의 크기가 서로 다르게 지정할 수 있다.
중괄호를 이용한 2차원 배열선언
- 중괄호를 이용한 2차원 배열 선언
int[][] twoDim = {{ 1, 2, 3 }, {4,5,6}};
- 위의 한줄을 기존의 표현으로 했을 때
int[][] twoDim = new int[2][3];
twoDim[0][0] = 1;
twoDim[0][1] = 2;
twoDim[0][2] = 3;
twoDim[1][0] = 4;
twoDim[1][1] = 5;
twoDim[1][2] = 6;
배열의 길이는 어떻게 알 수 있을까?
배열의 이름에 .length
를 붙여주면 된다
ArrayLength
클래스에 printArrayLength()
라는 메소드를 만들어보자
public class ArrayLength {
public static void main(String[] args) {
ArrayLength array = new ArrayLength();
array.printArrayLength();
}
private void printArrayLength() {
int[] oneDim = new int[3];
int[][] twoDim = new int[4][2];
System.out.println(oneDim.length);
System.out.println(twoDim.length);
}
}
➡️ 결과
3
4
- 왜 두번째는
4
라는 크기가 나왔을 까?
2차원 배열의 경우 해당 배열의 크기를 알려달라고 하면 1차원 크기를 알려준다.
public void printArray(){
int[][] twoDim = {{1,2,3}, {4,5,6 }} ;
System.out.println("twoDim.length = " + twoDim.length);
System.out.println("twoDim[0].length =" + twoDim[0].length);
for (int oneLoop = 0; oneLoop < 2; oneLoop++) {
for (int twoLoop = 0; twoLoop < 3; twoLoop++) {
System.out.println("twoDim[" + oneLoop + "]"+ "[" + twoLoop + "] = " + twoDim[oneLoop][twoLoop] );
}
}
}
➡️ 결과
twoDim.length = 2
twoDim[0].length =3
twoDim[0][0] = 1
twoDim[0][1] = 2
twoDim[0][2] = 3
twoDim[1][0] = 4
twoDim[1][1] = 5
twoDim[1][2] = 6
for루프에서 oneLoop<2
와 twoLoop < 3
배열의 크기를 알고 있기 때문에 이렇게 썼다. 하지만 배열의 길이를 모를경우는? .length
를 사용하면 길이을 몰라도 배열의 길이만큼 for문이 돈다.
for (int oneLoop = 0; oneLoop < twoDim.length; oneLoop++) {
for (int twoLoop = 0; twoLoop < twoDim[oneLoop].length; twoLoop++) {
System.out.println("twoDim[" + oneLoop + "]"+ "[" + twoLoop + "] = " + twoDim[oneLoop][twoLoop] );
}
}
위와 같이 하면 배열의 크기가 가변적이라고 할지라도 정확하게 데이트럴 출력해 줄 수 있다. 하지만 이렇게 .length
를 사용하여 for 루프가 수행될 때마다 길이를 얻어오는 것은 성능적 측면에서 좋지 않다.
- 크기를 알아내는 변수를 할당하여 사용하는 것이 가장 효과적이다.
- 배열의 값을 for 루프의 조건에 직접 입력하는 하드코딩은 반드시 피해야만 한다.
int twoDimLength = twoDim.length;
for (int oneLoop = 0; oneLoop < twoDimLength; oneLoop++) {
int twoDimOneLength = twoDim[oneLoop].length;
for (int twoLoop = 0; twoLoop < twoDimOneLength; twoLoop++) {
System.out.println("twoDim[" + oneLoop + "]"+ "[" + twoLoop + "] = " + twoDim[oneLoop][twoLoop] );
}
}
배열을 위한 for 루프 - (for-each)
배열뿐만 아니라 자바에서 제공되는 Collection이라는 자료 구조를 처리할 때 for 루프를 보다 쉽게 사용할 JDK 5부터 개선된 부분이 있다.
- 개선된 for 루프 - (for-each)
for(타입이름 임시변수명 : 반복대상객체){
}
괄호 안에 콜론 앞에는 배열의 각 항목을 처리하기 위한 “타입이름”과 “임시 변수명”
을 지정해주고 콜론(:) 뒤에는 반복을 수행할 대상 객체(여기서는 배열)
가 위치한다.
- for-each의 이해를 돕는 예시
public class ArrayNewFor {
public static void main(String[] args) {
ArrayNewFor array = new ArrayNewFor();
array.newFor();
}
private void newFor() {
int[] oneDim = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int date: oneDim) {
System.out.println(date);
}
}
}
➡️ 앞서 했던 for문
int twoDimLength = twoDim.length;
for (int oneLoop = 0; oneLoop < twoDimLength; oneLoop++) {
int twoDimOneLength = twoDim[oneLoop].length;
for (int twoLoop = 0; twoLoop < twoDimOneLength; twoLoop++) {
System.out.println("twoDim[" + oneLoop + "]"+ "[" + twoLoop + "] = " + twoDim[oneLoop][twoLoop] );
}
}
➡️ new for문(for-each)
public void twoDimFor(){
int[][] twoDim = { {1, 2, 3}, {4, 5, 6}};
for (int[] dimArray : twoDim) { // 첫 번째
for (int date : dimArray) { // 두 번째
System.out.println(date);
}
}
}
첫 번째 for 루프 안의 소괄호를 보면 twoDim이라는 배열의 1차원 값은 배열이다. 그래서, int dimArray가 아니라, int[] dimArray로 지정했다. (int의 배열을 앞부분에 쓴 것을 꼭 기억해야 한다.)
두 번째 for 루프 안의 소괄호를 보면 dimArray 배열의 1차원 값이 int타입이기 때문에 int date라고 지정함.
위와 같이 for 루프를 사용하면 단점 1차원 배열과 2차원 배열의 위치를 알 수 없다는 것이다.
그 위치를 확인하려면? 해결 → 임시 변수를 두면된다.
public void twoDimForWithCounter(){
int[][] twoDim = {{1, 2, 3}, {4, 5, 6}};
int oneCounter = 0;
for (int[] dimArray : twoDim) {
int twoCounter = 0;
for (int date : dimArray) {
System.out.println(date);
twoCounter++;
}
oneCounter++;
}
}
- 정리
- 값만 처리하기 위한 배열 : for-each 사용하면 편리하다
- 배열의 위치(index) 정보도 같이 필요한 배열은 그냥 for문 을 사용하는 것이 더 편리
자바 실행할 때 원하는 값들을 넘겨주자.
public class ArrayMain{
public static void main(String[] args){
}
}
위 코드에서 main() 메소드의 매개 변수 args라는 String[] 타입의 배열이다.
흠…. 그러면 이 배열에는 값을 어떻게 전달할까 ?
public class ArrayMain {
public static void main(String[] args) {
if (args.length > 0) {
for (String arg : args) {
System.out.println(arg);
}
}
}
}
$ javac ArrayMain.java
$ java ArrayMain
$
결과 :
실행하면 아무런 결과가 출력되지 않는다.
- args매개변수를 넘길 때
$ java ArrayMain a b c d
a
b
c
d
$
위와 같이 클래스 이름 뒤에 공백으로 분리한 문자열을 나열하면 이 문자열들이 args라는 배열에 전달된다. 그래서 애플리 케이션이 시작할 때 전달해야 할 값들이 있다면, 이와 같은 방법을 사용하면 된다.