데이터 타입 분류
자바의 데이터 타입은 크게 기본 타입(primitive type)과 참조 타입(reference type)으로 분류됨
참조 타입이란 객체(object)의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스 타입이 있음
객체(object)
데이터와 메소드로 구성된 덩어리
객체 = 데이터(필드) + 메소드
기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 차이점은 저장되는 값
기본 타입 변수는 값 자체를 저장하고 있지만, 참조 타입 변수는 객체가 생성된 메모리 번지를 저장함
//기본 타입 변수
int age = 25;
double price = 100.5;
//참조 타입 변수
String name = "신용권";
String hobby = "독서";
변수들은 모두 스택(stack)이라는 메모리 영역에 생성됨
기본 타입 변수인 age와 price는 직접 값을 저장하고 있지만, 참조 타입 변수인 name과 hobby는 힙(heap) 메모리 영역의 String 객체 번지를 저장하고 이 번지를 통해 String 객체를 참조함
메모리 사용 영역
java 명령어로 JVM이 구동되면 JVM은 운영체제에서 할당받은 메모리 영역(RUntime Data Area)을 메소드 영역(Method Area), 힙 영역(Heap Area), 스택(Stack) 영역으로 구분해서 사용함
메소드 영역
메소드(Method) 영역은 바이트코드 파일을 읽은 내용이 저장되는 영역
클래스별로 상수, 정적 필드, 메소드 코드, 생성자 코드 등이 저장됨
힙 영역
힙(Heap) 영역은 객체가 생성되는 영역
객체의 번지는 메소드 영역과 스택 영역의 상수와 변수에서 참조할 수 있음
스택 영역
스택(Stack) 영역은 메소드를 호출할 때마다 생성되는 프레임(Frame)이 저장되는 영역
메소드 호출이 끝나면 프레임은 자동으로 제거됨
프레임 내부에는 로컬 변수 스택이 있는데, 여기에서 기본 타입 변수와 참조 타입 변수가 생성되고 제거됨
참조 타입 변수의 ==, != 연산
==, != 연산자는 변수의 값이 같은지 아닌지를 조사함
참조 타입 변수의 값은 객체의 번지이므로 참조 타입 변수의 ==, != 연산자는 번지를 비교하는 것이 됨
번지가 같다면 동일한 객체를 참조하는 것이고, 다르다면 다른 객체를 참조하는 것
//1과 2가 서로 다른 객체를 참조할 때의 연산
refvar1 == rafVar2 //false
refvar1 != refVar2 //true
//2와 3이 동일한 객체를 참조할 때의 연산
refVar2 == refVar3 //true
refVar2 != refVar3 //false
==, != 연산자로 객체를 비교하는 코드는 if 문에서 많이 사용
if(refVar2 == refVar3 {...} //2와 3이 같은 객체를 참조할 경우 if 블록 실행
package ch05.sec03;
public class ReferenceVariableCompareExample {
public static void main(String[] args) {
int[] arr1; //배열 변수 arr1 선언
int[] arr2; //배열 변수 arr2 선언
int[] arr3; //배열 변수 arr3 선언
arr1 = new int[] {1, 2, 3}; //배열 {1, 2, 3}을 생성해 arr1 변수에 대입
arr2 = new int[] {1, 2, 3}; //배열 {1, 2, 3}을 생성해 arr2 변수에 대입
arr3 = arr2; //배열 변수 arr2 값을 배열 변수 arr3에 대입
System.out.println(arr1 == arr2); //false, 1과 2가 같은 배열을 참조하지 않음
System.out.println(arr2 == arr3); //true, 2와 3이 동일한 배열을 참조함
}
}
null과 NullPointerException
참조 타입 변수는 아직 번지를 저장하고 있지 않다는 뜻으로 null(널) 값을 가질 수 있음
null도 초기값으로 사용할 수 있기에 null로 초기화된 참조 변수는 스택 영역에 생성됨
String refVar1 = "자바";
String refvar2 = null;
//참조 타입 변수가 null 값을 가지는지 확인하기
refVar1 == null //false
refVar1 != null //true
refVar2 == null // true
rafVar2 != null // false
자바는 프로그램 실행 도중에 발생하는 오류를 예외(Exception)라고 부름
참조 변수를 사용하면서 가장 많이 발생하는 예외 중 하나는 NullPointerException
변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려 할 때 이 예외가 발생함
int[] intArray = null;
intArray[0] = 10; //NullPointerException
//intArray가 참조하는 배열 객체가 없으므로 10을 저장할 수 없기에 오류 발생
String str = null;
System.out.println("총 문자 수: " + str.length()); //NullPointerException
//str 변수가 참조하는 String 객체가 없으므로 문자열 길이를 구할 수 없기에 오류 발생
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
}
}
NullPointerException이 발생하면 예외가 발생된 곳에서 null인 상태의 참조 변수가 사용되고 있음을 알아야 함
이것을 해결하려면 참조 변수가 객체를 정확히 참조하도록 번지를 대입해야 함
경우에 따라 참조 타입 변수에 일부러 null을 대입하는데, 변수에 null을 대입하면 번지를 잃게 되므로 더 이상 객체를 사용할 수 없게 됨
String hobby = "여행";
hobby = null;
어떤 변수에서도 객체를 참조하지 않으면 해당 객체는 프로그램에서 사용할 수 없는 객체가 됨
즉 힙 메모리에는 있지만, 위치 정보를 모르기에 사용할 수 없게 됨
자바는 이러한 객체를 쓰레기로 취급하고, 쓰레기 수집기(Garbage Collector)를 실행시켜 자동으로 제거함
객체를 제거하는 유일한 방법은 객체의 모든 참조를 없애는 것
String hobby = "여행";
data = "영화"
//hobby 변수에 "영화"가 대입되면서 이전 번지를 잃어버리고
//"여행"에 해당하는 String 객체는 쓰레기 객체가 됨
package ch05.sec04;
public class GarbageObjectExample {
public static void main(String[] args) {
String hobby = "여헹";
hobby = null; //"여행"에 해당하는 String 객체를 쓰레기로 만듦
String kind1 = "자동차";
String kind2 = kind1; //kind1 변수에 저장돼 있는 번지를 kind2 변수에 대입
kind1 = null; //"자동차"에 해당하는 String 객체는 쓰레기가 아님
//kind2 변수가 "자동차" String 객체를 여전히 참조하고 있기 때문!
System.out.println(kind2); //자동차
}
}
문자열(String) 타입
자바의 문자열은 String 객체로 생성됨
String name; //String 타입 변수 name 선언
name = "홍길동"; //name 변수에 문자열 대입
String hobby = "여행" //String 타입 벼수 hobby를 선언하고 문자열 대입
문자열 비교
자바는 문자열 리터럴이 동일하다면 String 객체를 공유하도록 설계됨
String name1 = "홍길동";
String name2 = "홍길동";
//name1과 name2 변수에는 동일한 String 객체의 번지가 저장됨
String 변수에 문자열 리터럴을 대입하는 것이 일반적이지만, new 연산자로 직접 String 객체를 생성하고 대입할 수도 있음
new 연산자는 새로운 객체를 만드는 연산자로 객체 생성 연산자라고 함
이 경우 각자의 객체 번지를 가질 수 있음
String name1 = new String("홍길동");
String name2 = new String("홍길동");
//name1과 name2 변수는 서로 다른 String 객체의 번지를 가지게 됨
그렇기에 문자열 리터럴로 생성하느냐 new 연산자로 생성하느냐에 따라 비교 연산자의 결과가 달라짐
String name1 = "홍길동";
String name2 = "홍길동";
String name3 = new String("홍길동");
name1 == name2 // true
name1 == name3 //false
//동일한 String 객체든 다른 String 객체든 상관없이 내부 문자열만 비교할 경우
//String 객체의 equals() 메소드를 사용함
boolean result = str1.equals(str2) //문자열이 같은지 검사
boolean result != str1.equals(str2) //문자열이 다른지 검사
package ch05.sec05;
public class EqualsExample {
public static void main(String[] args) {
String strVar1 = "홍길동";
String strVar2 = "홍길동";
if(strVar1 == strVar2) {
System.out.println("strVar1과 strVar2는 참조가 같음");
} else {
System.out.println("strVar1과 strVar2는 참조가 다름");
}
if(strVar1.equals(strVar2)) {
System.out.println("strVar1과 strVar2는 문자열이 같음");
}
// strVar1과 strVar2는 참조가 같음
// strVar1과 strVar2는 문자열이 같음
String strVar3 = new String("홍길동");
String strVar4 = new String("홍길동");
if(strVar3 == strVar4) {
System.out.println("strVar3과 strVar4는 참조가 같음");
} else {
System.out.println("strVar3과 strVar4는 참조가 다름");
}
if(strVar3.equals(strVar4)) {
System.out.println("strVar3과 strVar4는 문자열이 같음");
}
// strVar3과 strVar4는 참조가 다름
// strVar3과 strVar4는 문자열이 같음
}
}
String 변수에 빈 문자열(””)을 대입하고 equals() 메소드를 사용할 수 있음
package ch05.sec05;
public class EmptyStringExample {
public static void main(String[] args) {
String hobby = "";
if(hobby.equals("")) {
System.out.println("hobby 변수가 참조하는 String 객체는 빈 문자열");
}
}
}
문자 추출
문자열에서 특정 위치의 문자를 얻고 싶다면 charAt() 메소드 사용
charAt() 메소드는 매개 값으로 주어진 인덱스의 문자를 리턴함
여기서 인덱스란 ()에서부터 ‘문자열의 길이-1’까지의 번호를 말함
String subject = "자바 프로그래밍";
char cahrValue = subject.charAt(3); //프
package ch05.sec05;
public class CharAtExample {
public static void main(String[] args) {
String ssn = "9506241230123";
char sex = ssn.charAt(6);
switch(sex) {
case '1', '3':
System.out.println("남자입니다.");
break;
case '2', '4':
System.out.println("여자입니다.");
break;
}
// 남자입니다.
}
}
문자열 길이
문자열에서 문자의 개수를 얻고 싶다면 length() 메소드를 사용
STring subject = "자바 프로그래밍";
int length = subject.length(); //8, 문자열 길이는 공백 포함
package ch05.sec05;
public class LengthExample {
public static void main(String[] args) {
String ssn = "9506251230123";
int length = ssn.length();
if(length == 13) {
System.out.println("주민등록번호 자릿수가 맞습니다.");
} else {
System.out.println("주민등록번호 자릿수가 틀립니다.");
}
// 주민등록번호 자릿수가 맞습니다.
}
}
문자열 대체
문자열에서 특정 문자열을 다른 문자열로 대체하고 싶다면 replace() 메소드를 사용
replace() 메소드는 기존 문자열은 그대로 두고, 대체한 새로운 문자열을 리턴함
String oldSTr = "자바 프로그래밍";
String newStr = oldStr.replace("자바", "JAVA");
String 객체의 문자열은 변경이 불가한 특성을 갖기 때문에 replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전히 새로운 문자열임
package ch05.sec05;
public class ReplaceExample {
public static void main(String[] args) {
String oldStr = "자바 문자열은 불변입니다. 자바 문자열은 String입니다.";
String newStr = oldStr.replace("자바", "JAVA");
System.out.println(oldStr); //자바 문자열은 불변입니다. 자바 문자열은 String입니다.
System.out.println(newStr); //JAVA 문자열은 불변입니다. JAVA 문자열은 String입니다.
}
}
문자열 잘라내기
문자열에서 특정 위치의 문자열을 잘라내어 가져오고 싶다면 substring() 메소드를 사용
메소드 | 설명 |
substring(int beginIndex) | beginIndex에서 끝까지 잘라내기 |
substring(int beginIndex, int endIndex) | beginIndex에서 endIndex 앞까지 잘라내기 |
String snn = "880815-1234567";
String firstNum = ssn.substring(0, 6); //880815
String secondNum = ssn.substring(7); //1234567
package ch05.sec05;
public class SubStringExample {
public static void main(String[] args) {
String ssn = "880815-1234567";
String firstNum = ssn.substring(0, 6); //0~5까지 출력
System.out.println(firstNum); //880815
String secondNum = ssn.substring(7); //7~끝까지 출력
System.out.println(secondNum); //1234567
}
}
문자열 찾기
문자열에서 특정 문자열의 위치를 찾고자 할 때에는 indexOf() 메소드를 사용
indexOf() 메소드는 주어진 문자열이 시작되는 인덱스를 리턴함
String subject = "자바 프로그래밍";
int index = subject.indexOf("프로그래밍"); //index 변수에 3이 저장됨
만약 주어진 문자열이 포함되어 있지 않으면 indexOf() 메소드는 -1을 리턴함
String subject = "자바";
int index = subject.indexOf("프로그래밍");
if(index == -1) {
//포함되어 있지 않은 경우
} else {
//포함되어 있는 경우
}
주어진 문자열이 단순히 포함되어 있는지만 조사하고 싶다면 contains() 메소드를 사용하면 편리함
원하는 문자열이 포함되어 있으면 contains() 메소드는 true를 리턴하고, 그렇지 않으면 false를 리턴함
boolean result = subject.contains("프로그래밍");
package ch05.sec05;
public class IndexOfContainsExample {
public static void main(String[] args) {
String subject = "자바 프로그래밍";
int location = subject.indexOf("프로그래밍");
System.out.println(location);
String substring = subject.substring(location); //3
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() 메소드를 사용함
String board = "번호, 제목, 내용, 글쓴이"ㅣ
String[] arr = board.split(", ");
//split() 메소드를 호출할 때 쉼표를 제공하면 분리된 문자열로 구성된 배열(array)을 얻을 수 있음
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();
// 번호: 1
// 제목자바학습
// 내용: 참조 타입 String을 학습합니다
// 성명: 홍길동
// for 문을 이용한 읽기
for(int i=0; i<tokens.length; i++) {
System.out.println(tokens[i]);
}
// 1
// 자바학습
// 참조 타입 String을 학습합니다
// 홍길동
}
}
배열(Array) 타입
변수는 하나의 값만 저장할 수 있기에 저장해야 할 값의 수가 많아지면 그만큼 많은 변수가 필요함
따라서 많은 양의 값을 효율적으로 다루기 위해 배열이 필요함
배열은 연속된 공간에 값을 나열시키고, 각 값에 인덱스(index)를 부여해놓은 자료구조
인덱스는 대괄호 []와 함께 사용하여 각 항목의 값을 읽거나 저장하는 데 사용됨
int sum = 0;
for(int i=0; i<30; i++) {
sum += score[i];
}
int avg = sum / 30;
//학생 30명의 성적 평균값을 구하는 코드
배열의 특징
배열은 같은 타입의 값만 관리함
배열의 길이는 늘리거나 줄일 수 없음
배열 변수 선언
배열을 사용하기 위해선 우선 배열 변수를 선언해야 함
타입[] 변수; //변수 선언법 1, 주로 사용함
int[] intArray;
double[] doubleArray;
String[] strArray;
타입 변수[]; //변수 선언법 2
int intArray[];
double doubleArray[];
String strArray[];
배열 변수는 참조 변수임
배열도 객체이므로 힙 영역에 생성되고 배열 변수는 힙 영역의 배열 주소를 저장함
참조할 배열이 없다면 배열 변수도 null로 초기화할 수 있음
만약 배열 변수가 null 값을 가진 상태에서 변수[인덱스]로 값을 읽거나 저장하게 되면 NullPointerException이 발생함
타입[] 변수 = null;
값 목록으로 배열 생성
배열에 저장될 값의 목록이 있다면, 아래와 같이 간단하게 배열을 생성할 수 있음
타입[] 변수 = { 값0, 값1, 값2, 값3, ... };
중괄호 {}는 나열된 값들을 항목으로 가지는 배열을 힙에 생성하고, 번지를 리턴함
배열 변수는 리턴된 번지를 저장함으로써 참조가 이루어짐
String[] season = { "Spring", "Summer", "Fall", "Winter" };
season[1] = "여름"
//"Spring"은 season[0], "Summer"는 season[1], "Fall"은 season[2], "Winter"는 season[4]
package ch05.sec06;
public class ArrayCreateByValueListExample {
public static void main(String[] args) {
// 배열 변수 선언과 배열 생성
String[] season = { "Spring", "Summer", "Fall", "Winter" };
// 배열의 항목값 읽기
System.out.println(season[0]); //Spring
System.out.println(season[1]); //Summer
System.out.println(season[2]); //Fall
System.out.println(season[3]); //Winter
// 인덱스 1번 항목의 값 변경
season[1] = "여름";
System.out.println(season[1]); //여름
System.out.println();
// 배열 변수 선언과 배열 생성
int[] scores = { 83, 90, 87};
// 총합과 평균 구하기
int sum = 0;
for(int i=0; i<3; i++) {
sum += scores[i];
}
System.out.println("총합: " + sum); //260
double avg = (double) sum / 3;
System.out.println("평균 " + avg); //86.66666666666667
}
}
중괄호 {}로 감싼 값의 목록을 배열 변수에 대입할 때 주의할 점은, 배열 변수를 미리 선언한 후에는 값 목록을 변수에 대입할 수 없다는 것!
타입[] 변수;
변수 = { 값0, 값1, 값2, 값3, ...}; //컴파일 에러!!
배열 변수를 선언한 시점과 값 목록이 대입되는 시점이 다르다면 아래와 같이 new 타입[]을 중괄호 앞에 붙여주면 됨
타입은 변수를 선언할 때 사용한 타입과 동일하게 주면 됨
변수 = new 타입[] { 값0, 값1, 값2, 값3, ...};
String[] names = null;
names = new String[] { "신용권", "홍길동", "김자바" };
//String 배열 변수 names를 선언한 후에 값 목록을 대입할 경우에는
//new String[]을 중괄호 앞에 붙여줘야함
메소드의 매개변수가 배열 타입일 경우에도 마찬가지
//메소드 선언
void printItem(int[] scores) { ... }
//잘못된 메소드 호출
printItem( {95, 85, 90} ); //컴파일 에러!
//올바은 메소드 호출
printItem( new int[] {95, 85, 90} );
//매개변수로 int[] 배열 타입을 갖는 printItem() 메소드를 호출할 때
//매개값으로 중괄호로 감싼 값 목록을 주면 컴파일 에러가 발생
//매개변수가 이미 선언되어 있고, 호출 시 값 목록을 제공하므로 new를 사용해야함
메소드 선언과 호출
메소드 선언은 이름 있는 중괄호 블록을 만드는 것이고,
메소드 호출은 해당 이름으로 중괄호 블록을 실행하는 것
package ch05.sec06;
public class ArrayCreateByValueListExample2 {
public static void main(String[] args) {
int[] scores; //배열 변수 선언
scores = new int[] { 83, 90, 87 }; //배열 변수에 배열을 대입
int sum1 = 0;
for(int i=0; i<3; i++) { //배열 항목의 총합을 구하고 출력
sum1 += scores[i];
}
System.out.println("총합: " + sum1); //260
printItem( new int[] {83, 90, 87} ); //배열을 매개값으로 주고, printItem() 메소드 호출
}
public static void printItem( int[] scores) { //printItem() 메소드 선언
for(int i=0; i<3; i++) { //매개변수가 참조하는 배열의 항목을 출력
System.out.println("score[" + i + "]: " + scores[i]);
}
// score[0]: 83
// score[1]: 90
// score[2]: 87
}
}
new 연산자로 배열 생성
값의 목록은 없지만 향후 값들을 저장할 목적으로 배열을 미리 생성할 수도 있음
타입[] 변수 = new 타입[길이]; //길이는 배열이 저장할 수 있는 항목 수
new 연산자는 해당 길이의 배열을 생성하고 배열의 번지를 리턴하기에 배열 변수에 대입할 수 있음
이미 배열 변수가 선언된 후에도 대입 가능
타입[] 변수 = null;
변수 = new 타입[길이];
int[] intArray = new int[5]; //길이 5인 int[]배열을 생성하고, 배열 번지를 intArray 변수에 대입
new 연산자로 배열을 처음 생성하면 배열 항목은 기본값으로 초기화됨
정소 배열은 0, 실수 배열은 0.0, 논리 배열은 false, 참조 배열은 null로 초기화됨
데이터 타입 | 초기값 | |
기본타입 | byte[] | 0 |
char[] | ‘\u0000’ | |
short[] | 0 | |
int[] | 0 | |
long[] | 0L | |
float[] | 0.0F | |
double[] | 0.0 | |
boolean[] | false | |
참조 타입 | 클래스[] | null |
인터페이스[] | null |
int[] scores = new int[30] //배열 항목은 모두 0으로 초기화
String[] names = new String[30]; //배열 항목은 모두 null로 초기화
배열을 생성하고 난 후 특정 인덱스 항목을 새로운 값으로 변경하는 방법은 동일함
변수[인덱스] = 값;
package ch05.sec06;
public class ArrayCreateByNewExample {
public static void main(String[] args) {
int[] arr1 = new int[3]; //배열 변수 선언과 배열 생성
for(int i=0; i<3; i++) { //배열 항목의 초기값 출력
System.out.print("arr[" + i + "]: " + arr1[i] + ", ");
}
System.out.println();
arr1[0] = 10; //배열 항목의 값 변경
arr1[1] = 20;
arr1[2] = 30;
for(int i=0; i<3; i++) { //배열 항목의 변경 값 출력
System.out.print("arr[" + i + "]: " + arr1[i] + ", ");
}
System.out.println("\\n");
double[] arr2 = new double[3]; //배열 변수 선언과 배열 생성
for(int i=0; i<3; i++) { //배열 항목의 초기값 출력
System.out.print("arr2[" + i + "]: " + arr2[i] + ", ");
}
System.out.println();
arr2[0] = 0.1; //배열 항목의 값 변경
arr2[1] = 0.2;
arr2[2] = 0.3;
for(int i=0; i<3; i++) { //배열 항목의 변경 값 출력
System.out.print("arr2[" + i + "]: " + arr2[i] + ", ");
}
System.out.println("\\n");
String[] arr3 = new String[3]; //배열 변수 선언과 배열 생성
for(int i=0; i<3; i++) { //배열 항목의 초기값 출력
System.out.print("arr3[" + i + "]: " + arr3[i] + ", ");
}
System.out.println();
arr3[0] = "1월"; //배열 항목의 값 변경
arr3[1] = "2월";
arr3[2] = "3월";
for(int i = 0; i<3; i++) {
System.out.print("arr3[" + i + "]: " + arr3[i] + ", ");
}
// arr[0]: 0, arr[1]: 0, arr[2]: 0,
// arr[0]: 10, arr[1]: 20, arr[2]: 30,
//
// arr2[0]: 0.0, arr2[1]: 0.0, arr2[2]: 0.0,
// arr2[0]: 0.1, arr2[1]: 0.2, arr2[2]: 0.3,
//
// arr3[0]: null, arr3[1]: null, arr3[2]: null,
// arr3[0]: 1월, arr3[1]: 2월, arr3[2]: 3월,
}
}
배열 길이
배열의 길이란 배열에 저장할 수 있는 항목 수를 말함
코드에서 배열의 길이를 얻으려면 도트(.) 연산자를 사용해서 참조하는 배열의 length 필드를 읽으면 됨
배열변수.length;
배열의 length 필드는 읽기만 가능하므로 값을 변경할 수는 없음
intArray.length = 10; //컴파일 에러 발생!
package ch05.sec06;
public class ArrayLengthExample {
public static void main(String[] args) {
int[] scores = { 84, 90, 96 }; //배열 변수 선언과 배열 대입
int sum = 0; //배열 항목의 총합 구하기
for(int i=0; i<scores.length; i++) { //length는 3
sum += scores[i];
}
System.out.println("총합: " + sum); //270
double avg = (double) sum / scores.length;
System.out.println("평균: " + avg); //90.0
}
}
위의 for 문 조건식에서 < 연산자를 사용한 이유는 배열의 마지막 인덱스는 배열 길이보다 1이 적기 때문
인덱스를 초과해서 사용하면 ArrayIndexOutOfBoundsException이 발생함
다차원 배열
배열 항목에는 또 다른 배열이 대입될 수 있는데 이러한 배열을 다차원 배열이라고 부름
변수[1차원인덱스][2차원인덱스]...[N차원인덱스]
변수[0][0][0] //값1
변수[0][1][0] //값3
변수[1][0][1] //값6
값 목록으로 다차원 배열 생성
값 목록으로 다차원 배열을 생성하려면 배열 변수 선언 시 타입 뒤에 대괄호[]를 차원의 수만큼 붙이고, 값 목록도 마찬가지로 차원의 수만큼 중괄호를 중첩시킴
타입[][] 변수 = {
{값1, 값2, ...}, //1차원 배열의 0인덱스
{값3, 값4, ...}, //1차원 배열의 1인덱스
...
};
//두 반의 학생 점수를 저장하는 배열
int[][] scores = {
{ 80, 90, 96 }, //1차원 배열의 0인덱스-첫번쨰 반 성적
{ 76, 88 } //1차원 배열의 1인덱스-두번쨰 반 성적
};
int score = scores[0][2]; //96, 0번 인덱스의 2번
int socre = scores[1][1]; //88, 1번 인덱스의 1번
//반의 개수는 1차원 배열의 길이(2)와 동일하고, 각 반의 학생 수는 2차원 배열의 길이(3, 2)와 동일
scores.length //반의 수-2
scores[0].length //첫번째 반의 학생 수-3
scores[1].length //두번째 반의 학생 수-2
package ch05.sec07;
public class MultidimensionalArrayByValueListExample {
public static void main(String[] args) {
int[][] scores = { //2차원 배열 생성
{ 80, 90, 96 },
{ 76, 88 }
};
System.out.println("1차원 배열 길이(반의 수): " + scores.length); //2
System.out.println("2차원 배열 길이(첫번째 반의 학생 수): " + scores[0].length); //3
System.out.println("2차원 배열 길이(두번째 반의 학생 수): " + scores[1].length); //2
// 첫번째 반의 세번째 학생의 점수
System.out.println(scores[0][2]); //96
// 두번째 반의 두번째 학생의 점수
System.out.println(scores[1][1]); //88
// 첫번째 반의 평균 점수
int class1Sum = 0;
for(int i=0; i<scores[0].length; i++) {
class1Sum += scores[0][i];
}
double class1Avg = (double) class1Sum / scores[0].length;
System.out.println("첫번쨰 반의 평균 점수: " + class1Avg); //88.66666666666667
// 두번째 반의 평균 점수
int class2Sum = 0;
for(int i=0; i<scores[1].length; i++) {
class2Sum += scores[1][i];
}
double class2Avg = (double) class2Sum / scores[1].length;
System.out.println("두번째 반의 평균 점수: " + class2Avg); // 82.0
// 전체 학생의 평균 점수
int totalStudent = 0;
int totalSum = 0;
for(int i=0; i<scores.length; i++) { //반의 수만큼 반복
totalStudent += scores[i].length; //반의 학생 수 합산
for(int k=0; k<scores[i].length; k++) { //해당 반의 학생 수만큼 반복
totalSum += scores[i][k]; //학생 점수 합산
}
}
double totalAvg = (double) totalSum / totalStudent;
System.out.println("전체 학생의 평균 점수: " + totalAvg); //86.0
}
}
new 연산자로 다차원 배열 생성
new 연산자로 다차원 배열을 생성하려면 배열 변수 선언 시 타입 뒤에 대괄호 []를 차원의 수만큼 붙이고, new 타입 뒤에도 차원의 수만큼 대괄호[]를 작성하면 됨
마지막 차원의 항목의 값은 초기값을 가지는데, 정수 타입은 0, 실수 타입은 0.0, 논리 타입은 false, 참조 타입은 null이 됨
타입[][] 변수 = new 타입[1차원수][2차원수];
//두 반의 학생 점수들을 저장하는 2차원 int 배열
//아래와 같이 생성하면 2차원 배열의 길이는 모두 3이고 항목들은 0으로 초기화됨
int[][] scores = new [2][3];
//두 반의 학생 이름을 저장하는 2차원 String 배열
//2차원 배열의 길이는 모두 3이고 항목들은 null로 초기화됨
String[][] names = new String[2][3];
//두 반의 학생 수가 다를 경우 2차원 배열의 길이를 다르게 줄 수 있음
//1차원 배열의 길이를 2로해서 배열 객체를 우선 생성하고, 각각의 항목 값으로 길이가 다른 2차원 배열을 대입
int [][] scores = new int[2][];
scores[0] = new int[3]; //첫번째 반의 학생 수 3명
score[1] = new int[2]; //두번째 학생 수 2명
package ch05.sec07;
public class MultidimensionalArrayByNewExample {
public static void main(String[] args) {
// 각 반의 학생 수가 3명으로 동일할 경우 점수 저장을 위한 2차원 배열 생성
int[][] mathScores = new int[2][3];
// 배열 항목 초기값 출력
for(int i=0; i<mathScores.length; i++) { //반의 수만큼 반복
for(int k=0; k<mathScores[i].length; k++) { //해당 반의 학생 수만큼 반복
System.out.println("mathScores[" + i + "][" + k + "]: " +
mathScores[i][k]);
}
}
System.out.println();
// 배열 항목 값 변경
mathScores[0][0] = 80;
mathScores[0][1] = 83;
mathScores[0][2] = 85;
mathScores[1][0] = 86;
mathScores[1][1] = 90;
mathScores[1][2] = 92;
// 전체 학생의 수학 평균 구하기
int totalStudent = 0;
int totalMathSum = 0;
for(int i=0; i<mathScores.length; i++) { //반의 수만큼 반복
totalStudent += mathScores[i].length; //반의 학생 수 합산
for(int k=0; k<mathScores[i].length; k++) { //해당 반의 학생 수만큼 반복
totalMathSum += mathScores[i][k]; //학생 점수 합산
}
}
double totalMathAvg = (double) totalMathSum / totalStudent;
System.out.println("전체 학생의 수학 평균 점수: " + totalMathAvg);
System.out.println();
// 각 반의 학생 수가 다를 경우 점수 저장을 위한 2차원 배열 생성
int[][] englishScores = new int[2][];
englishScores[0] = new int[2];
englishScores[1] = new int[3];
// 배열 항목 초기값 출력
for(int i=0; i<englishScores.length; i++) { //반의 수만큼 반복
for(int k=0; k<englishScores[i].length; k++) { //해당 반의 학생 수만큼 반복
System.out.println("englishScores[" + i + "][" + k + "]: " +
englishScores[i][k]);
}
}
System.out.println();
// 배열 항목 값 변경
englishScores[0][0] = 90;
englishScores[0][1] = 91;
englishScores[1][0] = 92;
englishScores[1][1] = 93;
englishScores[1][2] = 94;
// 전체 학생의 영어 평균 구하기
totalStudent = 0;
int totalEnglishSum = 0;
for(int i=0; i<englishScores.length; i++) { //반의 수만큼 반복
totalStudent += englishScores[i].length; //반의 학생 수 합산
for(int k=0; k<englishScores[i].length; k++) { //해당 반의 학생 수만큼 반복
totalEnglishSum += englishScores[i][k];
}
}
double totalEnglishAvg = (double) totalEnglishSum / totalStudent;
System.out.println("전체 학생의 영어 평균 점수: " + totalEnglishAvg);
// mathScores[0][0]: 0
// mathScores[0][1]: 0
// mathScores[0][2]: 0
// mathScores[1][0]: 0
// mathScores[1][1]: 0
// mathScores[1][2]: 0
//
// 전체 학생의 수학 평균 점수: 86.0
//
// englishScores[0][0]: 0
// englishScores[0][1]: 0
// englishScores[1][0]: 0
// englishScores[1][1]: 0
// englishScores[1][2]: 0
//
// 전체 학생의 영어 평균 점수: 92.0
}
}
객체를 참조하는 배열
기본 타입(byte, char, short, int, long, float, double, boolean) 배열은 각 항목에 값을 직접 저장하지만, 참조 타입(클래스, 인터페이스) 배열은 각 항목에 객체의 번지를 저장항
//String 타입의 배열을 생성하고 각 항목에 문자열 대입
//String[] 배열의 항목은 String 변수와 동일하게 참조 타입 변수로 취급
String[] strArray = new String[3];
strArray[0] = "Java";
strArray[1] = "C++";
atrArray[2] = "C#";
//==, != 연산자는 배열 항목이 참조하는 객체가 같은 객체인지 다른 객체인지 확인할 수 있음
//문자열만 비교할 때는 equals() 메소드를 사용
//languages[0]과 [1]은 동일한 번지에 저장되지만
//[2]는 new 연산자로 생성된 String 객체가 대입되므로 다른 번지가 저장됨
String[] languages = new String[3];
languages[0] = "Java";
languages[1] = "Java";
languages[2] = new String("Java")
System.out.pringln( langguages[0] == languages[1] ); //true, 같은 객체 참조
System.out.pringln( langguages[0] == languages[2] ); //false, 다른 객체 참조
System.out.pringln( langguages[0].equals(anguages[2]) ); //true, 문자열이 동일
package ch05.sec08;
public class ArrayReferenceObjectExample {
public static void main(String[] args) {
String[] strArray = new String[3];
strArray[0] = "Java";
strArray[1] = "Java";
strArray[2] = new String("Java");
System.out.println( strArray[0] == strArray[1] ); //true, 같은 객체 참조
System.out.println( strArray[0] == strArray[2] ); //false, 다른 객체 참조
System.out.println( strArray[0].equals(strArray[2]) ); //true, 문자열이 동일
}
}
배열 복사
배열은 한 번 생성하면 길이를 변경할 수 없음
더 많은 공간이 필요하다면 더 큰 길이의 배열을 새로 만들고 이전 배열로부터 항목들을 복사해야 함
가장 기본적인 복사 방법은 for 문을 이용해서 항목을 하나씩 읽고 새로운 배열에 저장하는 것
package ch05.sec09;
public class ArrayCopyByForExample {
public static void main(String[] args) {
int[] oldIntArray = { 1, 2, 3 }; //길이 3인 배열
int[] newIntArray = new int[5]; //길이 5인 배열을 새로 생성
// 배열 항목 복사
for(int i=0; i<oldIntArray.length; i++) {
newIntArray[i] = oldIntArray[i];
}
// 배열 항목 출력, 복사되지 않은 항목은 0(int배열의 항목 초기값)
for(int i=0; i<newIntArray.length; i++) {
System.out.print(newIntArray[i] + ", "); //1, 2, 3, 0, 0,
}
}
}
배열 복사를 위해 좀 간단한 방법은 System의 arraycopy() 메소드를 사용하는 것
System.arraycopy(Object src, int srcPos, Object dest, intdestPos, int length);
//(원본 배열, 원본 배열 복사 시작 인덱스, 새 배열, 새 배열 붙여넣기 시작 인덱스, 복사 항목 수)
System.arraycopy(arr1, 0, arr2, 0, arra.length);
//원본 배열 arr1의 모든 항목을 arr2의 항목에 복사
package ch05.sec09;
public class ArrayCopyExample {
public static void main(String[] args) {
String[] oldStrArray = { "java", "array", "copy" }; //길이 3인 배열
String[] newStrArray = new String[5]; //길이 5인 배열을 새로 생성
// 배열 항목 복사
System.arraycopy(oldStrArray, 0, newStrArray, 0, oldStrArray.length);
// 배열 항목 출력, 복사되지 않은 부분은 null
for(int i=0; i<newStrArray.length; i++) {
System.out.print(newStrArray[i] + ", "); //java, array, copy, null, null,
}
}
}
배열 항목 반복을 위한 향상된 for문
자바는 배열 및 컬렉션을 좀 더 쉽게 처리항 목적으로 아래와 같은 for 문은 제공함
카운터 변수와 증감식을 사용하지 않고, 항목의 개수만큼 반복한 후 자동으로 for문을 빠져나감
for( 타입 변수 : 배열 ) {
실행문;
}
//배열에서 가져올 항목이 있을 경우 변수에 항목을 저장하고 실행문을 실행
//가져올 항목이 없으면 for 문을 종료
package ch05.sec10;
public class AdvancedForExample {
public static void main(String[] args) {
int[] scores = { 95, 71, 84, 93, 87 }; //배연 변수 선언과 배열 생성
// 배열 항목 전체 합 구하기
int sum = 0;
for(int score : scores) { //5항목이 한 번씩 score 변수에
sum = sum + score; //저장되고 sum에 누적됨(반복 횟수: 5)
}
System.out.println("점수 총합= " + sum); //430
// 배열 항목 전체 평균 구하기
double avg = (double) sum / scores.length;
System.out.println("점수 평균= " + avg); //86.0
}
}
main() 메소드의 String[] 매개변수 용도
자바 프로그램을 실행하기 위해 지금까지 main() 메소드를 작성했는데, 여기에서 문자열 배열 형태인 String[] args 매개변수가 왜 필요할까?
윈도우의 명령 프롬프트나 맥OS의 터미널에서 프로그램을 실행할 때는 요구하는 값이 있을 수 있음
예를 들어 두 수를 입력받고 덧셈을 수행하는 Sum 프로그램은 실행할 때 아래와 같이 두 수를 요구할 수 있음
java Sum 10 20
공백으로 구분된 10과 20은 문자열로 취급되며 String[] 배열의 항목 값으로 구성됨
그리고 main() 메소드 호출 시 매개값으로 전달됨
{ "10", "20" }; //main() 메소드 호출 시 args로 전달됨
public static void main(String[] args) { ... }
main() 메소드 중괄호 {} 내에서 문자열 “10”과 “20”은 아래와 같이 얻을 수 있음
String x = args[0];
String y = args[1];
문자열 “10”과 “20”을 int 타입으로 변환하려면 아래와 같이 강제 타입 변환을 함
int x = Integer.parseInt(args[0]);
int y = Integer.parseInt(args[1]);
Sum을 실행할 때 몇 개의 값이 입력되었는지 확인하려면 main() 메소드에서 배열의 length 필드를 읽으면 됨
두 개의 값이 입력되지 않았다면 아래와 같이 출력 메시지를 보여줄 수도 있음
if(args.length != 2) {
System.out.println("실행 시 두 개의 값이 필요합니다.");
}
만약 아래와 같이 값을 주지 않고 실행하면 args.length는 0이 됨
java Sum
package ch05.sec11;
public class MainStringArrayArgument {
public static void main(String[] args) {
if(args.length != 2) { //입력된 데이터 개수가 2개가 아닐 경우
System.out.println("프로그램 입력값 부족");
System.exit(0); //프로그램 강제 종료
}
String strNum1 = args[0]; //첫번째 데이터 얻기
String strNum2 = args[1]; //두번째 데이터 얻기
int num1 = Integer.parseInt(strNum1); //문자열을 정수로 변환
int num2 = Integer.parseInt(strNum2);
int result = num1 + num2;
System.out.println(num1 + " + " + num2 + " = " + result);
}
}
위의 코드를 이클립스에서 입력값을 주고 실행하려면 Run Configurations의 Arguments에 가서 Program arguments 입력란에 값을 입력하면 됨
명령 프롬프트나 터미널에서 입력값 주기
윈도우 명형 프롬프트나 맥OS의 터미널에서 입력값을 주고 실행하고 싶다면 cd 명령을 사용해서 ‘thisisjava’ 디렉토리 밑에 있는 bin 폴더까지 이동 후 아래와 같이 java 명령어를 실행하면 됨
java ch05.sec11.MainStringArrayArgument 10 20
열거(Enum) 타입
데이터 중에는 요일(7개의 값), 계절(4개의 값)과 같이 몇 가지로 한정된 값을 갖는 경우가 있음
이와 같이 한정된 값을 갖는 타입을 열거 타입(enumeration type)이라고 함
열거 타입을 사용하기 위해선 먼저 열거 타입 이름으로 소스 파일(.java)을 생성하고 한정된 값을 코드로 정의해야 함
열거 타입 이름은 첫 문자를 대문자로 하고 캐멀(camel) 스타일로 지어주는 것이 관례
Week.java
Member.java
ProductKind.java
package ch05.sec12;
public enum Week { //열거 타입 이름 Week
MONDAY, //열거 상수 목록(한정된 값 목록)
TUESDAY,
WEDNESDAY,
THURDAY,
FRIDAY,
SATURDAY,
SUNDAY,
}
열거 상수는 열거 타입으로 사용할 수 있는 한정된 값을 말함
관례적으로 알파벳으로 정의하며, 모두 대문자로 작성함
만약 열거 상수가 여러 단어로 구성될 경우 단어와 단어 사이를 언더바(_)로 연결
public enum LoginResult {
LOGIN_SECCESS,
LOGIN_FAILES
}
열거 타입도 하나의 데이터 타입이므로 변수를 선언하고 사용해야 함
Week today;
Week reservationDay;
열거 타입 변수에는 열거 상수를 대입할 수 있는데, ‘열거 타입. 열거 상수’ 형태로 작성함
Week today = Week.SUNDAY;
열거 타입은 참조 타입이므로 null도 대입할 수 있음
Week birthday = null;
열거 변수의 값이 특정 열거 상수인지 비교할 땐 ==와 != 연산자를 사용
Week today = Week.SUNDAY;
today == Week.SUNDAY //true
컴퓨터의 날짜 및 요일, 시간을 얻을 때는 Calendar를 이용
Calendar now = Calendar.getInstance(); //Calender 객체 얻기
int year = now.get(Calendar.YEAR); //연
int month = now.get(Calendar.MONTH) + 1; //월(1~12)
int day = now.get(Calendar.DAY_OF_MONTH); //알
int week = now.get(Calendar.DAY_OF_WEEK); //요일(1~7)
int hour = now.get(Calendar.HOUR); //시간
int minute = now.get(Calendar.MINUTE); //분
int second = now.get(Calendar.SECOND); //초
package ch05.sec12;
import java.util.Calendar;
public class WeekExample {
public static void main(String[] args) {
Week today = null; //Weel 타입 변수 today 선언
Calendar cal = Calendar.getInstance(); //Calendar 어 ㄷ기
int week = cal.get(Calendar.DAY_OF_WEEK); //오늘의 요일 얻기(1~7)
// 숫자를 열거 상수로 변환해서 변수에 대입
switch(week) {
case 1: today = Week.SUNDAY ; break;
case 2: today = Week.MONDAY ; break;
case 3: today = Week.TUESDAY ; break;
case 4: today = Week.WEDNESDAY ; break;
case 5: today = Week.THURDAY ; break;
case 6: today = Week.FRIDAY ; break;
case 7: today = Week.SATURDAY ; break;
}
// 열거 타입 변수를 사용
if(today == Week.SUNDAY) {
System.out.println("일요일에는 축구를 합니다.");
} else {
System.out.println("열심히 자바를 공부합니다.");
}
// 열심히 자바를 공부합니다.
}
}
확인 문제
package ch05;
public class Test1 {
public static void main(String[] args) {
// for 문을 이용해 배열 항목에서 최대값을 출력하는 코드
int max = 0;
int[] array = { 1, 5, 3, 8, 2 };
for(int i=0; i<array.length; i++) {
if(max<array[i]) {
max = array[i];
}
}
System.out.println(max);
}
}
package ch05;
public class Test2 {
public static void main(String[] args) {
// 중첩 for 문을 이용해 배열 항목의 전체 합과 평균을 출력하는 코드
int[][] array = {
{95, 86},
{83, 92, 96},
{78, 83, 93, 87, 88}
};
int sum = 0;
double avg = 0.0;
int count = 0;
for(int i=0; i<array.length; i++) {
for(int j=0; j<array[i].length; j++) {
sum += array[i][j];
count++;
}
}
avg = (double) sum / count;
System.out.println(sum); //총합 881
System.out.println(avg); //평균 88.1
}
}
package ch05;
import java.util.Scanner;
public class Test3 {
public static void main(String[] args) {
// 키보드로부터 학생 수와 각 학생들의 점수를 입력받고
// while문과 Scanner의 nextLine() 메소드를 이용해
// 최고 점수와 평균 점수를 출력하는 코드
Scanner scanner = new Scanner(System.in);
boolean run = true;
int studentNum = 0;
int[] scores = null;
while(run) {
System.out.println("----------");
System.out.println("1.학생수 | 2.점수입력 | 3.점수리스트 | 4.분석 | 5.종료");
System.out.println("----------");
System.out.print("선택> ");
int selectNum = scanner.nextInt(); //입력받은 숫자와 studentNum과 일치시키기위해 int로 선언
if(selectNum == 1) {
System.out.print("학생수>");
studentNum = scanner.nextInt();
scores = new int[studentNum];
} else if(selectNum == 2) {
for(int i=0; i<scores.length; i++) {
System.out.print("scores[" + i + "]> ");
scores[i] = scanner.nextInt();
}
} else if(selectNum == 3) {
for(int i=0; i<scores.length; i++) {
System.out.println("scores[" + i + "]> " + scores[i]);
}
} else if(selectNum == 4) {
int max = 0;
int sum = 0;
for(int i=0; i<scores.length; i++) {
max = (max<scores[i])? scores[i] : max; //최고점수 고르기
sum += scores[i];
}
double avg = sum / studentNum;
System.out.println("최고 점수: " + max);
System.out.println("평균 점수: " + avg);
} else if(selectNum == 5) {
run = false;
}
}
System.out.println("프로그램 종료");
}
}
'공부기록 > 자바' 카테고리의 다른 글
Chapter 07. 상속 (1) | 2023.02.06 |
---|---|
Chapter 06. 클래스 (0) | 2022.12.18 |
Chapter 04. 조건문과 반복문 (0) | 2022.11.22 |
Chapter 03. 연산자 (0) | 2022.11.21 |
Chapter 02. 변수와 타입 (0) | 2022.11.21 |
댓글