[Java] 자바 랩퍼(wrapper) 클래스와 boxing / unboxing


랩퍼(wrapper) 클래스

- 자바의 원시 데이터 타입(primitive type)을 다루는 클래스를 의미한다.

 *    byte      ---> java.lang.Byte

 *    short     ---> java.lang.Short

 *    int       ---> java.lang.Integer

 *    long      ---> java.lang.Long

 *    float     ---> java.lang.Float

 *    double    ---> java.lang.Double

 *    boolean   ---> java.lang.Boolean

 *    char      ---> java.lang.Character


왜 이런 클래스를 만들었는가?

- 프로그래밍을 하다보면 원시 데이터 타입의 값을 다뤄야 하는 경우가 있다.

예) Object obj = 20 (x)

     Object obj = new Integer(20); (o)

- 또 산술연산자나 관계연산자, 비트 논리연산자, 논리 연산자, 비트 이동 연산자, 조건

  연산자 외에 추가적인 기능을 클래스에 선언해 두었다.

예) Integer.parseInt(문자열)


- 오토 박싱(auto-boxing) :

  원시 데이터 타입과 랩퍼 클래스 간의 전환을 자동으로 처리하는 것

  ㄴ boxing : 원시 데이터 타입의 값을 랩퍼 클래스의 인스턴스에 담는 것

  ㄴ unboxing : 랩퍼 클래스의 인스턴스에서 원시 데이터 타입의 값을 자동으로 

                     추출하는 것




랩퍼(wrapper) 클래스의 boxing과 unboxing 예제


public static void main(String[] args) {
    int a = 10;
    Integer obj = new Integer(20);
   
    // 개발자가 명시적으로 랩퍼 객체에서 값을 꺼내는 코드
    int b = obj.intValue();
    int c = obj; // auto-unboxing : obj는 주소이지만 랩퍼 객체에서 값을 자동으로 추출해준다.
   
    // 개발자가 명시적으로 랩퍼 객체를 만들어 값을 담기
    Integer obj2 = new Integer(a);
    Integer obj3 = a; // auto-boxing : 원시 타입의 값을 자동으로 랩퍼 객체를 만들어 담는다.

 }





* 참고 : 다음 예제

  String 클래스와 랩퍼(wrapper) 클래스는 StringBuffer 클래스와 달리

  equals() 메서드를 오버라이딩 한다. 전자의 equals()는 주소가 아닌 값을 비교하고

  후자는 Object 클래스의 equals()를 자동으로 상속 받아 주소를 비교한다.




랩퍼(wrapper) 클래스의 equals() 메서드 예제


public static void main(String[] args) {
    Integer i1 = new Integer(10);
    Integer i2 = new Integer(10);
   
    System.out.println(i1 == i2);
    System.out.println(i1.equals(i2));
    System.out.println("---------------------------");
    /* String 클래스와 랩퍼 클래스는 equals() 메서드를 재정의 하였다.
     * => 어떻게?
     *    주소가 아닌 값이 같은지 비교하도록 재정의한다.
     */
   
    StringBuffer s1 = new StringBuffer("Hello");
    StringBuffer s2 = new StringBuffer("Hello");
   
    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));
    /* StringBuffer 클래스는 equals를 재정의하지 않았다.
     * 그래서 Object에 있는 equals()를 그대로 사용한다.
     * Object의 equals()는 주소를 비교한다. 즉 연산자 == 와 기능이 같다.
     */

  }

- 실행 결과 :

false

true

---------------------------

false

false










블로그 이미지

필로그래머

,

[Java] 자바 Object 클래스 - toString() 메서드의 재정의 예제


toSring() 메서드



// super 클래스를 지정하지 않으면 자동으로 Object가 수퍼 클래스가 된다.
public class Test03_2 /* extends Object */{
  static class Student1 {
    String name;
    int age;
   
    // toString()을 재정의 하지 않았기 때문에, Object 클래스의 toString()을 사용할 것이다.
  }
  static class Student2 {
    String name;
    int age;
   
    public String toString() {
      return String.format("이름: %s\n나이: %d\n", name, age);
    }
  }
 


 


public static void main(String[] args) {
    // Student 클래스가 정말 Object의 서브 클래스인지 확인해보자
    // 서브 클래스라면 수퍼클래스의 기능을 이용할 수 있어야 할 것이다.
    Student1 s1 = new Student1();
    s1.name = "홍길동";
    s1.age = 20;
   
    Student2 s2 = new Student2();
    s2.name = "임꺽정";
    s2.age = 30;
   
    System.out.println(s1.toString()); // 오리지널 toString() 호출
    System.out.println("------------------------");
    System.out.println(s2.toString()); // 재정의한 toString() 호출
   
  }

}


- 실행 결과 :

step08.Test03_2$Student1@15db9742 // 원본

------------------------

이름: 임꺽정                                  // 재정의

나이: 30

블로그 이미지

필로그래머

,

[Java] 자바 오버라이딩 (overriding)과 super 키워드


오버라이딩 (overriding)

- 수퍼 클래스 (super cass)의 메서드를 재정의 하는 방법

- 서브 클래스의 조건에 맞춰서 기능을 바꾸는 것이 목적이다.



수퍼 클래스 예제


public class Student {
  String name;
  int age;
 
  void print() {
//원칙    System.out.printf("이름 : %s\n", Student.this.name);
    System.out.printf("이름 : %s\n", name);
    System.out.printf("나이 : %d\n", age);
  }

}




서브 클래스 예제


public class BitStudent extends Student{

  String school;
 
  void print() {
    // 수퍼 클래스의 메서드를 재정의 할 때
    // 기존 코드를 복사/붙여넣기 하는 대신
    // 재정의하기 전의 기존 메서드를 호출하는 것이 편하다.
    /*
    System.out.printf("이름: %s\n", name);
    System.out.printf("나이: %d\n", age);
    */
    // 재정의 하기 전의 메서드를 가리키기 위해
    // (주의! 수퍼 클래스라는 의미가 아니다!)
    // super라는 키워드를 사용하여 메서드를 호출한다.
    super.print(); // 이 메서드를 재정의하기 전의 메서드를 호
    System.out.printf("학교: %s\n", school);
  }
}


호출 코드


public static void main(String[] args) {
    BitStudent s = new BitStudent();
    s.name = "홍길동";
    s.age = 20;
    s.school = "비트대학교";
    s.print();
}


* super (주의 : 수퍼 클래스라는 의미가 아니다.)

- 수퍼 클래스의 메서드를 재정의할 때 기존 코드를 복사/붙여넣기 하는 대신

  재정의하기 전의 기존 메서드를 호출하는 것이 편하다. 재정의 하기 전의 메서드를

  가리키기 위해 super 라는 키워드를 사용하여 메서드를 호출한다.



* 참고

오버로딩 (overloading)

- 클래스 내에 동일한 이름을 가진 메서드를 여러 개 만들어 파라미터의 개수만 달리

  하는 방법이다

- 메서드의 일관성을 유지하는 것이 목적이다.



블로그 이미지

필로그래머

,

[Java] 자바 상속 (inheritance)과 Object 클래스


상속 (inheritance)


상속이라는 게 대체 무엇일까? 

상속에 대해 알아보기 전에 먼저 다음 예제를 천천히 확인해보자.



BasicCalculator 계산기 예제


public class BasicCalculator {

  int result;
 
  void plus(int value) {
    this.result += value;
  }
 
  void minus(int value) {
    this.result -= value;
  }

} 




BasicCalculator 인스턴스 생성 및 plus(), minus() 호출 코드


public class Test01 {

  public static void main(String[] args) {
    BasicCalculator calc = new BasicCalculator(); // 인스턴스 생성
    calc.plus(100); // -> 100
    calc.plus(20); // -> 120
    calc.minus(30); // -> 90
    System.out.println(calc.result);
  }

}


BasicCalculator 클래스에는 plus 메서드와 minus 메서드가 있고 위 호출 코드와 같은

방식으로 메서드를 사용할 수 있다. 그러나 만약 '원본'을 손상시키지 않는

방식으로 multiple이라는 곱하기 메서드를 추가하고 싶다면 어떻게 해야 할까?


처음에 사람들은 BasicCalculator 클래스의 소스 코드를 복사해 아래 예제와 같은 

새로운 클래스를 만들었다.




BasicCalculator 소스를 복붙해 만든 AdvancedCalculator 계산기 예제


public class AdvancedCalculator {

  int result;
 
  void plus(int value) {
    this.result += value;
  }
 
  void minus(int value) {
    this.result -= value;
  }
 
  // 새 곱하기 기능 추가
  void multiple(int value) {
    this.result *= value;
  }
}


그리고 다음과 같이 위에서 만든 AdvancedCalculator 클래스의 인스턴스를 새롭게 

생성해서 사용했다.




AdvancedCalculator 인스턴스 생성 및 plus(), minus(), multiple() 메서드 호출 코드


public class Test02 {

  public static void main(String[] args) {
    AdvancedCalculator calc = new AdvancedCalculator();
    calc.plus(100);
    calc.plus(20);
    calc.minus(30);
    calc.multiple(2);
    System.out.println(calc.result);
  }

}



원인 :

'상속'이라는 문법을 사용하기 전에는 이와 같이 기존에 있던 코드를 복붙해 추가

하고 싶은 메서드(기능)를 새롭게 작성하고, 이렇게 만들어진 class의 인스턴스를 생성

함으로써 유지보수를 했다. 그러나 점차 문제점이 드러나기 시작하는데, 회사의 

규모가 커지거나 해당 class를 공유하는 고객사가 많아질수록 소스 코드를 유지보수

하기 어려워진 것이다. 



결과 :

지속적인 복사 붙여넣기를 통해 발생된 낭비를 방지하기 위해

도입된 것이 '상속'이라는 문법이다.



해결방법


 1) 새 클래스를 만들어 곱하기 기능을 추가한다.

 2) BasicCalculator의 기능을 사용하겠다고 선언한다.




상속 예제


public class AdvancedCalculator extends BasicCalculator{
  int result;
  
  void multiple(int value) {
    this.result *= value;
  }

}


위와 같이 extends를 적고, 가져다 쓰고 싶은 메서드를 가진 class 이름을

적어주면 기능을 상속받을 수 있게 된다.



.이때 BasicCalculator를 parent class (부모 클래스) / super class

AdvancedCalculator를 child class (자식 클래스 / sub class 라고 부른다.


* 참고 : 

  super 클래스를 지정하지 않으면 자동으로 Object가 수퍼 클래스로 선언된다.

  

Object 클래스가 하는 일

  - 객체가 기본적으로 갖춰야 할 변수와 메서드를 제공한다.

  - 주요 메서드

     - toString()    : 클래스이름과 인스턴스 ID를 리턴한다. 

=> 프로그램을 실행할 때 인스턴스의 내부 값을 간단히 

살펴볼 수 있도록 서브 클래스들이 이 메서드를 재정의 

하기도 한다. 


     - equals()      : 인스턴스의 주소를 비교하여 true/false 값을 리턴한다.

=> 인스턴스 내부의 값을 비교하도록 서브 클래스에서 이

메서드를 재정의하기도 한다.


     - hashCode()  : 인스턴스를 구별할 때 사용하는 4 byte 숫자로 된 ID 값.

=> 인스턴스 변수의 값이 같을 때 같은 ID 값을 리턴

하도록 서브 클래스에서 이 메서드를 재정의하기도 한다.


     - getClass()    : 클래스 설계도를 리턴한다.    


     - finalize()     : 쓰레기 수집기(garbage collector)가 가비지를 메모리에서

     제거하기 전에 호출하는 메서드이다.

     => 쓰레기 수집기가 언제 호출되는지 알 수 없기 때문에 

  자주 쓰이지는 않는다.


  - 참조 문서 : http://docs.oracle.com/javase/8/docs/api/index.html







블로그 이미지

필로그래머

,

[Java] 자바 String[] args (프로그램 아규먼트)


프로그램 아규먼트 (String[] args)?


자바에서 가장 먼저 코드를 로딩하는 곳은 main()이다.

 

ex) 

public static void main(String[] args) {...}


main() 메서드 {...} 블록 안에 코드를 작성해주면 JVM은 가장 먼저 이곳을 읽어들인다.



그런데 대체 String[] args는 무엇을 의미하는가? 


역사 :

- 이클립스를 사용하기 전에는 명령창을 통해서 java 확장자 파일을 class 파일로

  직접 컴파일 시켰다. 그리고 컴파일된 class 파일의 디렉토리 주소를 찾아가 다음과

  같이 도스 창에 명령어를 작성해주었다.

  > java -cp bin step08.Test01_1


이렇게 class 파일을 로딩할 경우 JVM은 main() 메서드 안에 있는 코드를 순서대로 

읽게 된다. 그런데 main() 메서드 코드를 읽을 때 특정 파라미터 값을 바로 넘겨주고

싶을 때가 생긴다. 이때 args라는 이름을 가진 String[] 배열을 파라미터 값으로 넘기는

시도를 하게 된다.


class 파일이 생성된 디렉토리를 찾아가 다음과 같이 명령어를 주면 

String[] args 형태의 파라미터 값을 넘겨줄 수 있다.

> java -cp bin step08.Test01_1 aaa bbb ccc 111 222

굵게 칠한 부분이 바로 각각 String 타입의 args 배열 값이다.


그래서 만약 main() 메서드에 다음 코드

System.out.println(args[0], args[1], args[2], args[3], args[4]); 를 써주게 되면


- 실행 결과 :

aaa, bbb, ccc, 111, 222


이렇게 출력이 된다.


정리 : 

프로그램 아규먼트 (String[] args)

- 프로그램을 실행할 때 넘겨주는 값

- 예) 클래스 파일 뒤에 "aaa bbb ccc 111 222"와 같은 값을 넘겨줘 보자.

  > java -cp bin step08.Test01_1 aaa bbb ccc 111 222

- 이처럼 클래스 이름 뒤에 값을 주게 되면 공백을 기준으로 문자열을 잘라서 배열에

  담아 main() 메서드의 파라미터 값으로 넘어온다. 

블로그 이미지

필로그래머

,

[Java] 자바 문자열 (String)과 상수 문자열 (String) 그리고 equals() 메서드


유틸리티 클래스 : String

- 내부적으로 char[]을 이용하여 문자열을 처리한다.

- 문자열을 다루는 기능을 포함하고 있다.

- 즉, 문자를 저장하는 char[] 배열과 그 배열을 다루는 메서드를 구비한 

  데이터 타입이라 볼 수 있다.

- String 클래스는 immutable(변하지 않는) 객체이다.

  한 번 값이 결정되면 변하지 않는다.

  값을 바꾸려 하면 새로운 문자열 인스턴스가 자동 생성된다.



문자열 주소 비교 예제 1


public class Test02_1 {

  public static void main(String[] args) {
     //1) 문자열의 인스턴스 주소를 저장할 변수 선언
     String s1;
    
     //2) 문자열 인스턴스를 생성
     // => Heap 영역에 char[] 배열이 만들어지고 그 배열안에 문자열이 보관된다.
     s1 = new String("Hello!");
    
     String s2 = s1;
     if (s1 == s2) { // 두 변수에 저장된 주소가 같은지 비교해 보자!
       System.out.println("s1 == s2");
     }
     System.out.println();
    
  }

}

- 실행결과 : 

s1 == s2





상수 문자열 

- new 연산자 없이 인스턴스를 생성한다.

- heap이 아니라 Constant Pool 이라는 상수만 모아두는 영역에서 따로 관리한다.

-중복해서 생성되지 않는다.





public
static void main(String[] args) {
    String s1 = "Hello"; // new String("Hello")와 같지만, heap이 아니라 Constant Pool 영역에 생성된다.
    String s2 = "Hello"; // 한번 생성되면 기존의 상수 문자열 인스턴스의 주소를 리턴한다.
   
     if (s1 == s2) { // 상수 문자열을 가리키는 레퍼런스 비교
       System.out.println("s1 == s2");
     } else {
       System.out.println("s1 != s2");
     }
    

  }

- 실행 결과 :

s1 == s2






equals() 메서드


 문자열의 주소가 아니라 문자열의 '값'을 비교하고 싶다면 equals() 메소드를 이용해

 야 한다. equals() 메서드는 s1에 저장된 주소로 찾아가서 그 인스턴스의 문자 배열을

 보관한다. 그리고 s2에 저장된 주소로 찾아가서 그 인스턴스의 문자 배열을 보관

 한다. 이 두 개의 문자 배열의 값을 하나씩 비교하여 끝까지 같다면 true를 리턴하고

 같지 않다면 false를 리턴한다.




equals() 메서드 예제


public static void main(String[] args) {

    String s1 = new String("Hello");
    String s2 = new String("Hello");
   
     if (s1.equals(s2)) { // 문자열인스턴스주소1.equals(문자열인스턴스주소2)
       //equals() 메서드는 s1에 저장된 주소로 찾아가서 그 인스턴스의 문자 배열과
       //s2에 저장된 주소로 찾아가서 그 인스턴스의 문자 배열을 한 개씩 비교하여
       //끝까지 같다면 true를 리턴한다. 다르면 false를 리턴한다.
       System.out.println("s1 == s2");
     } else {
       System.out.println("s1 != s2");
     }
    

  }



- 실행 결과 :

s1 == s2











블로그 이미지

필로그래머

,

[Java] 자바 인스턴스 메서드 (instance method)


인스턴스 메서드 (instance method)

- 인스턴스 변수를 다루는 메서드이다.

- 인스턴스 주소 없이는 호출할 수 없다. (호출할 때 인스턴스 주소가 반드시 필요하다)

- 클래스의 코드는 Method Area 메모리 영역에 로딩된다.

  따라서 클래스의 코드인 "인스턴스 메서드" 역시 Method Area 영역에 로딩된다.

- 만약 인스턴스 변수를 다루지 않는다면,

  그 메서드는 "클래스 메서드"로 선언하는 것이 낫다.


* 주의!

  클래스의 모든 명령 코드는 Method Area 영역에 있다.

  인스턴스 생성할 때 인스턴스 메서드가 생성되는 것이 아니다.



인스턴스 메서드 예제


static class Calculator {

    int result;
   
    public void plus(int value) {
      this.result += value;
   
    }
   
    public void minus(int value) {
      this.result -= value;
    }

  }


 
인스턴스 메서드 호출 코드 

public static void main(String[] args) {

   Calculator c = new Calculator();
    c.plus(10);
    c.plus(7);
    c.minus(3);
    c.plus(1);
    System.out.println(c.result);

  }

- 실행 결과 : 15





위 예제에서의 Method Area 구조


Test04_1.class

void mian()

 {

Calculator c = new Calculator();

c.plus(10); c.plus(7); c.minus(3); c.plus(1); System.out.println(c.result);

}


Calculator.class

int result;

void plus(int value) {this.result += value};

void minus(int value) {this.result -= value};





블로그 이미지

필로그래머

,

[Java] 자바 생성자 (constructor)와 오버로딩 (overloading)


2017/05/11 - [java] - #Java 스태틱 블록 (static block), 인스턴스 블록 (instance block), 생성자

2017/05/10 - [java] - #Java 생성자(constructor)


overloading (오버로딩)

- 파라미터 타입이 다르거나 개수가 다른 생성자 또는 메서드를  여러 개 중복해서 

  만드는 문법을 말한다.

- 인스턴스를 생성할 때, 넘겨주는 아규먼트의 값과 순서에 따라 호출되는 생성자 메서드가 달라진다.



생성자 오버로딩 예제


static class Student {

    static String name = "홍길동"; // 변수 선언에 값을 초기화시키는 문장을 포함할 수 있다.
   
    int age = 20;
   
    Student() {
      System.out.println("Student()... 호출");
    }
   
    Student(int a) {
      System.out.println("Student(int)... 호출");
      this.age = a;
    }
   
    Student(int a, String n) {
      System.out.println("Student(int, String)... 호출");
      this.age = a;
    }
   
    Student(String n, int a) {
      System.out.println("Student(String, int)... 호출");
      this.age = a;
    }

  }



생성자 호출 코드


public static void main(String[] args) {

    new Student();
    System.out.println("---------------------------");
    new Student("홍길동", 20);
    new Student(20, "홍길동");

  }


- 실행 결과 :

    Student()... 호출

    ---------------------------

    Student(String, int)... 호출

    Student(int, String)... 호출




블로그 이미지

필로그래머

,