Java - 12 (자바 API 클래스)

hoegon kim·2022년 12월 6일
0

JAVA

목록 보기
12/26
post-thumbnail

47) Object 클래스


java.lang 패키지

java.lang 패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합입니다.

따라서 자바에서는 java.lang 패키지의 클래스들은 import 문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있도록 하고 있습니다.


java.lang.Object 클래스

java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 object 클래스입니다.

Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 됩니다.

따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있습니다.

이러한 Object 클래스는 필드를 가지지 않으며, 총 11개의 메소드만으로 구성되어 있습니다.


toString() 메소드

toString() 메소드는 해당 인스턴스에 대한 정보를 문자열로 반환합니다.

이때 반환되는 문자열은 클래스 이름과 함께 구분자로 '@'가 사용되며, 그 뒤로 16진수 해시 코드(hash code)가 추가 됩니다.

16진수 해시 코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스 마다 모두 다르게 반환됩니다.

다음 예제는 toString() 메소드를 이용하여 인스턴스의 정보를 출력하는 예제입니다.

<예제>

Car car01 = new Car();
Car car02 = new Car();

System.out.printIn(car01.toString());
System.out.printIn(car02.toString());

결과
Car@15db9742
Car@6d06d69c

※ 자바에서 toString() 메소드는 기본적으로 각 API 클래스 마다 자체적으로 오버라이딩을 통해 재정의되어 있습니다.


equals() 메소드

equals() 메소드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여, 그 결과를 반환합니다.

이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나 false를 반환하게 됩니다.

다음 예제는 equals() 메소드를 이용하여 두 인스턴스를 서로 비교하는 예제입니다.

<예제>


Car car01 = new Car();
Car car02 = new Car();

System.out.printIn(car01.equals(car02));
car01 = car02;		// 두 참조 변수가 같은 주소를 가리킴
System.out.printIn(car01.equals(car02));

실행결과
false
true

※ 자바에서 equals() 메소드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재 정의 되어 있습니다.


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;}	// modelName의 값을 반환함
 
 public void setModelName(String modelName){this.modelName = modelName;}	// modelName의 값을 설정함
 
 public ArrayList getOwners(){return this.owners;}		// owners의 값을 반환함
 
 public void setOwners(String ownerName) { this.owners.add(ownerName); }   // owners의 값을 추가함



    public Object clone() {

        try {

②          Car clonedCar = (Car)super.clone();

③          // clonedCar.owners = (ArrayList)owners.clone();

            return clonedCar;

④      } catch (CloneNotSupportedException ex) {

            ex.printStackTrace();

            return null;

        }
}



public class Object03 {

    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 : 아반떼, [홍길동]
Car02 : 아반떼, [홍길동, 이순신]
Car02 : 아반떼, [홍길동, 이순신]

위 예제의 ②번 라인에서는 부모 클래스의 clone() 메소드를 호출하여 clone() 메소드를 오버라이딩하고 있습니다.

⑤번 라인에서는 Car 클래스의 인스턴스인 car01을 생성하고, ⑦번 라인에서는 오버라이딩한 clone() 메소드를 호출하여 복제를 수행하고 있습니다.

하지만 ②번 라인처럼 clone() 메소드를 재정의하면, 필드의 값이 ①번 라인처럼 인스턴스일 때는 제대로 된 복제를 수행할수 없습니다.

⑧번 라인에서는 복제된 인스턴스인 car02의 owners 필드에 새로운 값을 하나 추가합니다.

하지만 ⑨번 라인의 실행 결과를 보면, ⑦번 라인의 결과와는 달리 원본 인스턴스인 car01의 owners 필드에도 새로운 값이 추가되었음을 확인할 수 있습니다.

이처람 단순히 부모 클래스의 clone() 메소드를 호출하여 clone()메소드를 재정의하면, 배열이나 인스턴스인 필드는 보제되는 것이 아닌 해당 배열이나 인스턴스를 가리키는 주소값만 복제되는것입니다.

따라서 정확한 복제를 위해서는 ③번 라인처럼 배열이나 인스턴스인 필드에 대해서는 별도로 clone() 메소드를 구현하여 호출해야 합니다.

③번 라인의 주석을 해제하고 결과보기를 다시 실행하면, 다음과 같이 정확한 실행결과가 출력될 것입니다.

Car01 : 아반떼, [홍길동]

 
Car02 : 아반떼, [홍길동]

Car02 : 아반떼, [홍길동, 이순신]

Object 메소드

Object 클래스의 메소드는 다음과 같습니다.


48) String 클래스


java.lang.String 클래스

C 언어에서는 문자열을 char형 배열로 표현하지만, 자바에서는 문자열을 위한 String이라는 클래스를 별도로 제공합니다.

String 클래스에는 문자열과 관련된 작업을 할 때 유용하게 사용할 수 있는 다양한 메소드가 포함되어 있습니다.

이러한 String 클래스는 java.lang 패키지에 포함되어 제공됩니다.

String 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없습니다.

이러한 객체를 자바에서 불변 객체(immutable object)라고 합니다.

즉, 자바에서 덧셈(+) 연산자를 이용하여 문자열 결합을 수행하면, 기존 문자열의 내용이 변경되는 것이 아니라 내용이 합쳐진 새로은 String 인스턴스가 생성되는 것입니다.


charAt() 메소드

charAt() 메소드는 해당 문자열의 특정 인덱스를 해당하는 문자를 반환합니다.

만약 해당 문자열의 길이보다 큰 인덱스나 음수를 전달하면, IndexOutOfBoundsException 오류가 발생합니다.

다음 예제는 문자열의 각 문자를 charAt() 메소드를 이용하여 하나씩 출력하는 예제입니다.

예제 

String str = new String("Java");

System.out.printIn("원본 문자열 : " + str);

for(int i=0; i< str.length(); i++){
	System.out.print(str.charAt(i) + "")
}

System.out.printIn("\ncharAt() 메소드 호출 후 원본 문자열 : " + str);

실행결과

원본 문자열 : Java

J a v a 

charAt() 메소드 호출 후 원본 문자열 : Java

compareTo() 메소드

compareTo() 메소드는 해당 문자열을 인수로 전달된 문자열과 사전 편찬 순으로 비교합니다.

이 메소드는 문자열을 비교할 때 대소문자를 구분하여 비교합니다.

만약 두 문자열이 같다면 0을 반환하며, 해당 문자열이 인수로 전달된 문자열보다 작으면 음수를,크면 양수를 반환합니다.

만약 문자열을 비교할 때 대소문자를 구분하지 않기를 원한다면, compareTolgnoreCase() 메소드를 사용하면 됩니다.

다음 예제는 compareTo() 메소드와 compareTolgnoreCase() 메소드를 이용하여 두 문자열을 비교하는 예제입니다.

예제

String str = new String("abcd");

System.out.println("원본 문자열 : " + str);

 

System.out.println(str.compareTo("bcef"));

System.out.println(str.compareTo("abcd") + "\n");

 

System.out.println(str.compareTo("Abcd"));

System.out.println(str.compareToIgnoreCase("Abcd"));

System.out.println("compareTo() 메소드 호출 후 원본 문자열 : " + str);

결과

원본 문자열 : abcd

-1

0

32

0

compareTo() 메소드 호출 후 원본 문자열 : abcd

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

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() 메소드는 문자나 문자열을 찾을 때 대소문자를 구분합니다.


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

toLowerCase()와 toUpperCase()

toLowerCase() 메소드는 해당 문자열의 모든 문자를 소문자로 변환시켜 줍니다.

또한, toUpperCase() 메소드는 해당 문자열의 모든 문자를 대문자로 변환시켜 줍니다.

다음 예제는 toLowerCase() 메소드를 이용하여 문자열의 대문자를 변경하는 예제입니다.

<예제>

String str = new String("Java");
System.out.printIn("원본 문자열 :" + str);

System.out.printIn(str.toLowerCase());
System.out.printIn(str.toUpperCase());
System.out.printIn("두 메소드 호출 후 원본 문자열 :" + str);

실행결과

원본 문자열 : Java

java

JAVA

두 메소드 호출 후 원본 문자열 : Java

대표적인 String 메소드

String 클래스의 메소드는 매우 다양하며, 그 중에서 많이 사용되는 메소드는 다음과 같습니다.


49) StringBuffer 클래스


java.lang.StringBuffer 클래스

String 클래스의 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없습니다.

하지만 StringBuffer 클래스의 인스턴스는 그 값을 변경할 수도 있고, 추가할 수도 있습니다.

이를 위해 StringBuffer 클래스는 내부적으로 버퍼(buffer)라고 하는 독립적인 공간을 가집니다.

버퍼 크기의 기본값은 16개의 문자를 저장할 수 있는 크기이며, 생성자를 통해 그 크기를 별도로 설정할 수도 있습니다.

하지만인스턴스 생성 시 사용자가 설정한 크기보다 언제나 16개의 문자를 더 저장할 수 있도록 여유 있는 크기로 생성됩니다.

덧셈(+) 연산자를 이용해 String 인스턴스의 문자열을 결합하면, 내용이 합쳐진 새로운 String 인스턴스를 생성합니다.

따라서 문자열이 많이 결합하면 결합할수록 공간의 낭비뿐만 아니라 속도 또한 매우 느려지게 됩니다.

하지만 StringBuffer 인스턴스를 사용하면 문자열을 바로 추가할 수 있으므로, 공간의 낭비도 없으며 속도도 매우 빨라집니다.

이러한 StringBuffer 클래스는 java.lang 패키지에 포함되어 제공됩니다.


불변 클래스(immutable class)와 가변 클래스(mutable class)

String 클래스와 같이 인스턴스가 한 번 생성되면 그 값을 변경할 수 없는 클래스를 불변 클래스(immutable class)라고 합니다.

반대로 StringBuffer 클래스와 같이 자유롭게 인스턴스의 값을 변경할 수 있는 클래스를 가변 클래스(mutable class)라고 합니다.

String 클래스와 같은 불변 클래스는 StringBuffer 클래스의 append()나 insert()메소드와 같이 값을 변경하는 set메소드를 포함하지 않습니다.

이렇게 불편하기만 할 것 같은 불변 클래스를 사용하는 이유는 멀티 스레드 한경에서 객체가 변화되는 상황이라면 불변 인스턴스를 사용하는 것이 좀 더 신뢰할 수 있는 코드를 작성할 수 있기 때문입니다.

즉, 하나의 객체에 접근하면서 각각의 객체가 서로 영향을 주어서는 안되는 경우에 불변 인스턴스를 사용하면 값이 변하지 않는다는 점이 보장됩니다.


append() 메소드

append()메소드는 인수로 전달된 값을 문자열로 변환한 후, 해당 문자열의 마지막에 추가합니다.

이 메소드는 String클래스의 concat() 메소드와 같은 결과를 반환하지만, 내부적인 처리 속도가 훨씬 빠릅니다.

다음 예제는 append() 메소드를 이용하면 한 문자열에 다른 문자열을 추가하는 예제입니다.

<예제>
StringBuffer str = new StringBuffer("Java");
System.out.printIn("원본 문자열 :" + str);

System.out.printIn(str.append("수업"));
System.out.printIn("append() 메소드 호출 후 원본 문자열 :" + str);

결과

원본 문자열 : Java

Java수업

append() 메소드 호출 후 원본 문자열 : Java수업

capacity() 메소드

capacity() 메소드는 StringBuffer 인스턴스의 현재 버퍼 크기를 반환합니다.

다음 예제는 capacity() 메소드를 이용하여 StringBuffer 인스턴스의 현재 버퍼 크기를 알아보는 예제입니다.

StringBuffer str01 = new StringBuffer();
StringBuffer str02 = new StringBuffer("Java");

System.out.printIn(str01.capacity());
System.out.printIn(str02.capacity());

결과

16
20

위의 예제 처럼 길이가 4인 문자열로 StringBuffer 인스턴스를 생성하면, 기본적으로 생성되는 여유 버퍼 크기인 16에 문자의 길이인 4를 더한 총 20개의 문자를 저장할 수 있는 버퍼가 생성되는 것을 확인할 수 있습니다.


delete() 메소드

delete() 메소드는 전달된 인덱스에 해당하는 부분 문자열을 해당 문자열에서 제거합니다.

또한, deleteCharAt() 메소드를 사용하면 특정 위치의 문자 한 개만을 제거할 수도 있습니다.

다음 예제는 delete() 메소드를 이용하여 해당 문자열의 특정 부분을 제거하는 예제입니다.

StringBuffer str = new StringBuffer("Java Oracle");
System.out.printIn("원본 문자열 :" + str);

① System.out.printIn(str.delete(4,8));
System.out.printIn(str.deleteCharAt(1));
System.out.printIn("deleteCharAt() 메소드 호출 후 원본 문자열 :" + str);

결과

원본 문자열 : Java Oracle

Javacle

Jvacle

deleteCharAt() 메소드 호출 후 원본 문자열 : Jvacle

위 예제의 ①번 라인에서는 delete() 메소드를 사용하여 해당 문자열에서 인덱스가 4인 위치의 문자부터 7인 위치의 문자까지를 삭제하고 있습니다.

이 처럼 delete() 메소드는 첫 번째 매개변수로 전달된 인덱스부터 두 번째 매개변수로 전달된 인덱스 바로 앞의 문자까지를 삭제하는 메소드입니다.


insert() 메소드

insert() 메소드는 인수로 전달된 값을 문자열로 변환한 후, 해당 문자열의 지정된 인덱스 위치에 추가합니다.

이때 전달된 인덱스가 해당 문자열의 길이와 같으면, append() 메소드와 같은 결과를 반환합니다.

다음 예제는 insert() 메소드를 이용하여 한 문자열 중간에 다른 문자열을 삽입하는 예제입니다.

StringBuffer str = new StringBuffer("Java 만세 !!");
System.out.printIn("원본 문자열 : " + str)

① System.out.printIn(str.insert(4, "Script"));
System.out.printIn("insert() 메소드 호출 후 원본 문자열 : " + str);

결과

원본 문자열 : Java 만세!!

JavaScript 만세!!

insert() 메소드 호출 후 원본 문자열 : JavaScript 만세!!

위 예제의 ①번 라인에서는 insert() 메소드를 사용하여 해당 문자열에서 인덱스가 4인 위치부터 두 번째 매개변수로 전달된 문자열을 추가하고 있습니다.


대표적인 StringBuffer 메소드

StringBuffer 클래스의 메소드는 매우 다양하며, 그중에서 많이 사용되는 메소드는 다음과 같습니다.


50) Math 클래스


java.lang.Math 클래스

Math 클래스는 수학에서 자주 사용하는 상수들과 함수들을 미리 구현해 놓은 클래스입니다.

Math 클래스의 모든 메소드는 클래스 메소드(static method)이므로,객체를 생성하지 않고도 바로 사용할 수 있습니다.

이러한 Math 클래스는 java.lang 패키지에 포함되어 제공됩니다.


Math.E 와 Math.PI

Math 클래스에 정의되어 있는 클래스 필드는 다음과 같습니다.

  1. Math.E : 오일러의 수라 불리며, 자연로그(natural logarithms)의 밑(base) 값으로 약 2.718을 의미합니다.

  2. Math.PI : 원의 원주를 지름으로 나눈 비율(원주율)값으로 약 3.14159를 의미합니다.


random() 메소드

random() 메소드는 0.0이상 1.0미만의 범위에서 임의의 double형 값을 생성하여 반환합니다.

이 메소드는 내부적으로 java.util 패키지의 Random 클래스를 사용한 의사 난수 발생기(peudorandom-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

자바에서는 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

abs() 메소드

abs() 메소드는 전달된 값이 음수이면 그 값의 절댓값을 반환하며, 전달된 값이 양수이면 전달된 값을 그대로 반환합니다.

(int)(Math.random() * 6);       // 0 ~ 5

((int)(Math.random() * 6) + 1); // 1 ~ 6

((int)(Math.random() * 6) + 3); // 3 ~ 8

결과

10
10
3.14


floor() 메소드, ceil() 메소드와 round() 메소드

floor() 메소드는 인수로 전달받은 값과 같거나 작은 수 중에서 가장 큰 정수를 반환합니다.

또한, ceil() 메소드는 반대로 인수로 전달받은 값과 같거나 큰 수 주에서 가장 작은 정수를 반환합니다.

round() 메소드는 전달받은 실수를 소수점 첫째 자리에서 반올림한 정수를 반환합니다.

예제

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

 

System.out.println(Math.floor(10.0));     // 10.0

System.out.println(Math.floor(10.9));     // 10.0

 

System.out.println(Math.round(10.0));     // 10

System.out.println(Math.round(10.4));     // 10

System.out.println(Math.round(10.5));     // 11

결과

10.0

11.0

11.0

 

10.0

10.0

 

10

10

11

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

결과

3.14159

3.14

-10

-11

pow() 메소드와 sqrt() 메소드

pow() 메소드는 전달된 두 개의 double형 값으 가지고 제곱 연산을 수행합니다.

예를 들어, pow(a,b)는 a의 b 승, 즉 a^b를 반환하게 됩니다.

반대로 sqrt() 메소드는 전달된 double형 값의 제곱근 값을 반환합니다.


System.out.println((int)Math.pow(5, 2)); // 25

System.out.println((int)Math.sqrt(25));  // 5

결과

25
5


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

위의 예제처럼 자바의 삼각 함수에 관한 메소드는 정확한 값을 나타내지 못합니다.

그 이유는 컴퓨터가 실수를 나타내는 데 사용하는 부동 소수점 방식의 한계로 모든 언어에서 공통으로 발생하는 문제입니다.

실수의 표현에 대한 더 자세한 사항은 자바 실수의 표현 수업에서 확인할 수 있습니다.


대표적인 Math 메소드

Math 클래스의 메소드는 매우 다양하며, 그중에서 많이 사용되는 메소드는 다음과 같습니다.


51) Wrapper 클래스


래퍼 클래스

프로그램에 따라 기본 타입의 데이터를 객체로 취급해야 하는 경우가 있습니다.

예를 들어, 메소드의 인수로 객체 타입만이 요구되면, 기본 타입의 데이터를 그대로 사용할 수는 없습니다.

이때에는 기본 타입의 데이터를 먼저 객체로 변환한 후 작업을 수행해야 합니다.

이렇게 8개의 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스를 래퍼 클래스(Wrapper class)라고 합니다.

래퍼 클래스는 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어 줍니다.

이러한 래퍼 클래스는 모두 java.lang 패키지에 포함되어 제공됩니다.

자바의 기본 타입에 대응하여 제공하고 있는 래퍼 클래스는 다음과 같습니다.

※ 래퍼 클래스 중에서 Integer 클래스와 Character 클래스만이 자신의 기본 타입과 이름이 다름을 주의해야 합니다.


박싱(Boxing)과 언박싱(UnBoxing)

래퍼 클래스(Wrapper class)는 산술 연산을 위해 정의된 클래스가 아니므로, 인스턴스에 저장된 값을 변경할 수 없습니다.

단지, 값을 참조하기 위해 새로운 인스턴스를 생성하고, 생성된 인스턴스의 값만을 참조할 수 있습니다.

위의 그림과 같이 기본 타입의 데이터를 래퍼 클래스의 인스턴스로 변환하는 과정을 박싱(Boxing)이라고 합니다.

반면 래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정을 언박싱(UnBoxing)이라고 합니다.


오토 박싱(AutoBoxing)과 오토언박싱(AutoUnBoxing)

JDK 1.5부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 이를 자동으로 처리해 줍니다.

이렇게 자동화된 박싱과 언박싱을 오토 박싱(AutoBoxing)과 오토 언박싱(AutoUnBoxing)이라고 부릅니다.

다음 예제는 박싱과 언박싱, 오토 박싱과 오토 언박싱의 차이를 보여주는 예제입니다.


<예제>
Integer num = new Integer(17); // 박싱

int n = num.intValue();        // 언박싱

System.out.println(n);

 

Character ch = 'X'; // Character ch = new Character('X'); : 오토박싱

char c = ch;        // char c = ch.charValue();           : 오토언박싱

System.out.println(c);

결과

17
x

위의 예제에서 볼 수 있듯이 래퍼 클래스인 Interger 클래스와 Character 클래스에는 각각 언박싱을 위한 intValue() 메소드와 charValue() 메소드가 포함되어 있습니다.

또한, 오토 방식을 이용하면 new 키워드를 사용하지 않고도 자동으로 Character 인스턴스를 생성할 수 있습니다.

반대로 charValue() 메소드를 사용하지 않고도, 오토 언박싱을 이용하여 인스턴스에 지정된 값을 바로 참조할 수 있습니다.

따라서 다음 예제처럼 오토 박싱과 오토 언박싱을 통해 기본 타입과 래퍼 클래스 간의 다양한 연산도 가능해집니다.

public class Wrapper02 {

    public static void main(String[] args) {

        Integer num1 = new Integer(7); // 박싱

        Integer num2 = new Integer(3); // 박싱

 

        int int1 = num1.intValue();    // 언박싱

        int int2 = num2.intValue();    // 언박싱

 

①      Integer result1 = num1 + num2; // 10 

②      Integer result2 = int1 - int2; // 4

③      int result3 = num1 * int2;     // 21

    }

}

실행결과
10
4
21

위 예제의 ①번 부터 ③번 라인까지의 연산은 내부적으로 래퍼 클래스인 피연산자를 오토 언박싱하여 기본 타입끼리의 연산을 수행하고 있는 것입니다.


<예제>

public class Wrapper03 {

    public static void main(String[] args) {

        Integer num1 = new Integer(10);

        Integer num2 = new Integer(20);

        Integer num3 = new Integer(10);

 

        System.out.println(num1 < num2);       // true

①      System.out.println(num1 == num3);      // false

②      System.out.println(num1.equals(num3)); // true

    }

}

결과
true
false
true

래퍼 클래스의 비교 연산도 오토언박싱을 통해 가능해지지만, 인스턴스에 저장된 값의 동등 여부 판단은 ①번 라인처럼 비교 연산자인 동등 연산자(==)를 사용해서는 안 되며, ②번 라인처럼 equals() 메소드를 사용해야만 합니다.

래퍼 클래스도 객체이므로 동등 연산자(==)를 사용하게 되면, 두 인스턴스의 값을 비교하는 것이 아니라 두 인스턴스의 주소값을 비교하게 됩니다.

따라서 서로 다른 두 인스턴스를 동등 연산자(==)로 비교하게 되면, 언제나 false값을 반환되게 됩니다.

그러므로 인스턴스에 저장된 값의 동등 여부를 정확히 판단하려면 equals() 메소드를 사용해야만 합니다.


52) Enum 클래스


열거체(enumeration type)

C언어와 C++에서는 열거체를 사용할 수 있지만, JDK 1.5 이전의 자바에서는 열거체를 사용할 수 없었습니다.

하지만 JDK 1.5부터는 C언어의 열거체보다 더욱 향상된 성능의 열거체를 정의한 Enum 클래스를 사용할 수 있습니다.

이와 같은 자바의 열거체는 다음과 같은 장점을 가집니다.

  1. 열거체를 비교할 때 실제 값뿐만 아니라 타입까지도 체크합니다.
  2. 열거체의 상숫값이 재정의되더라도 다시 컴파일 할 필요가 없습니다.

열거체의 정의 및 사용

자바에서는 enum 키워드를 사용하여 열거체를 정의할 수 있습니다.

<문법>

enum 열거체 이름{상수1 이름, 상수2 이름,...}

<예제>

enum Rainbow{RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET}

이렇게 정의된 열거체를 사용하는 방법은 다음과 같습니다.

<문법>
열거체 이름.상수이름
<예제>

Rainbow.RED

열거체의 상숫값 정의 및 추가

위와 같이 정의된 열거체의 첫 번째 상숫값은 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;}


}

java.lang.Enum 클래스

Enum 클래스는 모든 자바 열거체의 공통된 조상 클래스입니다.
Enum 클래스에는 열거체를 조작하기 위한 다양한 메소드가 포함되어 있습니다.


values() 메소드

values() 메소드는 해당 열거체의 모든 상수를 저장한 배열을 생성하여 반환합니다.

이 메소드는 자바의 모든 열거체에 컴파일러가 자동으로 추가 해주는 메소드입니다.

enum Rainbow{RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET} 


public clas Enum01{
	public static void main(String[] args){
    	   Rainbow[] arr = Rainbow.values();

        for (Rainbow rb : arr) {

            System.out.println(rb);

        }
    }

}

결과

RED
ORANGE
YELLOW
GREEEN
BLUE
INDIGO
VIOLET


valueOf() 메소드

valueOf() 메소드는 전달된 문자열과 일치하는 해당 열거체의 상수를 반환합니다.

예제 

enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }

 

public class Enum02 {

    public static void main(String[] args) {

        Rainbow rb = Rainbow.valueOf("GREEN");

        System.out.println(rb);

    }

}

실행결과
GREEN


ordinal() 메소드

ordinal() 메소드는 해당 열거체 상수가 열거체 정의에서 정의된 순서(0부터 시작)를 반환합니다.

이때 반환되는 값은 열거체 정의에서 해당 열거체 상수가 정의된 순서이며, 상숫값 자체가 아님을 명심해야 합니다.


<예제>

enum Rainbow{RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET}

public class Enum03{
	public static void main(String[] args){
    	int idx = Rainbow.YELLOW.ordinal();
        System.out.printIn(idx);
    }

}

결과
2

다음 예제는 불규칙적인 상숫값을 가지는 열거체에서 ordinal() 메소드를 사용한 예제입니다.

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 class Enum04{
	public static void main(String[] args){
    	System.out.printIn(Rainbow.YELLOW.ordinal());
    }

}

결과
2


대표적인 Enum 메소드

Enum 클래스의 메소드는 다음과 같습니다.


53) Arrays 클래스


java.util 패키지

java.util 패키지에는 프로그램을 개발하는 데 사용할 수 있는 유용한 유틸리티 클래스가 다수 포함되어 있습니다.

실제로 java.lang 패키지 다음으로 가장 많이 사용되는 패키지가 java.util 패키지 입니다.

하지만 import 문을 사용하지 않아도 바로 사용할 수 있는 java.lang 패키지와는 달리 java.util 패키지는 import 문으로 패키지를 불러오고 나서야 클래스 이름만으로 사용할 수 있습니다.


java.util.Arrays 클래스

Arrays 클래스에는 배열을 다루기 위한 다양한 메소드가 포함되어 있습니다.

Arrays 클래스의 모든 메소드는 클래스 메소드(static method)이므로, 객체를 생성하지 않아도 바로 사용할 수 있습니다.

이 클래스는 java.util 패키지에 포함되므로, 반드시 import문으로 java.util 패키지를 불러오고 나서 사용해야 합니다.


binarySerch() 메소드

binarySerch() 메소드는 전달받은 배열에서 특정 객체의 위치를 이진 검색 알고리즘을 사용하여 검색한 후, 해당 위치를 반환합니다.

이 메소드는 이진 검색 알고리즘을 사용하므로, 매개변수로 전달되는 배열이 sort() 메소드 등을 사용하여 미리 정렬되어 있어야만 제대로 동작합니다.

<예제>
int[] arr = new int[1000];
for(int i = 0; i < arr.length; i ++){
	arr[i] = i;
}


System.out.printIn(Arrays.binarySearch(arr,437));

결과
437


copyOf() 메소드

copyOf() 메소드는 전달받은 배열의 특정 길이만큼을 새로운 배열로 복사하여 반환합니다.

copyOf() 메소드는 첫 번째 매개변수로 원본 배열을 전달받고, 두 번째 매개변수로 원본 배열에서 새로운 배열로 복사할 요소의 개수를 전달받습니다.

그리고 원본 배열과 같은 타입의 복사된 새로운 배열을 반환합니다.

이때 새로운 배열의 길이가 원본 배열보다 길면, 나머지 요소는 배열 요소의 타입에 맞게 다음과 같은 기본값으로 채워집니다.

<예제>

int[] arr1 = {1,2,3,4,5};
① int[] arr2 = Arrays.copyOf(arr1, 3);

for(int i = 0; i<arr2.length; i ++){
	System.out.print(arr2[i] + "");
}

② int[] arr3 = Arrays.copyOf(arr1, 10);

for (int i = 0; i < arr3.length; i++) {

    System.out.print(arr3[i] + " ");

}

결과
123
1234500000

위 예제의 ①번 라인에서는 copyOf() 메소드를 사용하여 배열 arr1의 첫 번째 요소부터 3개의 요소를 복사하여 배열 arr2에 대입하고 있습니다.

②번 라인에서는 배열 arr1에서 10개의 배열 요소를 복사하여 배열 arr3에 대입하려고 합니다.

하지만 배열 arr1의 길이가 5밖에 안되므로, 배열 arr3의 나머지 배열 요소에는 int형의 기본값인 0이 채워지게 됩니다.


copyOfRange() 메소드

copyOfRange() 메소드는 전달받은 배열의 특정 범위에 해당하는 요소만을 새로운 배열로 복사하여 반환합니다.

copyOfRange() 메소드는 첫 번째 매개변수로 복사의 대상이 될 원본 배열을 전달받습니다.

두 번째 매개변수로는 원본 배열에서 복사할 시작 인덱스를 전달 받고, 세 번째 매개변수로는 마지막으로 복사될 배열 요소의 바로 다음 인덱스를 전달 받습니다.

즉, 세 번째 매개변수로 전달된 인덱스 바로 전까지의 배열 요소까지만 복사됩니다.

그리고 원본 배열과 같은 타입의 복사된 새로운 배열을 반환합니다.

<예제>

int[] arr1 = {1, 2, 3, 4, 5};

 

int[] arr2 = Arrays.copyOfRange(arr1, 2, 4);

for (int i = 0; i < arr2.length; i++) {

    System.out.print(arr2[i] + " ");

}

결과
3 4


fill() 메소드

fill() 메소드는 전달받은 배열의 모든 요소를 특정 값으로 초기화해 줍니다.

fill() 메소드는 첫 번째 매개변수로 초기화할 배열을 전달받고, 두 번째 매개변수로 초기값을 전달 받습니다.

따라서 이 메소드는 전달받은 원본 배열의 값을 변경하게 됩니다.

<예제>

int[] arr = new int[10];

Arrays.fill(arr, 7);
for(int i = 0; i < arr.length; i++){
	System.out.prin()

}

결과
7 7 7 7 7 7 7 7 7 7


sort() 메소드

sort() 메소드는 전달받은 배열의 모든 요소를 오름차순으로 정렬합니다.

sort() 메소드는 매개변수로 정렬할 배열을 전달받으며, 따라서 이 메소드는 전달받은 원본 배열의 순서를 변경하게 됩니다.

<예제>

int[] arr = {5, 3, 4, 1, 2};

Arrays.sort(arr);
for(int i = 0; i< arr.length; i ++){
	System.out.print(arr[i] + "");
}

결과
1 2 3 4 5


대표적인 Arrays 메소드

Arrays 클래스의 메소드는 매우 다양하며, 그 중에서 많이 사용되는 메소드는 다음과 같습니다.


54) Calendar 클래스


자바에서의 날짜 및 시간 처리

JDK 1.0 에서는 Date 클래스를 사용하여 날짜에 관한 간단한 처리만을 수행할 수 있었습니다.

하지만 Date 클래스는 현재 대부분의 메소드가 사용을 권장하지 않고(deprecated)있습니다.

JDK 1.1 부터는 새롭게 제공되는 Calendar 클래스를 이용하여 날짜와 시간에 관한 처리를 수행하게 됩니다.

하지만 이러한 Calendar 클래스는 다음과 같은 문제점을 안고 있습니다.

  1. Calendar 인스턴스는 불변 객체(immutable object)가 아니라서 값이 수정될 수 있습니다.

  2. 윤초(leap second)와 같은 특별한 상황을 고려하지 않습니다.

  3. Calendar 클래스에서는 월(month)을 나타낼 때 1월부터 12월을 0부터 11까지로 표현해야 하는 불편함이 있습니다.

따라서 많은 자바 개발자들은 Calendar 클래스뿐만 아니라 더 나은 성능의 Joda-Time 이라는 라이브러리를 함께 사용해 왔습니다.

Java SE 8버전에서는 이러한 Joda-Time 라이브러리를 발전시킨 새로운 날짜와 시간 API인 java.time 패키지를 제공합니다.

java.time 패키지는 위와 같은 문제점을 모두 해결했으며, 다양한 기능을 지원하는 다수의 하위 패키지를 포함하고 있습니다.

java.time 패키지에 대한 더 자세한 사항은 JAVA8 java.time 패키지 수업에서 확인할 수 있습니다.

http://www.tcpschool.com/java/java_time_javaTime


java.util.Calendar 클래스

Calendar 클래스는 자바에서 날짜와 시간에 관한 데이터를 손쉽게 처리할 수 있도록 제공하는 추상 클래스입니다.

이 클래스가 추상 클래스로 선언된 이유는 나라마다 사용하는 달력 체계가 조금씩 다를 수 있기 때문입니다.

이러한 Calendar 클래스에는 날짜와 시간을 처리하기 위한 다양한 필드와 메소드가 포함되어 있습니다.

Calendar 클래스의 모든 필드는 클래스 변수(static variable)이므로, 객체를 생성하지 않고도 바로 사용할 수 있습니다.


java.util.GregorianCalendar 클래스

현재 전 세계적으로 가장 많이 사용되는 달력은 1582년 교황 그레고리오 13세가 개혁한 그레고리오 달력입니다.

Calendar 클래스는 추상 클래스이므로, 직접 인스턴스를 생성할 수 없습니다.

GregorianCalendar 클래스는 이러한 Calendar 클래스를 상속받아 그레고리오 달력을 완전히 구현한 하위 클래스입니다.


add() 메소드

add() 메소드는 전달된 Calendar 필드에서 일정 시간 만큼을 더하거나 빼줍니다.

즉, 특정 시간을 기준으로 일정 시간 전후의 날짜와 시간을 알 수 있습니다.

다음 예제는 add() 메소드를 이용하여 현재 시각에 120초를 더하는 예제입니다.

예제

Calendar time = Calendar.getInstance();
System.out.printIn(time.getTime());

time.add(Calendar.SECOND, 120);
System.out.prinIn(time.getTime());

결과
Thu Feb 16 08:57:29 KST 2017
Thu Feb 16 08:59:29 KST 2017

※ Calendar 클래스의 메소드는 현재 시각을 기준으로 동작하므로, 여러분의 결과는 위의 실행 결과와는 다를 것입니다.


before() 와 after() 메소드

두 시간상의 전후 관계만을 알고 싶을 경우에는 before() 와 after()메소드를 사용할 수 있습니다.

before() 메소드는 현재 Calendar 인스턴스가 전달된 객체가 나타내는 시간보다 앞서는지를 판단합니다.

반댜로 after() 메소드는 현재 Calendar 인스턴스가 전달된 객체가 나타내는 시간보다 나중인지를 판단합니다.


Calendar time1 = Calendar.getInstance();

Calendar time2 = Calendar.getInstance();

Calendar time3 = Calendar.getInstance();

 

time2.set(1982, 2, 19);

time3.set(2020, 2, 19);

 

System.out.println(time1.before(time2));

System.out.println(time1.before(time3));

결과

false
true


get() 메소드

get() 메소드는 전달된 Calendar 필드에 저장된 값을 반환합니다.

Calendar time = Calendar.getInstance();

 
System.out.println(time.getTime());

System.out.println(time.get(Calendar.DAY_OF_WEEK));

System.out.println(time.get(Calendar.MONTH) + 1);

System.out.println(time.get(Calendar.DAY_OF_MONTH));

System.out.println(time.get(Calendar.HOUR_OF_DAY));

System.out.println(time.get(Calendar.MINUTE));

System.out.println(time.get(Calendar.SECOND));

System.out.println(time.get(Calendar.YEAR));

결과

Thu Feb 16 08:57:44 KST 2017

5

2

16

8

57

44

2017

roll() 메소드

roll() 메소드는 전달된 Calendar 필드에서 일정시간 만큼을 더하거나 빼줍니다.

하지만 add() 메소드와는 달리 다른 Calendar 필드에서는 영향을 주지 않습니다.

즉, 계산 결과가 해당 필드의 최대값이나 최솟값을 넘어가도 다른 필드에 영향을 주지 않습니다.

Calendar time1 = Calendar.getInstance();

Calendar time2 = Calendar.getInstance();

System.out.println(time1.getTime());

 

time1.add(Calendar.SECOND, 60);

System.out.println(time1.getTime());

 

time2.roll(Calendar.SECOND, 60);

System.out.println(time2.getTime());

결과

Thu Feb 16 08:58:23 KST 2017
Thu Feb 16 08:59:23 KST 2017
Thu Feb 16 08:58:23 KST 2017

위의 예제에서 add() 메소드를 사용하여 Calendar.SECOND 필드를 60초 증가시키면 결과적으로 Calendar.MINUTE 필드가 1 증가해야합니다.

하지만 roll() 메소드를 사용하여 Calendar.SECOND 필드를 60초 증가시키면 Calendar.MINUTE 필드에는 아무런 영향을 주지않습니다.

즉, Calendar.SECOND 필드만이 60초 증가하여 결과적으로 같은 값이 출력되게 됩니다.


set() 메소드

set() 메소드는 전달된 Calendar 필드를 특정 값으로 설정합니다.

다음 예제는 set() 메소드에 다양한 형태의인수를 전달하여 시간을 설정하는 예제입니다.

Calendar time = Calendar.getInstance();

System.out.println(time.getTime());

 

time.set(Calendar.YEAR, 2020);

System.out.println(time.getTime());

 

time.set(1982, 1, 19); // 1은 2월을 나타냄.

System.out.println(time.getTime());

 

time.set(1982, 1, 19, 12, 34, 56);

System.out.println(time.getTime());

결과
Thu Feb 16 08:58:01 KST 2017
Sun Feb 16 08:58:01 KST 2020
Fri Feb 19 08:58:01 KST 1982
Fri Feb 19 12:34:56 KST 1982


대표적인 Calendar 메소드

Calendar 클래스의 메소드는 매우 다양하며, 그 중에서 많이 사용되는 메소드는 다음과 같습니다.

0개의 댓글