int vs. Integer

자바/공부 2009.01.14 15:10

int와 Integer의 차이는 무엇일까?

우선 int는 기본형이고,

Integer는 기본형 int의 wrapper 클래스이다.

wrapper 클래스는 객체가 요구되는 위치에 기본형 데이터를 사용할 수 있도록 한다.

우선 boxing과 unboxing에 대해 알아보자.

boxing: 기본형 -> wrapper 클래스 객체
unboxing: wrapper 클래스 객체 -> 기본형

현재 자바에서는 auto boxing/unboxing이 되기 때문에 혼용해서 쓰기도 하지만,

모든 곳에서 auto boxing/unboxing이 가능한 것은 아니다.

다음은 auto boxing/unboxing의 되는 예이다.

int i = 1;
Integer integer = i;
int i2 = integer;

다음은 auto boxing/unboxing이 되지 않는 예이다.

ArrayList<int> intList = new ArrayList<int>();

Integer의 객체 integer를 메소드의 parameter로 전달하고,

메소드 내에서 integer++를 수행하면 integer의 값은 증가할까?

다음 예를 보자.

소스

public class IntegerTest {

 public static void main(String[] args) {
  int i = 1;
  Integer integer = 1;
  MyInteger myInteger = new MyInteger(1);
 
  System.out.println("Before incr(): i: " + i);  
  incr(i);  
  System.out.println("After incr(): i: " + i);
 
  System.out.println("Before incr(): integer: " + integer);
  incr(integer);
  System.out.println("After incr(): integer: " + integer);
 
  System.out.println("Before incr(): myInteger: " + myInteger);
  incr(myInteger);
  System.out.println("After incr(): myInteger: " + myInteger);
 }

 public static void incr(int i) {
  System.out.println("incr(int) invoked.");
  i++;
 }

 public static void incr(Integer i) {
  System.out.println("incr(Integer) invoked.");
  i++;
 }

 public static void incr(MyInteger i) {
  System.out.println("incr(MyInteger) invoked.");
  int value = i.getValue();
  value++;
  i.setValue(value);
 }
 
}

class MyInteger {
 
 private int value;

 public MyInteger(int value) {
  this.value = value;
 }
 
 public int getValue() {
  return value;
 }

 public void setValue(int value) {
  this.value = value;
 }
 
 @Override
 public String toString() {
  return "" + value;
 }
 
}


실행 결과

Before incr(): i: 1
incr(int) invoked.
After incr(): i: 1
Before incr(): integer: 1
incr(Integer) invoked.
After incr(): integer: 1
Before incr(): myInteger: 1
incr(MyInteger) invoked.
After incr(): myInteger: 2

결과에서 보듯이 증가되지 않음을 알 수 있다. 왜 그럴까?

integer++를 수행하기 위해서는 integer 객체를 unboxing해서 int로 변환한다.

그리고 이 int에 대한 ++ 연산을 수행한다.

따라서 integer 객체가 wrapping하고 있는 int 값은 변하지 않는다.

Integer 클래스는 wrapping하고 있는 int 값을 변경시키는 메소드를 제공하지 않는다.

따라서 변경가능한 int wrapper 객체를 생성하고 싶다면,

위의 예에서 MyInteger와 같이 별도로 구현하여 사용해야만 한다.

Posted by izeye

상속 관계에 있는 두 클래스에서

자식 클래스가 cloneable이기 위해서 부모 클래스도 cloneable이어야만 할까?

그렇지 않다.

Cloneable 인터페이스는 marker interface로서

Cloneable 인터페이스을 구현한 클래스의 clone() 메소드가 유효함을 의미한다.

따라서, Cloneable 인터페이스를 구현한 클래스는

자신만의 clone() 메소드를 갖고 있어야만 한다.

물론, 클래스가 기본형 데이터만으로 이루어진 경우 shallow copy만으로 충분하므로

메소드의 access modifier만 protected에서 public으로 변경해주고,

super.clone()을 반환해도 된다.

하지만 그 이외의 경우 deep copy를 수행하여야만 하므로

자신만의 clone() 메소드를 구현해야만 한다.

다음은 Cloneable 인터페이스를 구현하지 않은 Aminal 클래스를 상속하고,

Cloneable 인터페이스를 구현하는 Dog 클래스의 객체를 clone하는 예제이다.



소스

package clone;

public class Animal {
 private int id;

 public Animal(int id) {
  this.id = id;
 }

 public int getId() {
  return id;
 }
}

package clone;

public class Dog extends Animal implements Cloneable {
 private String name;

 public Dog(int id, String name) {
  super(id);

  this.name = name;
 }

 public String getName() {
  return name;
 }
 
 @Override
 public Object clone() throws CloneNotSupportedException {
  return super.clone();
 }
}

package clone;

public class CloneTest {
 public static void main(String[] args) throws CloneNotSupportedException {
  Dog dog = new Dog(1, "Dog 1");
  Dog clonedDog = (Dog)dog.clone();
 
  System.out.println(clonedDog.getId());
  System.out.println(clonedDog.getName());
 }
}



실행결과


1
Dog 1




Dog 클래스는 기본형 데이터만으로 이루어져 있으므로

super.clone() 메소드 호출만으로 충분함에 주목하기 바란다.

Posted by izeye