Java Collections가 Primitives 유형을 직접 저장할 수없는 이유는 무엇입니까?


123

Java 컬렉션은 기본 유형이 아닌 객체 만 저장합니다. 그러나 우리는 래퍼 클래스를 저장할 수 있습니다.

왜 이런 제약이 있습니까?


2
이 제약은 기본 요소를 처리하고 대기열을 사용하여 전송하고 싶을 때 좋지 않으며 전송 속도가 매우 빠릅니다. 나는 지금 너무 많은 시간이 걸리는 자동 복싱 문제를 다루고 있습니다.
JPM

기술적으로 기본 유형은 객체 (정확한 단일 인스턴스)이며 classJVM이 아니라으로 정의됩니다 . 이 명령문 int i = 1intJVM에서 정의 된 객체의 단일 인스턴스에 대한 포인터를 정의 하고 JVM의 1어딘가에 정의 된 값으로 설정됩니다 . 예, Java의 포인터-이것은 언어 구현에 의해 추상화되었습니다. 언어 조건자는 모든 제네릭 유형이 상위 유형이어야하므로 기본 형식을 제네릭으로 사용할 수 없습니다. Object따라서 런타임에 A<?>컴파일되는 이유는 무엇입니까 A<Object>?
Robert E Fry

1
@RobertEFry 기본 유형은 Java의 객체아니므로 싱글 톤 인스턴스에 대해 작성한 모든 내용은 근본적으로 잘못되고 혼란 스럽습니다. 객체가 무엇인지 정의하는 Java 언어 사양 의 "유형, 값 및 변수" 장을 읽는 것이 좋습니다 . "객체 (§4.3.1)는 동적으로 생성 된 클래스 유형의 인스턴스 또는 동적으로 생성 된 배열입니다. "
typeracer

답변:


99

그것은 자바 디자인 결정이었고 어떤 사람들은 실수로 생각하는 결정이었습니다. 컨테이너는 객체를 원하고 기본 요소는 객체에서 파생되지 않습니다.

이것은 .NET 디자이너가 JVM에서 배웠고 값 유형과 제네릭을 구현하여 많은 경우에 boxing이 제거 된 곳입니다. CLR에서 제네릭 컨테이너는 기본 컨테이너 구조의 일부로 값 형식을 저장할 수 있습니다.

Java는 JVM의 지원없이 컴파일러에서 일반 지원을 100 % 추가하기로 결정했습니다. JVM은 "비 개체"개체를 지원하지 않습니다. Java 제네릭을 사용하면 래퍼가없는 척할 수 있지만 여전히 권투의 성능 대가를 지불합니다. 이것은 특정 프로그램 클래스에 중요합니다.

권투는 기술적 인 타협이며 구현 세부 사항이 언어로 누출되는 것 같습니다. Autoboxing은 좋은 구문 설탕이지만 여전히 성능 저하입니다. 어떤 경우라도 컴파일러가 자동 상자에 경고를 표시하고 싶습니다. (내가 아는 한, 2010 년에이 답변을 썼습니다.)

권투에 대한 좋은 설명 : 왜 일부 언어에 Boxing과 Unboxing이 필요합니까?

그리고 자바 제네릭에 대한 비판 : 왜 일부는 자바의 제네릭 구현이 나쁘다고 주장 하는가?

자바의 방어에서는 뒤돌아보고 비판하기 쉽습니다. JVM은 오랜 세월의 시험을 견뎌 왔고 여러면에서 좋은 디자인입니다.


6
실수가 아니라 신중하게 선택한 트레이드 오프가 실제로 Java를 매우 잘 제공했다고 생각합니다.
DJClayworth 2011 년

13
.NET이 처음부터 오토 박싱을 배웠고, 처음부터 오토 박싱을 구현했고, 제네릭을 박싱 오버 헤드없이 VM 수준에서 구현 한 것은 실수였습니다. 수정을위한 자바의 시도는 여전히 autoboxing의 성능 저하를 겪고있는 구문 수준의 솔루션 일뿐입니다. Java의 구현은 대규모 데이터 구조로 인해 성능이 저하되었습니다.
codenheim 2011 년

2
@mrjoltcola : IMHO, 기본 오토 박싱은 실수이지만, 주어진 값을 자동으로 박스해야하는 변수와 매개 변수에 태그를 지정하는 방법이 있어야합니다. 지금도 특정 변수 나 매개 변수가 새로 자동 박싱 된 값을 허용 하지 않도록 지정하는 수단이 추가되어야한다고 생각 합니다. 예를 들어 , 박싱 된 정수를 식별하는 Object.ReferenceEquals유형의 참조 를 전달 Object하는 것이 합법적이어야하지만 합법적이어서는 안됩니다. 정수 값 전달]. Java의 자동 언 박싱은 IMHO에 불과합니다.
supercat 2014-06-08

18

구현을 더 쉽게 만듭니다. 자바 프리미티브는 객체로 간주되지 않으므로 이러한 각 프리미티브에 대해 별도의 컬렉션 클래스를 만들어야합니다 (공유 할 템플릿 코드 없음).

물론 GNU Trove , Apache Commons Primitives 또는 HPPC를 참조하십시오 .

정말 큰 컬렉션이 없다면, 래퍼에 대한 오버 헤드는 사람들이 관심을 가질만큼 충분히 중요하지 않습니다 (그리고 정말 큰 원시 컬렉션이있는 경우에는 특수 데이터 구조를 사용 / 구축하는 데 많은 노력을 기울일 수 있습니다. ).


11

두 가지 사실의 조합입니다.

  • 자바 프리미티브 유형은 참조 유형이 아닙니다 (예 : an intis not an Object).
  • Java는 참조 유형의 유형 삭제를 사용하여 제네릭을 수행합니다 (예 : a List<?>는 실제로 List<Object>런타임에 있음).

이 두 가지 모두 사실이므로 일반 Java 컬렉션은 기본 유형을 직접 저장할 수 없습니다. 편의를 위해 기본 유형이 참조 유형으로 자동으로 boxing 될 수 있도록 autoboxing이 도입되었습니다. 하지만 실수하지 마십시오. 컬렉션은 여전히 ​​객체 참조를 저장하고 있습니다.

이것을 피할 수 있었습니까? 혹시.

  • 이 경우 int입니다 Object, 모든에서 상자 유형에 대한 필요가 없습니다.
  • 유형 삭제를 사용하여 제네릭을 수행하지 않으면 유형 매개 변수에 기본 형식을 사용할 수 있습니다.

8

의 개념이 자동 복싱 및 자동 언 박싱은. 당신이 저장하려고 할 경우 intA의 List<Integer>자바 컴파일러는 자동으로 변환됩니다 Integer.


1
Autoboxing은 Generics와 함께 Java 1.5에서 도입되었습니다.
제레미

1
그러나 그것은 컴파일 시간입니다. 성능 이점이없는 구문 설탕. Java 컴파일러는 자동 상자를 사용하므로 제네릭이 권투를 포함하지 않는 .NET과 같은 VM 구현에 비해 성능이 저하됩니다.
codenheim 2011 년

1
@mrjoltcola : 당신의 요점은 무엇입니까? 나는 논쟁을하지 않고 사실을 공유하고 있었다.
제레미

3
내 요점은 구문과 성능의 차이를 지적하는 것이 중요합니다. 나는 또한 내 의견이 논쟁이 아니라 사실을 공유한다고 생각합니다. 감사.
codenheim 2011 년

2

정말 제약이 아닌가?

기본 값을 저장하는 컬렉션을 만들고 싶다면 고려하십시오. int, float 또는 char를 저장할 수있는 컬렉션을 어떻게 작성 하시겠습니까? 대부분의 경우 여러 컬렉션으로 끝날 것이므로 intlist와 charlist 등이 필요합니다.

컬렉션 클래스를 작성할 때 Java의 객체 지향 특성을 활용하면 모든 객체를 저장할 수 있으므로 하나의 컬렉션 클래스 만 필요합니다. 다형성이라는이 아이디어는 매우 강력하며 라이브러리 설계를 크게 단순화합니다.


7
"int, float 또는 char를 저장할 수있는 컬렉션을 어떻게 작성 하시겠습니까?" -다른 언어처럼 제대로 구현 된 제네릭 / 템플릿을 사용하면 모든 것을 객체 인 척하는 페널티를 지불하지 않습니다.
codenheim 2010 년

6 년 동안 Java에서 원시 컬렉션을 저장하고 싶었던 적이 거의 없습니다. 참조 객체를 사용하는 데 드는 추가 시간과 공간 비용을 원했던 몇 안되는 경우에도 무시할 수있는 수준이었습니다. 특히 많은 사람들이 Map <int, T>를 원한다고 생각하고 배열이 그 트릭을 아주 잘 할 것이라는 사실을 잊었습니다.
DJClayworth 2011 년

2
@DJClayworth 키 값이 희소하지 않은 경우에만 잘 작동합니다. 물론 보조 배열을 사용하여 키를 추적 할 수는 있지만 자체 문제가 있습니다. 상대적으로 효율적인 액세스는 이진 검색을 허용하기 위해 키 순서에 따라 정렬 된 두 배열을 유지해야하므로 삽입 및 삭제가 수행됩니다. 삽입 / 삭제 패턴이 삽입 된 항목이 이전에 삭제 된 항목이 있던 위치에서 끝나거나 일부 버퍼가 배열에 산재 해있을 가능성이있는 경우를 제외하고는 비효율적입니다. 사용 가능한 리소스가 있지만 포함하는 것이 좋습니다. 자바 자체.
JAB 2014 년

@JAB 실제로 키가 드문 경우 제대로 작동하며 드문 경우보다 더 많은 메모리가 필요합니다. 키가 희소하면 키가 많지 않으며 Integer를 키로 사용하면 잘 작동합니다. 최소한의 메모리가 필요한 접근 방식을 사용하십시오. 또는 당신이 신경 쓰지 않는다면 당신이 느끼는 것.
DJClayworth 2014 년

0

- 나는 우리가이 JEP에 따라 가능한 자바 (10)의 JDK에서이 공간에서 진행 상황을 볼 수 있습니다 생각 http://openjdk.java.net/jeps/218 .

오늘날 컬렉션에서 기본 복싱을 사용하지 않으려면 몇 가지 타사 대안이 있습니다. 앞서 언급 한 타사 옵션 외에도 Eclipse Collections , FastUtilKoloboke가 있습니다.

원시지도의 비교도 얼마 전에 Large HashMap 개요 : JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove 라는 제목으로 게시되었습니다 . GS Collections (Goldman Sachs) 라이브러리는 Eclipse Foundation으로 마이그레이션되었으며 이제 Eclipse Collections입니다.


0

주된 이유는 자바 디자인 전략입니다. ++ 1) 컬렉션은 조작을 위해 객체를 필요로하며 원시는 객체에서 파생되지 않으므로 다른 이유가 될 수 있습니다. 2) Java 기본 데이터 유형은 예를 들어 참조 유형이 아닙니다. int는 객체가 아닙니다.

극복하기:-

자동 박싱과 자동 언 박싱의 개념이 있습니다. 따라서 기본 데이터 유형을 저장하려는 경우 컴파일러는 자동으로 해당 기본 데이터 클래스의 객체로 변환합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.