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)

  • 실행시에 필요한 클래스를 동적으로 메모리에 로드하는 역할
  • 클래스 로드 순서
    1. 기존에 생성된 클래스 객체가 메모리에 존재하는지 확인
    2. 클래스패스(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] + ",");
    }
  }
}

단계별로 설명하면 아래의 스텝을 거친다.

  1. 정규식을 매개변수로 Pattern클래스의 static 메서드인 Pattern compile(String regex)을 호출하여 Pattern 인스턴스를 얻는다.
Pattern p = Pattern.compile("c[a-z]*");
  1. 정규식으로 비교할 대상을 매개변수로 Pattern클래스의 Matcher matcher (CharSequence input)를 호출해서 Matcher인스턴스를 얻는다.
Matcher m = p.matcher(data[i]);
  1. 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;