잘못 알려지거나 무용지물이 된 Java 상식들
Java에 대해 잘못 알려지거나 java 5.0 이전의 정보로 현재의 java에서는 무용지물인 상식들이 몇가지 있는데 그런 종류의 상식에 대해 올바른 답을 전달하는 글이 있어 정리합니다.
원문은 http://java.dzone.com/articles/incorrect-core-java-interview 입니다.
Java의 인자 전달 방식은?
이 질문은 자바 태생과 함께해온 오랜 질문 중의 하나로 제 과거 포스팅 '자바는 call by value? call by reference?' 에서도 언급했던 내용입니다. 하나의 기능에서 또다른 기능, 혹은 subroutine으로 인자를 전달하는 방식은 pass by value와 pass by reference 두 가지 방식이 존재합니다만 java 세상에서는 pass by value 만이 존재할 뿐입니다. reference의 값(reference by value)을 전달할 순 있지만 reference 자체를 전달할 순 없습니다. java reference는 Call By Sharing 으로 설명되기도 하지만 일반적으로 쓰이는 용어는 아닙니다.
Garbage collection이란 무엇이며 어떻게 동작하는가?
일반적으로 알려진 바로는 '어떤 변수에도 할당되지 않은 Object를 가비지콜렉터가 메모리에서 정리한다' 이죠. 맞는말이긴 합니다만 조금 더 정확히 기술하자면 Root context로 부터 더 이상 strong reference 되지 않은 Object가 가비지콜렉터의 대상이 됩니다. weak reference 혹은 soft reference Object가 그 대상인거죠.
또한 System.gc()는 Full GC를 수행하라고 VM에게 힌트를 주는것이지 System.gc() 호출 시점에 GC가 수행되는것은 아닙니다. ( finalize 메소드의 오버라이딩을 자제해야 하는 이유. )
Transient 와 Volatile 접근 제한자는 무엇인가?
알려진 내용은 다음과 같죠.
Transient 접근 제한자는 Object를 직렬화(serialize)하여 다른곳으로 전송하거나 객체를 저장할 때 Transient 제한자가 적용된 변수는 저장되지 않는다. Volatile 접근 제한자는 해당변수를 컴파일러에게 해당 변수가 다른 프로그램에 의해 불규칙하게 변경될 여지가 있음을 알려준다.
사실은 이렇습니다.
transient 접근제한자는 오직 feild (클래스변수)에만 적용할 수 있으며, 지역변수에는 적용할 수 없습니다. static 변수에도 적용할수는 있지만 그 기능은 무시됩니다. trensient가 적용된 변수는 serialized 되진 않지만 writeObject(), readObject() 같은 커스텀 serialization을 통해 직렬화 할 수 있습니다.
volatile 접근 제한자 역시 feild에만 적용할 수 있으며, compiler가 아닌 JIT 쪽에 필드값을 참조할 때 메인 메모리상의 필드값이 캐시(CPU의 L1,L2캐시)에 복사하도록(캐시를 갱신) 명시하는 역할을 합니다. 멀티쓰레드 환경에서 서로 다른 쓰레드들이 갱신되지 않은 캐시로 프로그램이 오작동 할 수 있는 부분에 적용할 수 있습니다.
Integer 클래스와 int 의 차이점은 무엇인가?
Integer는 java.lang 패키지에 정의된 클래스이며 int는 Java 언어 자체에 정의되어 있는 primitive 데이타 타입이다.
딱히 틀린말은 아니지만 조금 더 정확히 표현하면 Integer는 int를 싸는(wrap) 참조 객체(reference to an object) 이고 autoboxing, unboxing이 도입된 이후의 Integer와 int의 가장 큰 차이점은 Integer는 null일 수 있는것과 == 연산자에서 Integer는 reference를 비교하거나 warpping된 값(int) 를 비교하는것 입니다. 아래 코드를 보시죠
[code]
Integer i1 = 1;
Integer i2 = 1;
// autoboxing이 적용되어 int값 비교로 true 출력.
System.out.println(i1 == i2);
Integer i3 = 3000;
Integer i4 = 3000;
// autoboxing이 적용되지 않고 reference 비교를 하기때문에 false 출력.
System.out.println(i3 == i4);
[/code]
신기합니다. 두 Integer 객체 비교에 어떤 경우엔 true가, 또 어떤 경우엔 false가 됩니다.
이 문제의 비밀은 java실행 옵션에 있는데요. SUN/Oracle JVM의 경우 integer값을 캐시하는 기본 최대값은 127입니다. 즉 127이내의 Integer를 비교하면 autoboxing이 적용된 int를 비교하게됩니다. 물론 이 옵션은
-XX:AutoBoxCacheMax= or -Djava.lang.Integer.IntegerCache.high=2000
과 같은 방법으로 변경할 수 있습니다.
Thread의 상태는?
Thread는 ready, running, dead 의 상태를 갖는다고 일반적으로 알려져 있습니다만 java 5.0으로 넘어오면서 Thread.State enum이 추가되면서
NEW : 쓰레드가 시작되지 않은 상태
RUNNABLE : JVM에서 쓰레드가 동작중인 상태
BLOCKED : block되어 monitor lock을 기다리는 상태
WAITING : 다른쓰레드가 특정한 행위를 수행할때까지 기약없이 대기하는 상태.
TIMED_WAITING : 다른쓰레드가 특정한 행위를 수행할때까지 약속된 시간까지 대기하는 상태.
TERMINATED : 쓰레드가 종료된 상태.
의 6가지 상태로 구분됩니다.
모든 클래스의 base 클래스는?
java.lang.Object
아마 모든 Java 입문서에 나와있는 내용일겁니다. 물론 일반적인 자바객체는 java.lang.Object를 상속하고 있습니다.
하지만 이는 custom class에만 적용되는 이야기입니다. int.class, void.class와 같은 primitive 타입과 Object 그 자체는 super class가 없습니다.
[code]
Class parent = boolean.class.getSuperclass(); // returns null
[/code]
Java Beans란?
java beans는 '다양한 환경에서 재사용이 가능하도록 디자인된 소프트웨어 컴포넌트이다.' 라고 설명 되기도 합니다. 하지만 Java Beans를 좀 더 구체적으로 설명하자면 '직렬화 가능하고(serializable) 인자없는 생성자를 가지며, getter ,setter 메소드를 통하여 프로퍼티에 접근 가능한 Java Object이다.'정도가 될것입니다.
synchronized block vs. synchronized method.
일반적으로 synchronized block이 synchronized method보다 lock을 거는 주기가 더 짧다고 알려져있습니다. 옳은 말이긴하지만 항상 그렇게 동작한다고 보증할 순 없는데요. 아래는 일반적으로 사용되고 있는 코드 예시로 synchronized block에 lock으로 this가 아닌 다른 object를 사용하고 있습니다. 이런 경우 synchronized block은 synchronized method로 lock을 걸게 됩니다. 결국 synchronized block으로 lock 영역을 줄인 의미가 없어지게 되는거죠.
[code]
Map<Key, Value> map = Collections.synchronizedMap(new LinkedHashMap<Key, Value>());
// perform multiple operations in a thread safe manner
synchronized(map) {
Value value = map.get(key);
if (value == null)
map.put(key, value = new Value(key));
return value;
}
[/code]
안녕하세요 글 잘봤습니다. 제가 궁금하게 있어 질문은 남깁니다. Integer a = 10; 해서 a라는 Interger 타입의 클래스에 10라는 데이터를 담았습니다. 그리고 그 a의 주소값은 Integer b 에게 넘겨주려고 합니다. 기본적인 클래스의 방식 대로라면 Integer b = a; 이겠지만 이렇게 하면 값(10)이 넘어가 버립니다. 제가 원하는 것은 a 와 b 는 같은 주소를 공유해 a의 값에 변화가 생기면 b의 값에 변화를 주고 싶습니다. 그래서 a.hashcode(); 도 사용해봤는데 주소 값이 아닌 데이터 값이 10을 반환하더군요. a의 주소값은 얻어와 b에 그 주소값으로 설정해 줄수 있는 방법이 없을까요??
rkdgusrnrlrl님 안녕하세요.
java API를 유심히 살펴 보셨다면 java 언어가 wrapper 클래스를 님이 원하는 방식으로 사용하지 않기를 바랐다는것을 아실 수 있었을 겁니다.
java.lang.Integer 는 public final class Integer extends Number 와 같이 정의되어 있습니다. 네.. final class 죠. 한번 생성 후 변경할 수 없는 클래스로 만들어져 있습니다. 이런 이유로 setValue() 나 setInt() 같은 메소드도 존재하지 않는것이구요. final class이기 때문애 값을 변경하려면 항상 새로운 객체를 할당할 수 밖에 없습니다.
님과 같은 상황을 해결하려면 Integer를 멤버변수로 갖는 VO를 만들어 사용하시면 됩니다.
public class IntegerData implements Serializable{
private Integer i;
public void setInteger(Integer i){
this.i = i;
}
public Integer getInteger(){
return this.i;
}
}
안녕하세요 transient 관련 글을 검색하다 방문했습니다. 좋은 글 잘 읽었습니다. 그런데 class에 final 키워드는 제가 알기로는 더 이상 상속을 불가능케 하는거지 생성된 인스턴스의 변경 불가와는 크게 상관이 없어 보이는데요 제가 잘못 알고 있는건가요? 관련 레퍼런스가 있다면 알려주시면 감사하겠습니다.
아 그럼 위의 방식으로 하게 되면 데이터 값 교환이 아닌 주소값 교환인 되는 건가요?? 이제 프로그래밍을 배우고 있고 지금 제가 자바 초급을 막 완료한 상태라 VO가 뭔지는 잘 모르겠니요^^;; 얼마전에 wrapper 클래스를 배우서 Integer라는 클래스가 int와 비슷한 기능을 해 관심을 갖고 있었거든요 c 에서는 포인트가 있어 int 변수의 주소 값을 가져올 수 있는 것 같은데 그런 점에서는 자바가 많이 아쉽네요ㅠㅠ 답변 감사합니다.
@Saver
맞습니다. 클래스에 final이 붙어서 Integer가 불변이 아니지요.
값을 담고 있는 value가 final이라는 것을 보여주려고 하셨던 것 같습니다.
private final int value;
또한 setter가 없기 때문에 Integer의 내부의 value를 바꿀 수 없는 것이지요.