9. java.lang패키지와 유용한(util) 클래스
1. java.lang패키지
- 자바프로그래밍에 가장 기본이 되는 클래스들 포함
- import문 없이도 사용 가능
1.1 Object클래스
- 모든 클래스의 최고 조상
- Object클래스의 멤버들은 모든 클래스에서 사용 가능
- 멤버변수는 없고 11개의 메서드만 가짐 (인스턴스가 가져야 할 기본적인 것들)
Object클래스의 메서드 | 설명 |
---|---|
public boolean equals(Object obj) | 객체 자신과 객체 obj가 같은 객체 인지 여부를 반환 (같으면 true) |
public int hashCode() | 객체 자신의 해시코드를 반환 |
public String toString() | 객체 자신의 정보를 문자열로 반환 |
protected Object clone() | 객체 자신의 복사본을 반환 |
public Class getClass() | 객체 자신의 클래스 정보를 담고 있는 Class인스턴스를 반환 |
public void notify() | 객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨움 |
public void notifyAll() | 객체 자신을 사용하려고 기다리는 모든 쓰레드를 깨움 |
publid void wait() public void wait(long timeout) public void wait(long timeout, int nanos) |
다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 현재 쓰레드를 무한히 또는 지정된 시간(timeout, nanos)동안 기다리게 한다. (timeout은 천 분의 1초, nanos는 10^9분의 1초) |
protected void finalize() | 객체가 소멸될 때 가비지 컬렉터에 의해 자동적으로 호출 이 때 수행되어야하는 코드가 있을 때 오버라이딩 (거의 사용안함) |
참고: notify(), notifyAll(), wait()는 쓰레드(thread) 관련이라 13장에서 자세히 설명
equals(Object obj)
- 매개변수로 객체의 참조변수를 받아서 비교하여 그 결과를 boolean으로 알려준다.
- 두 객체의 같고 다름을 참조변수의 값으로 판단하므로 항상 false
/* 기본구현체 */ public boolean equals(Object obj) { return (this==obj); }
equals메서드 기본구현 사용 예제
class Value {
int value;
Value(int value) {
this.value = value;
}
}
class EqualsEx1 {
public static void main(String[] args) {
Value v1 = new Value(10);
Value v2 = new Value(10);
if(v1.equals(v2)) {
System.out.println("eqauls == true");
} else {
System.out.println("eqauls == false"); // 서로 다른 주소 참조
}
v2 = v1; // 서로 같은 주소 참조
if(v1.equals(v2)) {
System.out.println("eqauls == true"); // 서로 같은 주소 참조
} else {
System.out.println("eqauls == false");
}
}
}
eqauls == false
eqauls == true
참고: 객체를 생성할 때, 메모리의 비어있는 공간을 찾아 생성하므로 서로 다른 두 개의 객체가 같은 주소를 갖는 일은 있을 수 없다. 두 개 이상의 참조변수가 같은 주소값을 갖는 것(한 객체를 참조하는 것)은 가능하다.
equals메서드 오버라이딩 예제
class Person {
long id;
Person(long id) {
this.id = id;
}
// 오버라이딩
public boolean equals(Object obj) {
if(obj != null && obj instanceof Person) {
return id == ((Person)obj).id;
} else {
return false;
}
}
}
class EqualsEx2 {
public static void main(String[] args) {
Person p1 = new Pserson(8602192222111L);
Person p2 = new Pserson(8602192222111L);
if(p1 == p2) {
System.out.println("eqauls == true");
} else {
System.out.println("eqauls == false"); // 서로다른 주소 참조
}
if(p1.equals(p2)) {
System.out.println("eqauls == true"); // 서로 같은 값
} else {
System.out.println("eqauls == false");
}
}
}
eqauls == false
eqauls == true
참고: equals메서드를 오버라이딩하고 있는 클래스들
- String, Date, File, Wrapper클래스(Integer, Double 등)
- 의외로 StringBuffer클래스는 오버라이딩 되어있지 않다.
hashCode()
- 해싱(hashing)기법에 사용되는 해시함수(hash function)를 구현한 것
- 기본구현: 객체의 주소값을 이용해서 해시코드를 만들어 반환한다.
따라서, 서로 다른 두 객체는 결코 같은 해시코드를 가질 수 없다.- 오버라이딩: 클래스의 인스턴스변수값으로 객체의 같고 다림을 판단해야할 경우
참고
- 해싱: 데이터관리기법 중의 하나로 다량의 데이터를 저장하고 검색하는데 유용
- 해시함수: 찾고자하는 값을 입력하면, 그 값이 저장된 위치를 알려주는 해시코드를 반환
- 해싱기법을 사용하는 HashMap이나 HashSet과 같은 클래스에 저장할 객체라면 반드시 hashCode메서드를 오버라이딩해야 한다. (자세한 것은 11장 컬렉션 프레임웍에서)
hashCode메서드 오버라이딩 예제: String클래스
class HashCodeEx1 {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1.equals(str2)); // true
System.out.println(str1.hashCode()); // 96354
System.out.println(str2.hashCode()); // 96354
System.out.println(System.identityHashCode(str1)); // 27134973
System.out.println(System.identityHashCode(str2)); // 1284693
}
}
참고: System.identityHashCode(Object obj)
- 객체의 주소값을 해시코드로 생성
- 모든 객체에 대해 항상 다른 해시코드값을 반환할 것을 보장
- 호출결과는 실행 할 때마다 달라질 수 있음
toString()
- 인스턴스에 대한 정보를 문자열(String)으로 제공할 목적으로 정의
- 대부분의 경우 인스턴스 변수에 저장된 값들을 문자열로 표현
/* 기본구현체 */ public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
toString메서드 기본구현 사용 예제
class Card {
String kind;
int number;
Card() {
this("SPADE", 1)
}
Card(String kind, int number) {
this.kind = kind;
this.number = number;
}
}
class CardToString {
public static void main(String[] args) {
Card c1 = new Card();
Card c2 = new Card();
System.out.println(c1.toString()); // Card@19e0bfd
System.out.println(c2.toString()); // Card@139a55
}
toString메서드 오버라이딩 예제
class Card {
String kind;
int number;
Card() {
this("SPADE", 1)
}
Card(String kind, int number) {
this.kind = kind;
this.number = number;
}
// 조상클래스(Object)에 정의된 접근범위보다 같거나 넓어야 하므로, public
public String toString() {
return "kind : " + kind + ", number : " + number;
}
}
class CardToString2 {
public static void main(String[] args) {
Card c1 = new Card();
Card c2 = new Card("HEART", 2);
System.out.println(c1.toString()); // kind : SPADE, number : 1
System.out.println(c2.toString()); // kind : HEART, number : 2
}
참고: String, Date클래스도 toString메서드가 오버라이딩 되어 있음
clone()
- 자신을 복제하여 새로운 인스턴스를 생성
- 작업 실패시 원래 상태로 되돌리거나 변경되기 전의 값을 참고하는데 도움
- 기본구현: 단순히 인스턴스 변수의 값만 복사
따라서, 참조변수 타입의 인스턴스 변수가 정의되어 있는 경우 완전한 복제가 아님
공변 반환타입(covariant return type)
- 오버라이딩할 때 조상 메서드의 반환타입을 자손 클래스 타입으로 변경을 허용 (jdk1.5부터)
public Point clone() { // 1. 반환타입을 Object -> Point (조상->자손타입으로) 변경
Object obj = null;
try {
obj = super.clone();
} catch(CloneNotSupportedException e) { }
return (Point)obj; // 2. Point타입으로 형변환
}
// Point copy = (Point)original.clone();
Point copy = original.clone(); // 번거로운 형변환이 줄어든다.
clone()을 이용한 배열복사
- 배열도 객체이기 때문에 Object클래스를 상속받으며, Clonable인터페이스와 Serializable인터페이스가 구현되어 있다.
- java.util패키지의 Vector, ArrayList, LinkedList, HashSet, TreeSet, HashMap, TreeMap, Calendar, Date와 같은 클래스들도 이와 같은 방식으로 복제가 가능하다.
int[] arr = {1,2,3,4,5};
//int[] arrClone = new int[arr.length];
//System.arraycopy(arr,0,arrClone,0,arr.length);
int[] arrClone = arr.clone();
얕은 복사와 깊은 복사
- 얕은 복사(shallow copy): 단순히 객체에 저장된 값을 그대로 복제할 뿐, 객체가 참조하고 있는 객체까지 복사하지 않는다.
(원본과 복제본이 같은 객체를 공유하므로 완전한 복제가 아니며, 원본을 변경하면 복사본도 영향을 받는다.) - 깊은 복사(deep copy): 원본이 참조하고 있는 객체까지 복사한다.
(원본과 복사본이 서로 다른 객체를 참조하기 때문에 원본의 변경이 복사본에 영향을 미치지 않는다.)
class Circle implements Clonable {
Point p; // 원점 - 참조변수
double r; // 반지름
Circle(Point p, double r) {
this.p = p;
this.r = r;
}
// 얕은 복사
public Circle shallowCopy() {
Object obj = null;
try {
obj = super.clone(); // 복제본이 원본과 동일한 Point인스턴스를 참조하게 된다.
} catch(CloneNotSupportedException e) { }
return (Circle)obj;
}
// 깊은 복사
public Circle deepCopy() {
Object obj = null;
try {
obj = super.clone();
} catch(CloneNotSupportedException e) { }
Circle c = (Circle)obj;
c.p = new Point(this.p.x, this.p.y); // 복제본이 새로운 Point인스턴스를 참조하도록 한다.
return c;
}
}
Circle c1 = Circle(new Point(1, 1), 2.0);
Circle c2 = c1.clone(); // 얕은 복사: 동일한 Point 주소를 참조하는 p를 갖는다.
getClass()
- 자신이 속한 클래스의 Class객체를 반환
Class객체
- 이름이 'Class'인 클래스의 객체
- 클래스의 모든 정보(정의된 멤버의 이름이나 개수 등)를 담고 있고, 클래스당 단 1개만 존재
- 클래스 파일이 '클래스 로더(ClassLoader)'에 의해 메모리에 올라갈 때, 자동생성
/* Class클래스 */ public final class Class implements ... { ... }
클래스로더(ClassLoader)
- 실행시에 필요한 클래스를 동적으로 메모리에 로드하는 역할
- 클래스 로드 순서
- 기존에 생성된 클래스 객체가 메모리에 존재하는지 확인
- 클래스패스(classpath)에 지정된 경로를 따라서 클래스 파일 찾음
- 해당 클래스를 못찾으면 ClassNotFoundException 발생
Class객체를 얻는 방법
// 생성된 객체로부터 얻음
Class cObj = new Card().getClass();
// 클래스 리터럴(*.class)로부터 얻음
Class cObj = Card.class;
// 클래스 이름으로부터 얻음
// 특정 클래스 파일을 메모리에 올릴때 주로 사용 (예: 데이터베이스 드라이버)
Class cObj = Class.forName("Card");
Class객체를 이용해서 동적으로 객체를 생성하는 방법
// new연산자를 이용해서 객체 생성
Card c = new Card();
// Class객체를 이용해서 객체 생성
// InstantiationException 예외처리 필요
Card c = Card.class.newInstance();
참고: 동적으로 객체를 생성하고 메서드를 호출하는 방법에 대해 더 알고싶다면, '리플렉션(reflection) API'로 검색
1.2 String클래스
문자열을 저장하고 이를 다루는데 필요한 메서드를 제공한다.
변경 불가능한(immutable) 클래스
- 인스턴스변수로 문자형 배열 변수에 문자열을 저장한다.
- 클래스앞에 final이 붙으므로 다른 클래스의 조상이 될 수 없다.
- 한번 생성된 String 인스턴스가 갖고 있는 문자열은 읽어올 수만 있고, 변경할 수는 없다.
- '+' 연산자를 이용해서 문자열을 결합하는 경우 인스턴스내의 문자열이 바뀌는 것이 아니라 새로운 문자열이 담긴 String 인스턴스가 생성되는 것이다. (결합시마다 인스턴스가 생성되어 메모리 공간을 차지하므로 횟수를 줄이는 것이 좋다.)
- 문자열간의 결합이나 추출 등의 작업은 StringBuffer클래스를 사용하는 것이 좋다.
문자열의 비교
// 문자열 리터럴
String str1 = "abc";
String str2 = "abc";
// 새로운 인스턴스
String str3 = new String("abc");
String str4 = new String("abc");
str1 == str2; // true
str1.equals(str2); // true
str3 == str4; // false
str3.equals(str4); // true
문자열 리터럴
- 자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다.
- 문자열 리터럴도 String인스턴스이고 한번 생성하면 내용을 변경할 수 없기 때문에 하나의 인스턴스를 공유한다.
- 클래스 파일에는 소스파일에 포함된 모든 리터럴의 목록이 있다.
- 클래스로더에 의해 메모리에 올라갈 때, 리터럴들이 JVM내에 있는 '상수저장소(constant pool)'에 저장된다.
빈 문자열(empty string)
- 길이가 0인 char형 배열
String s = ""; // 빈문자열로 초기화 (null보다는 이렇게 초기화)
char c = ' '; // char형 변수에는 반드시 하나의 문자를 지정해야 함
참고: c언어에서는 문자열의 끝에 널 문자가 항상 붙지만, 자바에서는 널 문자를 사용하지 않는다. 대신 문자열의 길이정보를 따로 저장한다.
String클래스의 생성자와 메서드: p468 ~ p471 참고
join()과 StringJoiner
- jdk1.8부터 추가된 기능
- join(): 여러 문자열 사이에 구분자를 넣어서 결합한다.
- split(): 구분자로 문자열을 자른다.
- java.util.StringJoiner클래스로 문자열을 결합할 수도 있다.
String animals = "dog,cat,bear";
String[] arr = animals.split(",");
String str = String.join("-", arr);
System.out.println(str); // dog-cat-bear
StringJoiner sj = new StringJoiner(",", "[", "]");
String[] strArr = { "aaa", "bbb", "ccc" };
for(String s : strArr)
sj.add(s.toUpperCase());
System.out.println(sj.toString()); // [AAA,BBB,CCC]
유니코드의 보충문자
- String클래스 메서드 중에 보충 문자를 지원하는 경우 매개변수로 int를 받는다.
- 보충 문자를 사용할 일은 거의 없기 때문에 이정도만 알아둔다.
참고: 유니코드는 원래 2byte(16bit) 문자체계인데 20bit로 확장하게되었다. 그래서 하나의 문자를 char타입으로 다루지 못하고 int타입으로 다룰 수 밖에 없다.
문자 인코딩 변환
- getBytes(String chartsetName)를 사용하여 문자열의 문자 인코딩을 다른 인코딩으로 변경할 수 있다.
- 자바가 UTF-16를 사용하지만, 문자열 리터럴에 포함되는 문자들은 OS의 인코딩을 사용한다.
byte[] utf8_str = "가".getBytes("UTF-8"); // 문자열을 UTF-8로 변환
String str = new String(utf8_str, "UTF-8"); // byte배열을 문자열로 변환
참고
- 한글 윈도우즈 문자 인코딩: CP949
- UTF-8은 한글 한글자를 3byte로 표현하고, CP949는 2byte로 표현한다.
- 사용가능한 문자 인코딩 목록: java.nio.charset.Charset.availableCharsets()
String.format()
- 형식화된 문자열을 만들어낸다.
String str = String.format("%d 더하기 %d는 %d입니다.", 3,5,3+5);
System.out.println(str); // 3 더하기 5는 8입니다.
기본형 값을 String으로 변환
int i = 100;
String str1 = i + ""; // 100 -> "100"
String str2 = String.valueOf(i); // 100 -> "100" (성능향상이 필요한 경우)
String을 기본형 값으로 변환
기본형 -> 문자열 | 문자열 -> 기본형 |
---|---|
String String.valueOf(boolean b) | boolean Boolean.parseBoolean(String s) |
String String.valueOf(char c) | byte Byte.parseByte(String s) |
String String.valueOf(short short) | short Short.parseShort(String s) |
String String.valueOf(int i) | int Integer.parseInt(String s) |
String String.valueOf(long l) | long Long.parseLong(String s) |
String String.valueOf(float f) | float Float.parseFloat(String s) |
String String.valueOf(double d) | double Double.parseDouble(String s) |
참고: 변환시 예외발생에 대해 적절히 처리해주어야 한다.
trim(): 문자열 양끝의 공백제거
substring(int start, int end): 한 문자열에서 내용의 일부를 추출한다.
- 각 문자의 위치를 뜻하는 index가 0부터 시작한다.
- end 위치는 포함되지 않는다.
String str = "Hello.java";
int index = str.indexOf('.'); // 5
int index2 = str.lastIndexOf('.'); // 5
String a = str.substring(0,5); // Hello
String b = str.substring(6,10); // java
1.3 StringBuffer클래스와 String Builder클래스
문자열을 변경할 수 있도록 내부적으로 편집을 위한 버퍼(buffer)를 가진 클래스
- StringBuffer인스턴스를 생성할 때 그 크기를 지정할 수 있다.
- 편집할 문자열의 길이를 고려하여 버퍼의 길이를 충분히 잡아주는 것이 좋다.
- 문자열이 버퍼의 길이를 넘어서게되면 길이를 늘려주는 작업이 수행되어야 한다.
- String클래스와 같이 문자열을 저장하기 위한 char형 배열 참조변수를 인스턴스로 갖는다.
StringBuffer의 생성자
- 인스턴스 생성시 적절한 길이의 char형 배열이 생성되고, 이 배열은 문자열을 저장하고 편집하기 위한 공간으로 사용된다.
public StringBuffer(int length) {
value = new char[length];
shared = false;
}
public StringBuffer() {
this(16); // 버퍼의 크기를 정하지 않으면 16으로 잡는다.
}
public StringBuffer(String str) {
this(str.length() + 16); // 버퍼의 크기를 지정한 문자열의 길이보다 16 크게 잡는다.
append(str);
}
/* 버퍼의 크기를 늘리는 작업 코드 */
// 새로운 길이의 배열을 생성 (newCapacity는 정수값)
char newValue[] = new char[newCapacity];
// 기존 내용 복사
System.arraycopy(value, 0, newValue, 0, count); // count = 문자열 길이
value = newValue; // 새로 생성된 배열의 주소를 참조변수 value에 저장
StringBuffer의 변경
StringBuffer sb = new StringBuffer("abc");
sb.append("123"); // sb의 내용 뒤에 123을 추가하고 자신의 주소를 반환한다.
StringBuffer sb2 = sb.append("ZZ"); // sb의 내용 뒤에 ZZ를 추가하고 자신의 주소를 반환한다.
System.out.println(sb); // abc123ZZ
System.out.println(sb2); // abc123ZZ
StringBuffer의 비교
// equals()는 오버라이딩 되어있지 않음.
StringBuffer sb = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb == sb2); // false
System.out.println(sb.equals(sb2)); // false
// toString()은 오버라이딩 되어 있음.
String s = sb.toString();
String s2 = sb2.toString();
System.out.println(s.equals(s2)); // true
StringBuffer클래스의 생성자와 메서드: p480 ~ p481 참고
StringBuilder란?
- StringBuffer는 멀티쓰레드에 안전(thread safe)하도록 동기화 되어 있다. (성능을 떨어뜨림)
- StringBuilder: StringBuffer에서 쓰레드의 동기화만 뺀 클래스 (그외에는 완전 똑같은 기능)
- 멀티쓰레드 환경이 아니라면 StringBuilder를 쓰면된다.
- StringBuffer도 충분히 성능이 좋기 때문에 성능향상이 반드시 필요한 경우에만 쓴다.
1.4 Math클래스
기본적인 수학계산에 유용한 메서드로 구성된 클래스
- 생성자가 private이므로 다른 클래스에서 인스턴스를 생성할 수 없다. (인스턴스변수가 하나도 없어서 인스턴스를 생성할 필요가 없다.)
- 메서드는 모두 static
- 2개의 상수만 정의되어 있다.
public static final double E = 2.71828 ... ; // 자연로그의 밑 public static final double PI = 3.14159 ... ; // 원주율
올림, 버림, 반올림
round(): 항상 소수점 첫째자리에서 반올림을 해서 정수값(long)을 결과로 돌려준다.
- 원하는 자리 수에서 반올림된 값을 얻기 위해서는 10의 n제곱으로 곱한 후 다시 곱한 수로 나눠준다.
// 원래값에 100을 곱한다.
90.7552 * 100 -> 9075.52
// 위의 결과에 Math.round()를 사용한다.
Math.round(9075.52) -> 9076
// 위의 결과에 다시 100.0(정수형으로 나누면 90이 됨)으로 나눈다.
9076 / 100.0 -> 90.76
예외를 발생시키는 메서드
Exact가 포함된 메서드들 (jdk1.8부터 새로 추가됨)
- 정수형 연산에서 발생할 수 있는 오버플로우(overflow)를 감지한다.
- 오버플로우가 발생하면 ArithmeticException 예외를 발생시킨다.
int addExact(int x, int y); // x + y
int subtractExact(int x, int y); // x - y
int multiplyExact(int x, int y); // x * y
int incrementExact(int a); // a++
int decrementExact(int a); // a--
int negateExact(int a); // -a
int toIntExact(long value); // (int)value - int 로의 형변환
삼각함수와 지수, 로그
Math클래스에는 수학 관련 메서드들이 많이 있다. 자세한 내용은 Java API를 참고
StrictMath클래스
어떤 OS에서 실행되어도 항상 같은 결과를 얻도록 Math클래스를 새로 작성한 것
참고: Math클래스는 성능 이슈로 JVM이 설치된 OS의 메서드를 호출해서 사용하기 때문에 OS에 의존적이다. (ex. 부동소수점계산)
Math클래스의 메서드: p489 ~ p490 참고
메서드 | 설명 |
---|---|
static double abs(double a) static float abs(float f) static int abs(int f) static long abs(long f) |
주어진 값의 절대값을 반환 |
static double ceil(double a) | 주어진 값을 올림하여 반환 |
static double floor(double a) | 주어진 값을 버림하여 반환 |
static double max(double a, double b) static float max(float a, float b) static int max(int a, int b) static long max(long a, long b) |
주어진 두 값을 비교하여 큰 쪽을 반환 |
static double min(double a, double b) static float min(float a, float b) static int min(int a, int b) static long min(long a, long b) |
주어진 두 값을 비교하여 작은 쪽을 반환 |
static double random() | 0.0 ~ 1.0 범위의 임의의 double값을 반환 (1.0은 범위에 포함되지 않는다.) |
static double rint(double a) | 주어진 double값과 가장 가까운 정수값을 double형으로 반환 |
static long round(double a) static long round(float a) |
소수점 첫째자리에서 반올림한 정수값(long)을 반환 (매개변수의 값이 음수인 경우, round()와 rint()의 결과가 다르다.) |
1.5 래퍼(wrapper) 클래스
기본형(primitive type)을 클래스로 다루어야 할 경우를 위한 클래스
- 래퍼클래스들은 모두 equals(), toString()이 오버라이딩 되어 있다.
- 비교연산자를 사용할 수 없는 대신 compareTo()를 제공한다.
기본형 | 래퍼클래스 | 생성자 | 예제 |
---|---|---|---|
boolean | Boolean | Boolean(boolean value) Boolean(String s) |
Boolean b = new Boolean(true); Boolean b2 = new Boolean("true"); |
char | Character | Character(char value) | Character c = new Character('a'); |
byte | Byte | Byte(byte value) Byte(String s) |
Byte b = new Byte(10); Byte b2 = new Byte("10"); |
short | Short | Short(short value) Short(String s) |
Short s = new Short(10); Short s2 = new Short("10"); |
int | Integer | Integer(int value) Integer(String s) |
Integer i = new Integer(100); Integer i2 = new Integer("100"); |
long | Long | Long(long value) Long(String s) |
Long l = new Long(100); Long l2 = new Long("100"); |
float | Float | Float(double value) Float(float value) Float(String s) |
Float f = new Float(1.0); Float f2 = new Float(1.0f); Float f3 = new Float("1.0f"); |
double | Double | Double(double value) Double(String s) |
Double d = new Double(1.0); Double d2 = new Double("1.0"); |
참고: 래퍼클래스의 생성자는 매개변수로 문자열이나 각 자료형의 값들을 인자로 받는다. 각 자료형에 알맞은 타입을 사용하지 않으면 FormatException이 발생한다.
Number클래스
추상클래스로 내부적으로 숫자를 멤버변수로 갖는 래퍼클래스들의 조상
- 객체가 가지고 있는 값을 숫자와 관련된 기본형으로 변환하여 반환하는 메서드들을 정의하고 있다.
- BigInteger: long으로도 다룰 수 없는 큰 범위의 정수
- BigDecimal: double로도 다룰 수 없는 큰 범위의 부동 소수점수
Object
|
Boolean - Character - Number
|
Byte - Short - Integer - Long - Float - Double - BigInteger - BigDecimal
/* Number클래스의 실제 소스 */
public abstract class Number implements java.io.Serializable {
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
public byte byteValue() {
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
}
문자열을 숫자로 변환하기
int i = new Integer("100").intValue(); // floatVlaue(), longValue(), ...
int i2 = Integer.parseInt("100"); // 주로 이 방법을 많이 사용
Integer i3 = Integer.valueOf("100");
문자열 -> 기본형 | 문자열 -> 래퍼클래스 |
---|---|
byte b = Byte.parseByte("100"); | Byte b = Byte.valueOf("100"); |
short s = Short.parseShort("100"); | Short s = Short.valueOf("100"); |
int i = Integer.parseInt("100"); | Integer i = Integer.valueOf("100"); |
long l = Long.parseLong("100"); | Long l = Long.valueOf("100); |
float f = Float.parseFloat("3.14"); | Float f = Float.valueOf("3.14"); |
double d = Double.parseDouble("3.14"); | Double d = Double.valueOf("3.14"); |
참고: jdk1.5부터 도입된 오토박싱(autoboxing) 기능 때문에 반환값이 기본형일 때와 래퍼 클래스일 때의 차이가 없어졌다. 그래서 그냥 구별없이 valueOf()를 쓰는 것도 괜찮다. 단, 성능은 valueOf()가 조금 더 느리다.
진법 숫자 변환
static int parseInt(String s, int radix);
Integer.parseInt("100", 2); // 100(2) -> 4
Integer.parseInt("100", 8); // 100(8) -> 64
Integer.parseInt("100", 16); // 100(16) -> 256
Integer.parseInt("FF", 16); // FF(16) -> 255
Integer.parseInt("FF"); // NumberFormatException
static Integer valueOf(String s, int radix);
Integer.valueOf("100", 2); // 100(2) -> 4
Integer.valueOf("100", 8); // 100(8) -> 64
Integer.valueOf("100", 16); // 100(16) -> 256
Integer.valueOf("FF", 16); // FF(16) -> 255
Integer.valueOf("FF"); // NumberFormatException
오토박싱 & 언박싱 (autoboxing & unboxing)
jdk1.5에 추가된 기본형과 참조형 간의 연산이 가능하도록 컴파일러가 자동으로 변환하는 기능 (이전에는 형변환해야했음)
- 오토박싱(autoboxing): 기본형값을 래퍼클래스의 객체로 자동변환
- 언박싱(unboxing): 래퍼클래스를 기본형값으로 자동변환
컴파일 전 | 컴파일 후 |
---|---|
int i = 5; Integer iObj = new Integer(7); int sum = i + iObj; |
int i = 5; Integer iObj = new Integer(7); int sum = i + iObj.intValue(); |
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(10); // 오토박싱: 10 -> new Integer(10)
int value = list.get(0); // 언박싱: new Integer(10) -> 10
2. 유용한 클래스
2.1 java.util.Objects 클래스
Object 클래스의 보조 클래스로 Math 클래스처럼 모든 메서드가 'static'이다. 객체의 비교나 널 체크에 유용하다.
2.2 java.util.Random 클래스
난수를 얻는 방법을 생각하면 Math.random()이 떠오를 것이다. 이 외에도 Random 클래스를 사용하면 난수를 얻을 수 있다. 사실 Math.random()은 내부적으로 Random 클래스의 인스턴스를 생성해서 사용하는 것이므로 둘 중에서 편한 것을 사용하면 된다.
2.3 정규식(Regular Expression) - java.util.regex 패키지
정규식이란 텍스트 데이터 중에서 원하는 조건(패턴, pattern)과 일치하는 문자열을 찾아내기 위해 사용하는 것으로 미리 정의된 기호와 문자를 이용해서 작성한 문자열을 말한다. 이거 문자 파싱할 때 자주 쓰는데요-
A. 비밀번호 유효성 체크
B. 이메일 유효성 체크
C. 전화번호 추출
D. html 에서 텍스트 마이닝
import java.util.regex.*;
class RegularEx1 {
public static void main(String[] args) {
String[] data = {"bat", "baby", "bonus", "cA"};
Pattern p = Pattern.compile("c[a-z]*");
for(int i = 0;i<data.length; i++){
Matcher m = p.matcher(data[i]);
if(m.matches())
System.out.print(data[i] + ",");
}
}
}
단계별로 설명하면 아래의 스텝을 거친다.
- 정규식을 매개변수로 Pattern클래스의 static 메서드인 Pattern compile(String regex)을 호출하여 Pattern 인스턴스를 얻는다.
Pattern p = Pattern.compile("c[a-z]*");
- 정규식으로 비교할 대상을 매개변수로 Pattern클래스의 Matcher matcher (CharSequence input)를 호출해서 Matcher인스턴스를 얻는다.
Matcher m = p.matcher(data[i]);
- Matcher 인스턴스에 boolean matches()를 호출해서 정규식에 부합하는 지 확인한다.
if(m.matches())
정규식 패턴 | 설명 | 결과 |
---|---|---|
c[a-z]* | c로 시작하는 영단어 | c,ca,co,car,combat,count |
c[a-z] | c로 시작하는 두자리 영단어 | ca,co |
c[a-zA-Z] | c로 시작하는 두자리 영단어 (a~z 또는 A~Z) | cA,ca,co |
c[a-zA-Z0-9] | c로 시작하고 숫자와 영어로 조합된 두 글자 | cA,ca,co,c0 |
.* | 모든 문자열 | bat,baby,bonus,c,cA,ca,co,c.,c0,c#,car,combat,count,date,disc |
c. | c로 시작하는 두 자리 | cA,ca,co,c.,c0,c# |
c.* | c로 시작하는 모든 문자열(기호포함) | cA,ca,co,c.,c0,c#,car,combat,count |
c. | c.와 일치하는 문자열'.'은 패턴작성에 사용되는 문자이므로 escape문자인 '\'를 사용해야 한다. | c. |
c\d or c[0-9] | c와 숫자로 구성된 두자리 문자열 | c0 |
c.*t | c로 시작하고 t로 끝나는 모든 문자열 | combat,count |
[bc].* or [b-c].* | b나 c로 시작하는 문자열 | |
bc.* | b나 c로 시작하지 않는 문자열 | |
.*a.* | a를 포함하는 모든 문자열 | date, disc |
[bc].{2} | b 또는 c로 시작하는 세자리 문자열 | bat, car |
2.4 java.util.Scanner 클래스
Scanner는 화면, 파일, 문자열과 같은 입력소스로부터 문자데이터를 읽어오는데 도움을 줄 목적으로 JDK 1.5부터 추가되었다.
Scanner (String source)
Scanner (File source)
Scanner (InputStream source)
Scanner (Readable source)
Scanner (ReadableByteChannel source)
Scanner (Path source)
JDK 1.5이전
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine();
JDK 1.5이후
Scanner s = new Scanner(System.in);
String input = s.nextLine();
JDK 1.6이후
Console console = System.console();
String input = console.readLine();
import java.util.Scanner;
import java.io.File;
class ScannerEx2 {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(new File("data2.txt"));
int sum = 0 ;
int cnt = 0 ;
while (sc.hasNextInt()) {
sum += sc.nextInt();
cnt++;
}
System.out.println("sum="+sum);
System.out.println("average=" + (double)sum/cnt);
}
}
2.5 java.util.StringTokenizer 클래스
StringTokenizer는 긴 문자열을 지정된 구분자를 기준으로 토큰(token)이라는 여러개의 문자열로 잘라내는 데 사용된다. 예를 들어 "100,200,300,400"라는 문자열이 있을 때 ','를 구분자로 잘라내면 100, 200, 300, 400 이라는 4개의 문자열을 얻을 수 있다.
생성자 / 메서드 | 설명 |
---|---|
StringTokenizer(String str, String delim) | 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성한다. |
StringTokenizer(String str, String delim, boolean returnDelims) | 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성한다. |
int countTokens() | 전체 토큰의 수를 반환한다. |
boolean hasMoreTokens() | 토큰이 남아있는지 알려준다. |
String nextToken() | 다음 토큰을 반환한다. |
import java.util.*;
class StringTokenizerEx1 {
public static void main(String[] args) {
String sources = "100,200,300,400";
StringTokenizer st = new StringTokenizer(source, ",");
while(st.hasMoreTokens())
{
System.out.println(st.nextToken());
}
}
}
2.6 java.math.BigInteger 클래스
정수형으로 표현할 수 있는 값의 한계가 있다. 가장 큰 정수형 타입인 long으로 표현할 수 있는 값은 10진수로 19자리 정도이다. 이 값도 상당히 큰 값이지만, 과학적 계산에서는 더 큰 값을 다뤄야 할 때가 있다. 그럴 때 사용하면 좋은 것이 BigInteger이다.
BigInteger의 생성
BigInteger val;
val = new BigInteger("12345678901234");
val = new BigInteger("FFFF", 16);
val = BigInteger.valueOf(12345789L);
BigInteger의 연산
BigInteger add(BigInteger val)
BigInteger subtract(BigInteger val)
BigInteger multiply(BigInteger val)
BigInteger divide(BigInteger val)
BigInteger remainder(BigInteger val)
2.7 java.math.BigDecimal 클래스
Double 타입으로 표현할 수 있는 값은 상당히 범위가 넓지만, 정밀도가 최대 13자리 밖에 되지 않고 실수형의 특성상 오차를 피할 수 없다. BigDecimal은 실수형과 달리 정수를 이용해서 실수를 표현한다. 앞에서 배운 것과 같이 실수의 오차는 10진 실수를 2진 실수로 정확히 변환할 수 없는 경우가 있기 때문에 발생하는 것이므로, 오차가 없는 2진 정수로 변환하여 다루는 것이다. 실수를 정수와 10의 제곱의 곱으로 표현한다.
정수 x 10 ^ scale
BigDecimal의 생성
BigDecimal val;
val = new BigDecimal("123.4567890");
val = new BigDecimal(123.4567);
private final BigInteger intVal;
private final int scale;
private transient int precision;