자동 박싱 및 언박싱 문제는 Java에서 흔히 발생하는 문제입니다. 오늘은 박싱 및 언박싱과 관련된 몇 가지 문제를 살펴보겠습니다. 이번 글에서는 먼저 포장 및 언박싱에 대한 가장 기본적인 사항에 대해 이야기한 후, 서면 인터뷰에서 자주 접하는 포장 및 언박싱과 관련된 질문을 살펴봅니다.
1. 포장이란? 언박싱이란 무엇인가요?
이전 기사에서 언급했듯이 Java는 기본 데이터 유형마다 해당 래퍼 유형을 제공합니다. 왜 기본 데이터 유형마다 래퍼 유형을 제공하는지에 대해서는 여기서 설명하지 않겠습니다. 관심 있는 친구들은 관련 정보를 확인할 수 있습니다. Java SE5 이전에는 값이 10인 Integer 객체를 생성하려면 다음과 같이 진행해야 합니다.
Integer i = new Integer(10);
Java SE5부터 Integer 객체를 생성하려는 경우 autoboxing 기능이 제공되었습니다. 값이 10인 경우 Integer 개체의 경우 다음만 수행하면 됩니다.
Integer i = 10;
이 프로세스에서는 값을 기반으로 해당 Integer 개체가 자동으로 생성됩니다.
그럼 언박싱이란 무엇일까요? 이름에서 알 수 있듯이 boxing에 해당하면 자동으로 래퍼 유형을 기본 데이터 유형으로 변환합니다.
Integer i = 10; //装箱 int n = i; //拆箱
간단히 말하면 boxing은 기본 데이터 유형을 래퍼 유형으로 자동 변환하는 것을 의미하며 unboxing은 자동으로 변환하는 것을 의미합니다. 패키징 유형을 래퍼 유형으로 변환합니다.
다음 표는 기본 데이터 유형에 해당하는 래퍼 유형을 보여줍니다.
2. boxing 및 unboxing 구현 방법
이전 섹션에서 boxing의 기본 개념을 이해한 후, 이번 섹션에서는 boxing과 unboxing이 어떻게 구현되는지 알아보겠습니다.
Interger 클래스를 예로 들어 코드를 살펴보겠습니다.
public class Main { public static void main(String[] args) { Integer i = 10; int n = i; } }
클래스 파일을 디컴파일한 후 , 다음 내용을 얻습니다.
복싱 중에 Integer의 valueOf(int) 메서드가 자동으로 호출되는 것을 디컴파일하여 얻은 바이트코드 내용에서 볼 수 있습니다. unboxing 중에 자동으로 호출되는 것은 Integer의 intValue 메서드입니다.
더블이나 캐릭터 등 다른 것들도 비슷해서 믿지 못하는 친구들은 수동으로 해볼 수도 있다.
그래서 boxing과 unboxing의 구현 과정은 한 문장으로 요약할 수 있습니다:
boxing 과정은 래퍼의 valueOf 메서드를 호출하여 구현되고, unboxing은 프로세스 프로세스는 래퍼의 xxxValue 메서드를 호출하여 구현됩니다. (xxx는 해당 기본 데이터 유형을 나타냅니다).
3. 면접 관련 질문
대부분의 사람들은 짐을 싸고 풀고의 개념을 확실히 알고 있음에도 불구하고 면접과 필기시험에서 짐을 싸는 것과 관련된 질문을 접하게 됩니다. 복싱과 언박싱에 대한 질문에는 답변이 없을 수도 있습니다. 다음은 포장/개봉과 관련된 몇 가지 일반적인 인터뷰 질문입니다.
1. 다음 코드의 출력은 무엇입니까?
public class Main { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4); } }
어쩌면 어떤 친구는 false가 출력될 것이라고 말할 수도 있고, 어떤 친구는 true가 출력될 것이라고 말할 수도 있습니다. 그러나 실제로 출력 결과는 다음과 같습니다.
true
false
왜 이런 결과가 발생합니까? 출력에서는 i1과 i2가 동일한 개체를 가리키는 반면, i3과 i4는 서로 다른 개체를 가리키는 것으로 표시됩니다. 이 시점에서 진실을 알기 위해서는 소스 코드만 보면 됩니다. 다음 코드는 Integer의 valueOf 메소드를 구체적으로 구현한 것입니다.
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }
IntegerCache 클래스의 구현은 다음과 같습니다.
private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may be configured by property int h = 127; if (integerCacheHighPropValue != null) { // Use Long.decode here to avoid invoking methods that // require Integer's autoboxing cache to be initialized int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
valueOf 메소드를 통해 Integer 객체를 생성할 때 다음 두 코드에서 볼 수 있습니다. 값이 [-128,127] 사이인 경우 IntegerCache.cache에 이미 존재하는 개체에 대한 참조를 반환합니다. 그렇지 않으면 새 Integer 개체를 만듭니다.
위 코드에서 i1과 i2의 값은 100이므로 기존 객체를 캐시에서 직접 가져오므로 i1과 i2는 동일한 객체를 가리키지만, i3과 i4는 각각 다른 객체를 가리킵니다.
2. 다음 코드의 출력은 무엇입니까?
public class Main { public static void main(String[] args) { Double i1 = 100.0; Double i2 = 100.0; Double i3 = 200.0; Double i4 = 200.0; System.out.println(i1==i2); System.out.println(i3==i4); } }
어떤 친구들은 위 질문의 출력 결과가 같다고 생각할 수도 있지만 실제로는 그렇지 않습니다. 실제 출력 결과는 다음과 같습니다.
false
false
구체적인 이유는 Double 클래스의 valueOf 구현을 독자가 확인할 수 있습니다.
여기에서는 Double 클래스의 valueOf 메서드가 Integer 클래스의 valueOf 메서드와 다른 구현을 사용하는 이유를 설명하겠습니다. 간단합니다. 특정 범위 내의 정수 값의 개수는 유한하지만 부동 소수점 숫자는 그렇지 않습니다.
Integer, Short, Byte, Character 및 Long 클래스의 valueOf 메소드 구현은 유사합니다.
Double과 Float의 valueOf 메소드 구현은 비슷합니다.
3. 다음 코드의 출력 결과는 무엇입니까?
public class Main { public static void main(String[] args) { Boolean i1 = false; Boolean i2 = false; Boolean i3 = true; Boolean i4 = true; System.out.println(i1==i2); System.out.println(i3==i4); } }
🎜>true
true至于为什么是这个结果,同样地,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:
public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
而其中的 TRUE 和FALSE又是什么呢?在Boolean中定义了2个静态成员属性:
public static final Boolean TRUE = new Boolean(true); /** * The <code>Boolean</code> object corresponding to the primitive * value <code>false</code>. */ public static final Boolean FALSE = new Boolean(false);
至此,大家应该明白了为何上面输出的结果都是true了。
4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。
当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:
1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;
2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。
5.下面程序的输出结果是什么?
public class Main { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; Long h = 2L; System.out.println(c==d); System.out.println(e==f); System.out.println(c==(a+b)); System.out.println(c.equals(a+b)); System.out.println(g==(a+b)); System.out.println(g.equals(a+b)); System.out.println(g.equals(a+h)); } }
先别看输出结果,读者自己想一下这段代码的输出结果是什么。这里面需要注意的是:当 “==”运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然:
true
false
true
true
true
false
true
第一个和第二个输出结果没有什么疑问。第三句由于 a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。
以上所述是小编给大家介绍的Java의 박싱 및 언박싱에 대한 심층적인 이해,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网站的支持!
更多Java의 박싱 및 언박싱에 대한 심층적인 이해相关文章请关注PHP中文网!