[윤성우의 열혈 Java 프로그래밍] Chapter 20 - 자바의 기본 클래스

Update:     Updated:

카테고리:

태그:

20-1. 래퍼 클래스 (Wrapper 클래스)

래퍼 클래스는 이름이 의미하듯이 ‘기본 자료형의 값들을 감싸는 클래스’이다.

- 기본 자료형의 값을 감싸는 래퍼 클래스

래퍼 클래스는 기본 자료형의 값을 감싸는 클래스이다.
모든 기본 자료형을 대상으로 래퍼 클래스가 정의되어 있다.

// Boolean
public Boolean(boolean value)

// Character
public Character(char value)

// Byte
public Byte(byte value)

// Short
public Short(short value)

// Integer
public Integer(int value)

// Long
public Integer(long value)

// Float
public Float(float value), public Float(double value)

// Double
public Double(double value)

- 래퍼 클래스의 두 가지 기능

하나는 값을 인스턴스로 감싸는 것이고, 다른 하나는 인스턴스에서 값을 꺼내는 것이다.
image

  • 박싱(Boxing): 값을 인스턴스에 감싸는 행위
  • 언박싱(Unboxing): 저장된 값을 꺼내는 행위
Integer iObj = new Integer(10); // 박싱
Double dObj = new Double(3.14); // 박싱

int num1 = iObj.intValue(); // 언박싱
double num2 = dObj.doubleValue();   // 언박싱

래퍼 인스턴스들은 담고 있는 값을 수정하지 못한다.
따라서 값의 수정이 필요하면 새로운 래퍼 인스턴스를 생성해야 한다.

iObj = new Integer(iObj.intValue() + 10);
dObj = new Double(dObj.doubleValue() + 1.2);

- 오토 박싱(Auto Boxing) & 오토 언박싱(Auto Unboxing)

자바 5부터 박싱과 언박싱이 필요한 상황에서 이를 자동으로 처리하기 시작했다.
이를 오토 박싱, 오토 언박싱이라 한다.

Integer iObj = 10;  // 오토 박싱 진행
Double dObj = 3.14  // 오토 박싱 진행

int num1 = iObj;    // 오토 언박싱
double num2 = dObj; // 오토 언박싱

iObj++; // 오토 박싱, 오토 언박싱 동시 진행

20-2. BigInteger 클래스와 BigDecimal 클래스

- 매우 큰 정수의 표현을 위한 java.math.BigInteger 클래스

일반적인 범위를 넘어서는 매우 큰 수의 표현을 위해 자바는 BigInteger 클래스를 제공한다.

BigInteger big1 = new BigInteger("10000000000000000000000");
BigInteger big2 = new BigInteger("-9999999999999999999999");

그리고 이렇게 표현한 큰 수를 연산하는 다양한 메소드가 정의되어있다.

public BigInteger add(BigInteger val);  // 덧셈
public BigInteger subtract(BigInteger val); // 뺄셈
public BigInteger multiply(BigInteger val); // 곱셈
public BigInteger divide(BigInteger val); // 나눗셈의 몫
public BigInteger remainder(BigInteger val);  // 나눗셈의 나머지

연산을 통해 그 값이 int형 또는 long형으로 표현이 가능한 수준에 이르면 다음 메소드의 호출로 인스턴스에 저장된 값을 얻을 수 있다.

public long longValueExact(); // BigInteger 인스턴스에 저장된 값을 long형 정수로 반환
public int intValueExact(); // BigInteger 인스턴스에 저장된 값을 int형 정수로 반환

- 오차 없는 실수의 표현을 위한 java.math.BigDecimal 클래스

BigDecimal 클래스는 오차 없는 실수의 표현을 위해 제공되는 클래스이다.

// 정상적인 방법
BigDecimal d1 = new BigDecimal("1.6");
BigDecimal d2 = new BigDecimal("0.1");

// 가능은 하지만 오차 발생(실수는 표현되는 순간부터 오차를 지니기 때문)
BigDecimal d1 = new BigDecimal(1.6);
BigDecimal d2 = new BigDecimal(0.1);

BigDecimal 클래스에도 다음 사칙연산을 포함하여 다양한 연산을 위한 메소드가 정의되어 있다.

public BigDecimal add(BigDecimal augend); // 덧셈
public BigDecimal subtract(BigDecimal subtrahend);  // 뺄셈
public BigDecimal multiply(BigDecimal multiplicand);  // 곱셈
public BigDecimal divide(BigDecimal divisor); // 나눗셈

20-3. Math 클래스와 난수의 생성, 그리고 문자열 토큰(Tocken)의 구분

- 수학 관련 다양한 연산의 제공을 위한 Math 클래스

Math 클래스에 정의된 여러 static 메소드에 대해서 알아보자.

public class SimpleMathUse {
    public static void main(String[] args) {
        System.out.println("원주열: " + Math.PI);
        System.out.println("2의 제곱근: " + Math.sqrt(2));
        System.out.println();

        System.out.println("파이에 대한 Degree: " + Math.toDegrees(Math.PI));
        System.out.println("2 파이에 대한 Degree: " + Math.toDegrees(2 * Math.PI));
        System.out.println();

        double radian45 = Math.toRadians(45);   // 디그리 단위의 값을 라디안 값으로 변환!
        System.out.println("싸인 45: " + Math.sin(radian45));
        System.out.println("코싸인 45: " + Math.cos(radian45));
        System.out.println("탄젠트 45: " + Math.tan(radian45));
        System.out.println();

        System.out.println("로그 25: " + Math.log(25));
        System.out.println("2의 16승: " + Math.pow(2, 26));
    }
}

image

- 난수(Random Number)의 생성

난수는 예측 불가능한 수를 의미한다.
자바에서 난수를 생성하는 방법은 java.util.Random 클래스의 인스턴스를 이용하면 된다.

Random rand = new Random();

// 메소드
public boolean nextBoolean(); // boolean형 난수 반환
public int nextInt(); // int형 난수 반환
public long nextLong(); // long형 난수 반환
public float nextFloat(); // 0.0 이상 1.0 미만의 float형 난수 반환
public double nextDouble(); // 0.0 이상 1.0 미만의 double형 난수 반환

- 씨드(Seed) 기반의 난수 생성

컴퓨터가 난수를 생성하는 것은 일종의 패턴이 있다.
이 값을 씨드 값(Seed Number)라고 하는데, 난수 생성 알고리즘은 이 숫자를 기반으로 돌아가기 때문에 이 값이 같으면 생성되는 난수의 패턴은 100% 일치한다.

import java.util.Random;

public class GanRandom {
    public static void main(String[] args) {
        Random rand = new Random(10);  // seed 값을 전달받음

        for (int i = 0; i < 5; i++) {
            System.out.println(rand.nextInt(1000));
        }
    }
}

사실 씨드 값을 별도로 전달하지 않고 Random 인스턴스를 생성해도 내부에서는 다음과 같은 방식으로 씨드 값을 설정한다.

Random rand = new Random();

public Random() {
  this(System.currentTimeMillis());
}

- 문자열의 토큰(Token) 구분

StringTokenizer 클래스를 이용하면 특정 기준을 가지고 문자열을 작게 나눌 수 있다.

// StringTokenizer 생성자
public StringTokenizer(String str, String delim);

// 반환할 토큰이 남아있나
public boolean hasMoreTokens();

// 다음 토큰을 반환
public String nextToken();
import java.util.StringTokenizer;

public class TokenizeString {
    public static void main(String[] args) {
        StringTokenizer st1 = new StringTokenizer("PM:08:45", ":");
        while (st1.hasMoreTokens()) {
            System.out.print(st1.nextToken() + " ");
        }

        System.out.println();

        // 구분자로 여러 개를 설정할 수 있다.
        StringTokenizer st2 = new StringTokenizer("12 + 36 - 8 / 2 = 44", "+-/= ");
        while (st2.hasMoreTokens()) {
            System.out.print(st2.nextToken() + " ");
        }
    }
}

20-4. Arrays 클래스

java.util.Arrays 클래스는 배열 조작에 도움을 주는 메소드들로 채워져 있다.
이 클래스의 메소드들을 이용해 배열의 복사, 비교, 정렬 및 탐색을 손쉽게 진행해보자.

- 배열의 복사

image
image
image

import java.util.Arrays;

public class CopyOfArrays {
    public static void main(String[] args) {
        int n = 3;
        double[] originArray = {1.1, 2.2, 3.3, 4.4, 5.5};

        // copyOf 메소드: 첫 번째 요소부터 n번째 요소까지 배열 복사
        double[] copyArray1 = Arrays.copyOf(originArray, n);

        // copyOfRange 메소드: 인덱스 번호 from 부터 to 이전 요소까지 복사
        double[] copyArray2 = Arrays.copyOfRange(originArray, 1, 4);

        // 이미 존재하는 배열에 복사를 하려는 경우
        // 배열 org의 인덱스 1에서 배열 copyArray3의 인덱스 1로 n 개의 요소 복사
        double[] copyArray3 = new double[4];
        System.arraycopy(originArray, 1, copyArray3, 1, n);

        for (double i : copyArray1) {
            System.out.print(i + " ");
        }
        System.out.println();
        for (double i : copyArray2) {
            System.out.print(i + " ");
        }
        System.out.println();
        for (double i : copyArray3) {
            System.out.print(i + " ");
        }
    }
}

image

- 배열의 비교

image
위의 메소드는 두 배열에 저장된 데이터의 수, 순서, 그리고 내용이 같을 때 true를 반환한다.(배열의 길이가 다른 경우에도 false를 반환한다.)

public static boolean equals(Object[] a, Object[] a2);

이 메소드는 Object형 배열에 대해서도 오버로딩 되어 있다.
Object 클래스에 정의되어 있는 equals 메소드는 참조 값 비교를 진행한다.
따라서, 배열의 참조 값 비교가 아닌 내용 비교가 목적이라면 다음과 같이 equals 메소드를 목적에 맞게 오버라이딩 해야 한다.

import java.util.Arrays;

class INum {
  private int num;

  public INum(int num) {
    this.num = num;
  }

  @Override
  public boolean equals(Object obj) {
    if (this.num == ((Num)obj).num) { // 두 인스턴스의 내용 비교
      return true;
    } else {
      return false;
    }
  }
}

class ArrayObjEquals {
  public static void main(String[] args) {
    INum[] ar1 = new INum[3];
    INum[] ar2 = new INum[3];

    ar1[0] = new INum(1); ar2[0] = new INum(1);
    ar1[1] = new INum(2); ar2[1] = new INum(2);
    ar1[2] = new INum(3); ar2[2] = new INum(3);

    System.out.println(Arrays.equals(ar1, ar2));  // true
  }
}

- 배열의 정렬

image

int[] ar = {1, 5, 3, 2, 4};
Arrays.sort(ar);

이 메소드는 다음과 같이 Object 배열에 대해서도 오버로딩 되어 있다.

public static void sort(Object[] a)

인스턴스의 참조 값을 저장하고 있는 배열에 대한 정렬은 무엇을 기준으로 할까?
다음 인터페이스의 구현을 기반으로 프로그래머가 클래스 별로 결정하게 되어 있다.

image
위 인터페이스에 존재하는 추상 메소드 compareTo의 구현 방법은 다음과 같다.

  • 인자로 전달된 o가 작다면 양의 정수 반환
  • 인자로 전달된 o가 크다면 음의 정수 반환
  • 인자로 전달된 o와 같다면 0을 반환

다음의 예시를 통해 compareTo 메소드를 어떻게 구성하는지 살펴보자.

import java.util.Arrays;

class Person implements Comparable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }

    /**
     * 나이가 어린 인스턴스의 크기가 작은 것으로 결정한다.
     *
     * @param o the object to be compared.
     * @return
     */
    @Override
    public int compareTo(Object o) {
        Person p = (Person) o;
        return this.age - p.age;
//        if (this.age > ((Person)o).age) return 1;
//        else if (this.age < ((Person)o).age) return -1;
//        else return 0;
    }
}

public class ArrayObjSort {
    public static void main(String[] args) {
        Person[] ar = new Person[3];
        ar[0] = new Person("Kim", 22);
        ar[1] = new Person("Choi", 26);
        ar[2] = new Person("Park", 24);

        Arrays.sort(ar);
        for (Person p : ar) {
            System.out.println(p);
        }
    }
}

image

- 배열의 탐색

image

import java.util.Arrays;

public class ArraySearch {
    public static void main(String[] args) {
        int[] ar = {33, 55, 11, 44, 22};

        Arrays.sort(ar);    // 탐색 이전에 정렬이 선행되어야 한다.

        for (int n : ar) {
            System.out.print(n + " ");
        }
        System.out.println();

        int idx = Arrays.binarySearch(ar, 33);
        System.out.println("Index of 33: " + idx);
    }
}

이진 탐색(Binary Search)라는 알고리즘을 기반으로 탐색을 진행하기 때문에 정렬 과정이 선행되어야한다.

public static int binarySearch(Object[] a, Object key)

마찬가지로 Object형 배열에 대해서도 오버로딩되어있고,
마찬가지로 이 메소드를 사용하기 위해 Comparable 인터페이스를 구현하고 compareTo 메소드를 오버라이딩하면 된다.

import java.util.Arrays;

class Person implements Comparable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }

    /**
     * 탐색 기준: 이름
     *
     * @param o the object to be compared.
     * @return
     */
    @Override
    public int compareTo(Object o) {
        Person p = (Person) o;
        return this.name.compareTo(p.name);
    }
}

public class ArrayObjSearch {
    public static void main(String[] args) {
        Person[] ar = new Person[3];
        ar[0] = new Person("Kim", 22);
        ar[1] = new Person("Choi", 26);
        ar[2] = new Person("Park", 24);

        Arrays.sort(ar);

        int idx = Arrays.binarySearch(ar, new Person("Choi", 26));
        System.out.println(ar[idx]);  // choi: 26
    }
}

image

Java lang 카테고리 내 다른 글 보러가기

댓글 남기기