12. 자바 API 클래스(Java API Class) - 1
1. 키워드
java.lang
패키지Object
클래스String
클래스와 불변 클래스(Immutable Class)StringBuffer
클래스와 가변 클래스(Mutable Class)Math
클래스Wrapper
클래스, 박싱(Boxing), 언박싱(UnBoxing)Enum
클래스와 열거체(Enumeration Type)
2. Object
클래스
1) java.lang
패키지
java.lang
패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합이다.- 따라서 자바에서는
java.lang
패키지의 클래스들은import
문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있다.
2) java.lang.Object
클래스
java.lang
패키지 중에서도 가장 많이 사용되는 클래스는 바로Object
클래스이다.Object
클래스는 모든 자바 클래스의 최고 조상 클래스가 된다.- 따라서 자바의 모든 클래스는
Object
클래스의 모든 메서드를 바로 사용할 수 있다. - 이러한
Object
클래스는 필드를 가지지 않으며, 총 11개의 메서드만으로 구성되어 있다.
3) toString()
메서드
toString()
메서드는 해당 인스턴스에 대한 정보를 문자열로 반환한다.- 이때 반환되는 문자열은 클래스 이름과 함께 구분자로
@
이 사용되며, 그 뒤로 16진수 해시 코드(Hash Code)가 추가된다. - 16진수 해시 코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스마다 모두 다르게 반환된다.
- 다음 예제는
toString()
메서드를 이용하여 인스턴스의 정보를 출력하는 예제이다.
Car car01 = new Car();
Car car02 = new Car();
System.out.println(car01.toString());
System.out.println(car02.toString());
// Car@15db9742
// Car@6d06d69c
Note
- 자바에서
toString()
메서드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있다.
4) equals()
메서드
equals()
메서드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여, 그 결과를 반환한다.- 이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나
false
를 반환하게 된다.
- 다음 예제는
equals()
메서드를 이용하여 두 인스턴스를 서로 비교하는 예제이다.
Car car01 = new Car();
Car car02 = new Car();
System.out.println(car01.equals(car02)); // false
car01 = car02;
System.out.println(car01.equals(car02)); // true
Note
- 자바에서
equals()
메서드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있다.
5) clone()
메서드
clone()
메서드는 해당 인스턴스를 복제하여, 새로운 인스턴스를 생성해 반환한다.- 하지만
Object
클래스의clone()
메서드는 단지 필드의 값만을 복사하므로, 필드의 값이 배열이나 인스턴스면 제대로 복제할 수 없다. - 따라서 이러한 경우에는 해당 클레스에서
clone()
메서드를 오버라이딩하여, 복제가 제대로 이루어지도록 재정의해야 한다. - 이러한
clone()
메서드는 데이터의 보호를 이유로Cloneable
인터페이스를 구현한 클래스의 인스턴스만이 사용할 수 있다.
- 다음 예제는
clone()
메서드를 이용하여 인스턴스를 복제하는 예제이다.
import java.util.*;
class Car implements Cloneable {
private String modelName;
① private ArrayList<String> owners = new ArrayList<String>();
public String getModelName() {
return this.modelName;
}
public void setModelname(String modelName) {
this.modelName = modelName;
}
public ArrayList getOwners() {
return this.owners;
}
public void setOwners(String ownerName) {
this.owners.add(ownerName);
}
@Override
public Object clone() {
try {
② Car clonedCar = (Car) super.clone();
③ // clonedCar.owners = (ArrayList) owners.clone();
return clonedCar;
④ } catch (CloneNotSupportedException ex) {
ex.printStackTrace();
return null;
}
}
}
class Test {
public static void main(String[] args) {
⑤ Car car01 = new Car();
car01.setModelname("아반떼");
car01.setOwners("홍길동");
⑥ System.out.println(
"Car01: " + car01.getModelName() + ", " + car01.getOwners() + "\n"
);
⑦ Car car02 = (Car) car01.clone();
⑧ car02.setOwners("이순신");
⑨ System.out.println(
"Car01: " + car01.getModelName() + ", " + car01.getOwners()
);
⑩ System.out.println(
"Car02: " + car02.getModelName() + ", " + car02.getOwners()
);
}
}
// Car01: 아반떼, [홍길동]
//
// Car01: 아반떼, [홍길동, 이순신]
// Car02: 아반떼, [홍길동, 이순신]
- 위 예제의 ②번 라인에서는 부모 클래스의
clone()
메서드를 호출하여clone()
메서드를 오버라이딩하고 있다. - ⑤번 라인에서는
Car
클래스의 인스턴스인car01
을 생성하고, ⑦번 라인에서는 오버라이딩한clone()
메서드를 호출하여 복제를 수행하고 있다. - 하지만 ②번 라인처럼
clone()
메서드를 재정의하면, 필드의 값이 ①번 라인처럼 인스턴스일 때는 제대로 된 복제를 수행할 수 없다. - ⑧번 라인에서는 복제된 인스턴스의
car02
의owners
필드에 새로운 값을 하나 추가한다. - 하지만 ⑨번 라인의 실행 결과를 보면, ⑦번 라인의 결과와는 달리 원본 인스턴스의
car01
의owners
필드에도 새로운 값이 추가되었음을 확인할 수 있다. - 이처럼 단순히 부모 클래스의
clone()
메서드를 호출하여clone()
메서드를 재정의하면, 배열이나 인스턴스인 필드는 복제되는 것이 아닌 해당 배열이나 인스턴스를 가리키는 주소값만이 복제되는 것이다. - 따라서 정확한 복제를 위해서는 ③번 라인처럼 배열이나 인스턴스인 필드에 대해서는 별도로
clone()
메서드를 구현하여 호출해야 한다.
- 다음 예제는 ③번 라인의 주석을 해제하고 실행한 예제이다.
import java.util.*;
class Car implements Cloneable {
private String modelName;
private ArrayList<String> owners = new ArrayList<String>();
public String getModelName() {
return this.modelName;
}
public void setModelname(String modelName) {
this.modelName = modelName;
}
public ArrayList getOwners() {
return this.owners;
}
public void setOwners(String ownerName) {
this.owners.add(ownerName);
}
@Override
public Object clone() {
try {
Car clonedCar = (Car) super.clone();
clonedCar.owners = (ArrayList) owners.clone();
return clonedCar;
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
return null;
}
}
}
class Test {
public static void main(String[] args) {
Car car01 = new Car();
car01.setModelname("아반떼");
car01.setOwners("홍길동");
System.out.println(
"Car01: " + car01.getModelName() + ", " + car01.getOwners() + "\n"
);
Car car02 = (Car) car01.clone();
car02.setOwners("이순신");
System.out.println(
"Car01: " + car01.getModelName() + ", " + car01.getOwners()
);
System.out.println(
"Car02: " + car02.getModelName() + ", " + car02.getOwners()
);
}
}
// Car01: 아반떼, [홍길동]
//
// Car01: 아반떼, [홍길동]
// Car02: 아반떼, [홍길동, 이순신]
3. String
클래스
1) java.lang.String
클래스
- C언어에서는 문자열을
char
형 배열로 표현하지만, 자바에서는 문자열을 위한String
이라는 클래스를 별도로 제공한다. String
클래스에는 문자열과 관련된 작업을 할 때 유용하게 사용할 수 있는 다양한 메서드가 포함되어 있다.- 이러한
String
클래스는java.lang
패키지에 포함되어 제공된다. String
인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없다.- 이러한 객체를 자바에서는 불변 객체(Immutable Object)라고 한다.
- 즉, 자바에서
+
(덧셈) 연산자를 이용하여 문자열 결합을 수행하면, 기존 문자열의 내용이 변경되는 것이 아니라 내용이 합쳐진 새로운String
인스턴스가 생성되는 것이다.
2) charAt()
메서드
charAt()
메서드는 해당 문자열의 특정 인덱스에 해당하는 문자를 반환한다.- 만약 해당 문자열의 길이보다 큰 인덱스나 음수를 전달하면,
IndexOutOfBoundsException
오류가 발생한다.
- 다음 예제는 문자열의 각 문자를
charAt()
메서드를 이용하여 하나씩 출력하는 예제이다.
String str = new String("Java");
System.out.println("원본 문자열: " + str);
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i) + " ");
}
System.out.println("\ncharAt() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java
// J a v a
// charAt() 메서드 호출 후 원본 문자열: Java
3) compareTo()
메서드
compareTo()
메서드는 해당 문자열을 인수로 전달된 문자열과 사전 편찬 순으로 비교한다.- 이 메서드는 문자열을 비교할 때 대소문자를 구분하여 비교한다.
- 만약 두 문자열이 같다면
0
을 반환하며, 해당 문자열이 인수로 전달된 문자열보다 작으면 음수를, 크면 양수를 반환한다. - 만약 문자열을 비교할 때 대소문자를 구분하지 않기를 원한다면,
compareToIgnoreCase()
메서드를 사용하면 된다.
- 다음 예제는
compareTo()
메서드와compareToIgnoreCase()
메서드를 이용하여 두 문자열을 비교하는 예제이다.
String str = new String("abcd");
System.out.println("원본 문자열: " + str);
System.out.println(str.compareTo("bcef"));
System.out.println(str.compareTo("abcd"));
System.out.println(str.compareTo("Abcd"));
System.out.println(str.compareToIgnoreCase("Abcd"));
System.out.println("compareTo() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: abcd
// -1
// 0
// 32
// 0
// compareTo() 메서드 호출 후 원본 문자열: abcd
4) concat()
메서드
concat()
메서드는 해당 문자열의 뒤에 인수로 전달된 문자열을 추가한 새로운 문자열을 반환한다.- 만약 인수로 전달된 문자열의 길이가
0
이면, 해당 문자열을 그대로 반환한다.
- 다음 예제는
concat()
메서드를 이용하여 두 문자열을 연결하는 예제이다.
String str = new String("Java");
System.out.println("원본 문자열: " + str);
System.out.println(str.concat("수업"));
System.out.println("concat() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java
// Java수업
// concat() 메서드 호출 후 원본 문자열: Java
5) indexOf()
메서드
indexOf()
메서드는 해당 문자열에서 특정 문자나 문자열이 처음으로 등장하는 위치의 인덱스를 반환한다.- 만약 해당 문자열에 전달된 문자나 문자열이 포함되어 있지 않으면
-1
을 반환한다.
- 다음 예제는
indexOf()
메서드를 이용하여 특정 문자나 문자열이 처음 등장하는 위치의 인덱스를 찾는 예제이다.
String str = new String("Oracle Java");
System.out.println("원본 문자열: " + str);
System.out.println(str.indexOf('o'));
System.out.println(str.indexOf('a'));
System.out.println(str.indexOf("Java"));
System.out.println("indexOf() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Oracle Java
// -1
// 2
// 7
// indexOf() 메서드 호출 후 원본 문자열: Oracle Java
- 위의 예제처럼
indexOf()
메서드는 문자나 문자열을 찾을 때 대소문자를 구분한다.
6) trim()
메서드
trim()
메서드는 해당 문자열의 맨 앞과 맨 뒤에 포함된 모든 공백 문자를 제거해 준다.
- 다음 예제는
trim()
메서드를 이용하여 문자열에 포함된 띄어쓰기와 탭 문자를 제거하는 예제이다.
String str = new String(" Java ");
System.out.println("원본 문자열: " + str);
System.out.println(str + '|');
System.out.println(str.trim() + '|');
System.out.println("trim() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java
// Java |
// Java|
// trim() 메서드 호출 후 원본 문자열: Java
7) toLowerCase()
와 toUpperCase()
메서드
toLowerCase()
메서드는 해당 문자열의 모든 문자를 소문자로 변환시켜준다.- 또한,
toUpperCase()
메서드는 해당 문자열의 모든 문자를 대문자로 변환시켜준다.
- 다음 예제는
toLowerCase()
메서드와toUpperCase()
메서드를 이용하여 문자열의 대소문자를 변경하는 예제이다.
String str = new String("Java");
System.out.println("원본 문자열: " + str);
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
System.out.println("두 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java
// java
// JAVA
// 두 메서드 호출 후 원본 문자열: Java
4. StringBuffer
클래스
1) java.lang.StringBuffer
클래스
String
클래스의 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없다.- 하지만
StringBuffer
클래스의 인스턴스는 그 값을 변경할 수도 있고, 추가할 수도 있다. - 이를 위해
StringBuffer
클래스는 내부적으로 버퍼(Buffer)라고 하는 독립적인 공간을 가진다. - 버퍼 크기의 기본값은 16개의 문자를 저장할 수 있는 크기이며, 생성자를 통해 그 크기를 별도로 설정할 수도 있다.
- 하지만 인스턴스 생성 시 사용자가 설정한 크기보다 언제나 16개의 문자를 더 저장할 수 있도록 여유있는 크기로 생성된다.
+
(덧셈) 연산자를 이용해String
인스턴스의 문자열을 결합하면, 내용이 합쳐진 새로운String
인스턴스를 생성한다.- 따라서 문자열을 많이 결합하면 결합할수록 공간의 낭비뿐만 아니라 속도 또한 매우 느려지게 된다.
- 하지만
StringBuffer
인스턴스를 사용하면 문자열을 바로 추가할 수 있으므로, 공간의 낭비도 없으며 속도도 매우 빨라진다. - 이러한
StringBuffer
클래스는java.lang
패키지에 포함되어 제공된다.
2) 불변 클래스(Immutable Class)와 가변 클래스(Mutable Class)
String
클래스와 같이 인스턴스가 한 번 생성되면 그 값을 변경할 수 없는 클래스를 불변 클래스라고 한다.- 반대로
StringBuffer
클래스와 같이 자유롭게 인스턴스의 값을 변경할 수 있는 클래스를 가변 클래스라고 한다. String
클래스와 같은 불변 클래스는StringBuffer
클래스의append()
나insert()
메서드와 같이 값을 변경하는set()
메서드를 포함하지 않는다.- 이렇게 불편하기만할 것 같은 불변 클래스를 사용하는 이유는 멀티 스레드 환경에서 객체가 변화되는 상황이라면 불변 인스턴스를 사용하는 것이 좀 더 신뢰할 수 있는 코드를 작성할 수 있기 때문이다.
- 즉, 하나의 객체에 접근하면서 각각의 객체가 서로 영향을 주어서는 안 되는 경우에 불변 인스턴스를 사용하면 값이 변하지 않는다는 점이 보장된다.
3) append()
메서드
append()
메서드는 인수로 전달된 값을 문자열로 변환한 후, 해당 문자열의 마지막에 추가한다.- 이 메서드는
String
클래스의concat()
메서드와 같은 결과를 반환하지만, 내부적인 처리 속도가 훨씬 빠르다.
- 다음 예제는
append()
메서드를 이용하여 한 문자열에 다른 문자열을 추가하는 예제이다.
StringBuffer str = new StringBuffer("Java");
System.out.println("원본 문자열: " + str);
System.out.println(str.append("수업"));
System.out.println("append() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java
// Java수업
// append() 메서드 호출 후 원본 문자열: Java수업
4) capacity()
메서드
capacity()
메서드는StringBuffer
인스턴스의 현재 버퍼 크기를 반환한다.
- 다음 예제는
capacity()
메서드를 이용하여StringBuffer
인스턴스의 현재 버퍼 크기를 알아보는 예제이다.
StringBuffer str01 = new StringBuffer();
StringBuffer str02 = new StringBuffer("Java");
System.out.println(str01.capacity()); // 16
System.out.println(str02.capacity()); // 20
- 위의 예제처럼 길이가
4
인 문자열로StringBuffer
인스턴스를 생성하면, 기본적으로 생성되는 여유 버퍼 크기인16
에 문자의 길이인4
를 더한 총20
개의 문자를 저장할 수 있는 버퍼가 생성되는 것을 확인할 수 있다.
5) delete()
메서드
delete()
메서드는 전달된 인덱스에 해당하는 부분 문자열을 해당 문자열에서 제거한다.- 또한,
deleteCharAt()
메서드를 사용하면 특정 위치의 문자 한 개만을 제거할 수도 있다.
- 다음 예제는
delete()
메서드를 이용하여 해당 문자열의 특정 부분을 제거하는 예제이다.
StringBuffer str = new StringBuffer("Java Oracle");
System.out.println("원본 문자열: " + str);
① System.out.println(str.delete(4, 8));
System.out.println("delete() 메서드 호출 후 원본 문자열: " + str);
System.out.println(str.deleteCharAt(1));
System.out.println("deleteCharAt() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java Oracle
// Javacle
// delete() 메서드 호출 후 원본 문자열: Javacle
// Jvacle
// deleteCharAt() 메서드 호출 후 원본 문자열: Jvacle
- 위 예제의 ①번 라인에서는
delete()
메서드를 사용하여 해당 문자열에서 인덱스가4
인 위치의 문자부터7
인 위치의 문자까지를 삭제하고 있다. - 이처럼
delete()
메서드는 첫 번째 매개변수로 전달된 인덱스부터 두 번째 매개변수로 전달된 인덱스 바로 앞의 문자까지를 삭제하는 메서드이다.
6) insert()
메서드
insert()
메서드는 인수로 전달된 값을 문자열로 변환한 후, 해당 문자열의 지정된 인덱스 위치에 추가한다.- 이때 전달된 인덱스가 해당 문자열의 길이와 같으면,
append()
메서드와 같은 결과를 반환한다.
- 다음 예제는
insert()
메서드를 이용하여 한 문자열 중간에 다른 문자열을 삽입하는 예제이다.
StringBuffer str = new StringBuffer("Java Java!!");
System.out.println("원본 문자열: " + str);
① System.out.println(str.insert(4, "Script"));
System.out.println("insert() 메서드 호출 후 원본 문자열: " + str);
// 원본 문자열: Java Java!!
// JavaScript Java!!
// insert() 메서드 호출 후 원본 문자열: JavaScript Java!!
- 위 예제의 ①번 라인에서는
insert()
메서드를 사용하여 해당 문자열에서 인덱스가4
인 위치부터 두 번째 매개변수로 전달된 문자열을 추가하고 있다.
5. Math
클래스
1) java.lang.Math
클래스
Math
클래스는 수학에서 자주 사용하는 상수들과 함수들을 미리 구현해 놓은 클래스이다.Math
클래스의 모든 메서드는 클래스 메서드(Static Method)이므로, 인스턴스를 생성하지 않고도 바로 사용할 수 있다.- 이러한
Math
클래스는java.lang
패키지에 포함되어 제공된다.
2) Math.E
와 Math.PI
Math
클래스에 정의되어 있는 클래스 필드는 다음과 같다.
1] Math.E
- 오일러의 수라 불리며, 자연로그(Natural Logarithms)의 밑(Base) 값으로 약
2.718
을 의미한다.
2] Math.PI
- 원의 원주를 지름으로 나눈 비율(원주율) 값으로 약
3.14159
를 의미한다.
3) random()
메서드
random()
메서드는0.0
이상1.0
미만의 범위에서 임의의double
형 값을 하나 생성하여 반환한다.- 이 메서드는 내부적으로
java.util
패키지의Random
클래스를 사용한 의사 난수 발생기(Pseudorandom-Number Generator)를 사용하여 임의의 수를 생성한다.
- 다음 예제는
Math
클래스의random()
메서드를 이용하여0
부터99
까지의 난수를 생성하는 예제이다.
System.out.println((int) (Math.random() * 100)); // 0 ~ 99
Random ran = new Random();
System.out.println(ran.nextInt(100)); // 0 ~ 99
// 48
// 74
- 자바에서는
Math
클래스의random()
메서드뿐만 아니라java.util
패키지에 포함된Random
클래스의nextInt()
메서드를 사용해도 난수를 생성할 수 있다.
- 만약 특정 범위에 속하는 난수를 생성하려면, 다음과 같이 난수 생성 범위를 조절할 수 있다.
(int) (Math.random() * 6); // 0 ~ 5
((int) (Math.random() * 6) + 1); // 1 ~ 6
((int) (Math.random() * 6) + 3); // 3 ~ 8
4) abs()
메서드
abs()
메서드는 전달된 값이 음수이면 그 값의 절댓값을 반환하며, 전달된 값이 양수이면 전달된 값을 그대로 반환한다.
System.out.println(Math.abs(10)); // 10
System.out.println(Math.abs(-10)); // 10
System.out.println(Math.abs(-3.14)); // 3.14
5) floor()
메서드, ceil()
메서드와 round()
메서드
floor()
메서드는 인수로 전달받은 값과 같거나 작은 수 중에서 가장 큰 정수를 반환한다.- 또한,
ceil()
메서드는 반대로 인수로 전달받은 값과 같거나 큰 수 중에서 가장 작은 정수를 반환한다. round()
메서드는 전달받은 실수를 소수점 첫째 자리에서 반올림한 정수를 반환한다.
// floor() 메서드 -> 정수 내림
System.out.println(Math.floor(10.0)); // 10.0
System.out.println(Math.floor(10.9)); // 10.0
// ceil() 메서드 -> 정수 올림
System.out.println(Math.ceil(10.0)); // 10.0
System.out.println(Math.ceil(10.1)); // 11.0
System.out.println(Math.ceil(10.000001)); // 11.0
// round() 메서드 -> 정수 반올림
System.out.println(Math.round(10.0)); // 10
System.out.println(Math.round(10.4)); // 10
System.out.println(Math.round(10.5)); // 11
6) max()
메서드와 min()
메서드
max()
메서드는 전달된 두 값을 비교하여 그중에서 큰 값을 반환하며,min()
메서드는 그중에서 작은 값을 반환한다.
System.out.println(Math.max(3.14, 3.14159)); // 3.14159
System.out.println(Math.min(3.14, 3.14159)); // 3.14
System.out.println(Math.max(-10, -11)); // -10
System.out.println(Math.min(-10, -11)); // -11
7) pow()
메서드와 sqrt()
메서드
pow()
메서드는 전달된 두 개의double
형 값을 가지고 제곱 연산을 수행한다.- 예를 들어,
pow(a, b)
는 \(a^b\)를 반환하게 된다. - 반대로
sqrt()
메서드는 전달된double
형 값의 제곱근 값을 반환한다.
8) sin()
메서드, cos()
메서드와 tan()
메서드
- 자바에서는 삼각 함수와 관련된 다양한 연산을 간편하게 수행할 수 있도록 많은 삼각 함수를 제공하고 있다.
sin()
메서드는 전달된double
형 값의 사인값을,cos()
메서드는 코사인값을,tan()
메서드는 탄젠트값을 반환한다.- 이외에도
Math
클래스에서 제공하는 삼각 함수와 관련된 메서드는 다음과 같다.
asin()
, acos()
, atan()
, atan2()
, sinh()
, cosh()
, tanh()
- 다음 예제는 기본적인 삼각 함숫값을 자바의 삼각 함수 메서드로 확인하는 예제이다.
System.out.println(Math.sin(Math.toRadians(30)));
System.out.println(Math.sin(Math.PI / 6));
System.out.println(Math.tan(Math.toRadians(45)));
System.out.println(Math.tan(Math.PI / 4));
System.out.println(Math.cos(Math.toRadians(60)));
System.out.println(Math.cos(Math.PI / 3));
// 0.49999999999999994
// 0.49999999999999994
// 0.9999999999999999
// 0.9999999999999999
// 0.5000000000000001
// 0.5000000000000001
- 위의 예제처럼 자바의 삼각 함수에 관한 메서드는 정확한 값을 나타내지 못한다.
- 그 이유는 컴퓨터가 실수를 나타내는 데 사용하는 부동 소수점 방식의 한계 때문이다.
6. Wrapper
클래스
- 프로그램에 따라 기본 타입의 데이터를 객체로 취급해야 하는 경우가 있다.
- 예를 들어, 메서드의 인수로 객체 타입만이 요구되면, 기본 타입의 데이터를 그대로 사용할 수는 없다.
- 이때에는 기본 타입의 데이터를 먼저 객체로 변환한 후 작업을 수행해야 한다.
- 이렇게 8개의 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스를
Wrapper
클래스라고 한다. Wrapper
클래스는 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어준다.- 이러한
Wrapper
클래스는 모두java.lang
패키지에 포함되어 제공된다.
- 자바의 기본 타입에 대응하여 제공하고 있는
Wrapper
클래스는 다음과 같다.
기본 타입 | Wrapper 클래스 |
---|---|
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
char |
Character |
boolean |
Boolean |
Note
Wrapper
클래스 중에서Integer
클래스와Character
클래스만이 자신의 기본 타입과 이름이 다름을 주의해야 한다.
1) 박싱(Boxing)과 언박싱(UnBoxing)
Wrapper
클래스는 산술 연산을 위해 정의된 클래스가 아니므로, 인스턴스에 저장된 값을 변경할 수 없다.- 단지, 값을 참조하기 위해 새로운 인스턴스를 생성하고, 생성된 인스턴스의 값만을 참조할 수 있다.
- 위의 그림과 같이 기본 타입의 데이터를
Wrapper
클래스의 인스턴스로 변환하는 과정을 박싱이라고 한다. - 반면
Wrapper
클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정을 언박싱이라고 한다.
2) 오토 박싱(AutoBoxing)과 오토 언박싱(AutoUnBoxing)
- JDK 1.5부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 이를 자동으로 처리해 준다.
- 이렇게 자동화된 박싱과 언박싱을 오토 박싱과 오토 언박싱이라고 부른다.
- 다음 예제는 박싱과 언박싱, 오토 박싱과 오토 언박싱의 차이를 보여주는 예이다.
Integer intObj = new Integer(17); // 박싱
int n = intObj.intValue(); // 언박싱
System.out.println(n);
Character charObj = 'X'; // Character ch = new Character('X'); -> 오토 박싱
char c = charObj; // char c = ch.charValue(); -> 오토 언박싱
System.out.println(c);
// 17
// X
- 위의 예제에서 볼 수 있듯이
Wrapper
클래스인Integer
클래스와Character
클래스에는 각각 언박싱을 위한intValue()
메서드와charValue()
메서드가 포함되어 있다. - 또한, 오토 박싱을 이용하면
new
키워드를 사용하지 않고도 자동으로Character
인스턴스를 생성할 수 있다. - 반대로
charValue()
메서드를 사용하지 않고도, 오토 언박싱을 이용하면 인스턴스에 저장된 값을 바로 참조할 수 있다.
- 따라서 다음 예제처럼 오토 박싱과 오토 언박싱을 통해 기본 타입과
Wrapper
클래스 간의 다양한 연산도 가능해진다.
Integer intObj1 = new Integer(7); // 박싱
Integer intObj2 = new Integer(3); // 박싱
int int1 = intObj1.intValue(); // 언박싱
int int2 = intObj2.intValue(); // 언박싱
① Integer result1 = intObj1 + intObj2; // 오토 언박싱
System.out.println(result1); // 10
② Integer result2 = int1 - int2; // 오토 언박싱
System.out.println(result2); // 4
③ int result3 = intObj1 * int2; // 오토 언박싱
System.out.println(result3); // 2
- 위 예제의 ①번부터 ③번 라인까지의 연산은 내부적으로
Wrapper
클래스인 피연산자를 오토 언박싱하여 기본 타입끼리의 연산을 수행하고 있는 것이다.
Integer intObj1 = new Integer(10);
Integer intObj2 = new Integer(20);
Integer intObj3 = new Integer(10);
System.out.println(intObj1 < intObj2); // true
① System.out.println(intObj1 == intObj3); // false
② System.out.println(intObj1.equals(intObj3)); // true
Wrapper
클래스의 비교 연산도 오토언박싱을 통해 가능하지만, 인스턴스에 저장된 값의 동등 여부 판단은 ①번 라인처럼 비교 연산자인 동등 연산자(==
)를 사용해서는 안 되며, ②번 라인처럼equals()
메서드를 사용해야만 한다.Wrapper
클래스도 객체이므로 동등 연산자(==
)를 사용하게 되면, 두 인스턴스의 값을 비교하는 것이 아니라 두 인스턴스의 주소값을 비교하게 된다.- 따라서 서로 다른 두 인스턴스를 동등 연산자(
==
)로 비교하게 되면, 언제나false
값을 반환하게 된다. - 그러므로 인스턴스에 저장된 값의 동등 여부를 정확히 판단하려면
equals()
메서드를 사용해야만 한다.
7. Enum
클래스
1) 열거체(Enumeration Type)
- JDK 1.5부터는 열거체를 정의한 Enum 클래스를 사용할 수 있다.
- 이와 같은 자바의 열거체는 다음과 같은 장점을 가진다.
1] 열거체를 비교할 때 실제 값뿐만 아니라 타입까지도 체크한다.
2] 열거체의 상숫값이 재정의되더라도 다시 컴파일할 필요가 없다.
2) 열거체의 정의 및 사용
- 자바에서는
enum
키워드를 사용하여 열거체를 정의할 수 있다.
- 이렇게 정의된 열거체를 사용하는 방법은 다음과 같다.
3) 열거체의 상숫값 정의 및 추가
- 위와 같이 정의된 열거체의 첫 번째 상숫값은
0
부터 설정되며, 그다음은 바로 앞의 상숫값보다1
만큼 증가되며 설정된다. - 또한, 불규칙한 값을 상숫값으로 설정하고 싶으면 상수의 이름 옆에 괄호를 추가하고, 그 안에 원하는 상숫값을 명시할 수 있다.
- 하지만 이때에는 불규칙한 특정 값을 저장할 수 있는 인스턴스 변수와 생성자를 다음 예제와 같이 별도로 추가해야만 한다.
enum Rainbow {
RED(3),
ORANGE(10),
YELLOW(21),
GREEN(5),
BLUE(1),
INDIGO(-1),
VIOLET(-11);
private final int value;
Rainbow(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
4) java.lang.Enum
클래스
Enum
클래스는 모든 자바 열거체의 공통된 조상 클래스이다.Enum
클래스에는 열거체를 조작하기 위한 다양한 메서드가 포함되어 있다.
5) values()
메서드
values()
메서드는 해당 열거체의 모든 상수를 저장한 배열을 생성하여 반환한다.- 이 메서드는 자바의 모든 열거체에 컴파일러가 자동으로 추가해 주는 메서드이다.
class Test {
enum Rainbow {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET,
}
public static void main(String[] args) {
Rainbow[] arr = Rainbow.values();
for (Rainbow rb : arr) {
System.out.println(rb);
}
}
}
// RED
// ORANGE
// YELLOW
// GREEN
// BLUE
// INDIGO
// VIOLET
6) valueOf()
메서드
valueOf()
메서드는 전달된 문자열과 일치하는 해당 열거체의 상수를 반환한다.
class Test {
enum Rainbow {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET,
}
public static void main(String[] args) {
Rainbow rb = Rainbow.valueOf("GREEN");
System.out.println(rb);
}
}
// GREEN
7) ordinal()
메서드
ordinal()
메서드는 해당 열거체 상수가 열거체 정의에서 정의된 순서(0
부터 시작)를 반환한다.- 이때 반환되는 값은 열거체 정의에서 해당 열거체 상수가 정의된 순서이며, 상숫값 자체가 아님을 명심해야 한다.
class Test {
enum Rainbow {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET,
}
public static void main(String[] args) {
int idx = Rainbow.YELLOW.ordinal();
System.out.println(idx);
}
}
// 2
- 다음 예제는 불규칙적인 상숫값을 가지는 열거체에서
ordinal()
메서드를 사용한 예제이다.
class Test {
enum Rainbow {
RED(3),
ORANGE(10),
YELLOW(21),
GREEN(5),
BLUE(1),
INDIGO(-1),
VIOLET(-11);
private final int value;
Rainbow(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public static void main(String[] args) {
int idx = Rainbow.YELLOW.ordinal();
System.out.println(idx);
}
}
// 2