왜 사람들은 여전히 자바에서 원시형을 사용하는가?
Java 5 이후 원시 유형의 박싱/언박싱을 통해int로 포장되어 있다java.lang.Integer, 등등.
최근 많은 새로운 자바 프로젝트 (6은 아니더라도 적어도 버전5의 JRE가 필요)를 사용하고 있습니다.int보다는java.lang.Integer후자를 사용하는 것이 훨씬 편리하지만, 로 변환하기 위한 도우미 방법이 몇 가지 있기 때문에long값 등
왜 아직도 Java에서 원시 유형을 사용하는가?눈에 띄는 이점이 있나요?
Joshua Bloch의 Effective Java, Item 5: "불필요한 오브젝트 생성 방지"에서 그는 다음 코드 예를 게시합니다.
public static void main(String[] args) {
Long sum = 0L; // uses Long, not long
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
달리는 데 43초가 걸립니다.롱을 원시로 가져가면 6.8초로 단축되고...우리가 왜 원형을 사용하는지 알 수 있다면요
원어민 가치의 평등성 결여도 우려된다..equals()에 비해 상당히 장황하다==)
biziclop의 경우:
class Biziclop {
public static void main(String[] args) {
System.out.println(new Integer(5) == new Integer(5));
System.out.println(new Integer(500) == new Integer(500));
System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
}
}
결과:
false
false
true
false
편집 (3)이 반환되는 이유true(4) 반품false?
왜냐하면 그들은 서로 다른 두 물체이기 때문이다.0에 가장 가까운 256개의 정수 [-128; 127]는 JVM에 의해 캐시되므로 동일한 개체를 반환합니다.그러나 이 범위를 초과하면 캐시되지 않으므로 새 개체가 생성됩니다.상황을 더 복잡하게 만들기 위해 JLS는 최소 256개의 플라이웨이트를 캐시할 것을 요구하고 있습니다.JVM 구현자는 필요에 따라 추가 작업을 수행할 수 있습니다. 즉, 가장 가까운 1024개가 캐시되고 모두 true로 반환되는 시스템에서 실행할 수 있습니다.#실패하다
자동 보관함은 NPE를 발견하기 어려운 원인이 될 수 있습니다.
Integer in = null;
...
...
int i = in; // NPE at runtime
대부분의 경우 에 대한 늘 할당in위보다 훨씬 덜 명백합니다.
박스 타입의 경우는, 퍼포먼스가 저하해, 메모리 용량이 증가합니다.
기본 유형:
int x = 1000;
int y = 1000;
이제 평가:
x == y
그건…true놀랄 일도 아니지이제 박스 타입을 시험해 보겠습니다.
Integer x = 1000;
Integer y = 1000;
이제 평가:
x == y
그건…false. 아마도.런타임에 따라 다릅니다.그 이유만으로 충분합니까?
퍼포먼스와 메모리의 문제 외에, 또 다른 문제가 있습니다.인터페이스가 고장나면int.
문제는 과부하입니다.remove()메서드(remove(int)와 )를 비교. remove(Integer)는 항상 후자를 호출하기 때문에 인덱스로 요소를 삭제할 수 없습니다.
한편, 다른 한편으로, 추가 및 삭제를 시도할 때 문제가 있습니다.int:
final int i = 42;
final List<Integer> list = new ArrayList<Integer>();
list.add(i); // add(Object)
list.remove(i); // remove(int) - Ouch!
정말 상상이 가십니까?
for (int i=0; i<10000; i++) {
do something
}
java.loop을 사용합니다.대신 정수?java.lang.정수는 불변하기 때문에 루프를 도는 각 증분은 하나의 JVM 명령으로 스택의 int만 증분하는 것이 아니라 힙에 새로운 Java 객체를 만듭니다.그 공연은 끔찍할 것이다.
java.lang을 사용하는 것이 훨씬 편리한 모드라는 것에는 반대합니다.int보다 큰 정수입니다.그 반대야.자동박스는 Integer를 사용하지 않으면 강제로 Integer를 사용할 수 있는 것을 의미하며, Java 컴파일러는 새로운 Integer 개체를 만드는 코드를 삽입합니다.자동박스는 컴파일러가 관련 객체 구조를 삽입하여 Integer가 예상되는 int를 사용할 수 있도록 하는 것입니다.애초에 int의 필요성을 없애거나 줄이는 것은 아닙니다.오토박스를 통해 두 가지 장점을 모두 누릴 수 있습니다.힙 기반 Java 객체가 필요할 때 자동으로 Integer가 생성되며, 산술 및 로컬 계산만 수행해도 int의 속도와 효율성을 얻을 수 있습니다.
원시 유형이 훨씬 빠릅니다.
int i;
i++;
Integer(모든 번호 및 문자열)는 불변의 유형입니다.일단 작성하면 변경할 수 없습니다.한다면i다음 중 하나의 정수i++새로운 Integer 오브젝트를 만듭니다.메모리와 프로세서의 관점에서 보면 훨씬 더 비쌉니다.
무엇보다도, 습관이다.자바에서 8년간 코드화하면 상당한 관성이 축적됩니다.굳이 변경할 이유가 없는데 왜 변경합니까?박스형 프리미티브를 사용하는 데 추가적인 이점이 있는 것은 아닙니다.
또 다른 이유는 이라고 단언하는 것이다.null유효한 옵션이 아닙니다.2개의 숫자 또는 루프 변수의 합계를 다음과 같이 선언하는 것은 무의미하고 오해의 소지가 있습니다.Integer.
퍼포먼스 측면도 있습니다.많은 경우 퍼포먼스 차이는 중요하지 않지만(매우 나쁘지만), 이미 익숙한 방법으로 쉽게 작성할 수 있는 코드를 작성하는 것을 좋아하는 사람은 없습니다.
덧붙여서 Smalltalk는 오브젝트(원본 없음)만을 가지고 있지만, 작은 정수(32비트 전체가 아닌 27비트 등)를 최적화하여 힙스페이스를 할당하지 않고 특별한 비트패턴만 사용하고 있습니다.또한 다른 일반적인 오브젝트(true, false, null)에도 특별한 비트패턴이 있어요
따라서 적어도 64비트 JVM(64비트 포인터 네임스페이스 포함)에서는 Integer, Character, Byte, Short, Boolean, Float(및 small Long) 개체를 전혀 가질 수 없습니다(명시적으로 생성된 개체는 제외).new ...()특별한 비트 패턴만 있습니다.일반 오퍼레이터에 의해 매우 효율적으로 조작할 수 있습니다.
아무도 내가 생각하는 가장 중요한 이유를 언급하지 않았다니 믿을 수 없다: "int"는 "integer"보다 타이핑하기가 훨씬 더 쉽다.나는 사람들이 간결한 구문의 중요성을 과소평가한다고 생각한다.숫자를 사용하는 대부분의 경우 루프 인덱스에 포함되어 있기 때문에 성능으로는 이러한 인덱스를 피할 수 없습니다.또한 이러한 인덱스를 증가시켜 비교해도 (int 또는 Integer를 사용하는 경우에도) 비용이 들지 않습니다.
또 다른 이유는 NPE를 취득할 수 있지만 박스형에서는 회피하기 매우 쉽기 때문입니다(또한 NPE를 늘이 아닌 값으로 초기화하는 한 반드시 회피할 수 있습니다).
또 다른 이유는 (새로운 Long(1000))입니다.==(new Long(1000))은 거짓이지만, 이는 ".filength"가 (연산자 <, >, = 등과 달리) 박스형 구문을 지원하지 않는다는 또 다른 표현이기 때문에 "parament syntax"의 이유로 돌아갑니다.
Steve Yegge의 비인기 루프 예는 제 요점을 잘 보여주고 있다고 생각합니다.
이것을 생각해 보세요: 실행 가능 및 호출 가능 및 이름 없는 클래스 등의 인터페이스를 사용하여 시뮬레이션해야 하는 Java에 비해 함수 유형에 적합한 구문(기능 언어, 파이썬, 루비, 심지어 C)을 가진 언어로 함수 유형을 얼마나 자주 사용하는지.
기본 요소를 제거하지 않는 몇 가지 이유는 다음과 같습니다.
- 하위 호환성
없애버리면 오래된 프로그램도 실행되지 않을 거예요.
- JVM의 리라이트
이 새로운 기능을 지원하려면 전체 JVM을 다시 작성해야 합니다.
- 메모리 설치 공간 확대.
더 많은 메모리를 사용하는 값과 참조를 저장해야 합니다.대량의 바이트 배열이 있는 경우byte는 사용하는 것보다 훨씬 작습니다.Byte의
- 특수한 포인터의 문제.
선언하다int i그럼 뭐 하는 거야?i문제가 발생하지 않을 것입니다만약에Integer i같은 방법으로 하면 NPE가 됩니다.
- 평등 문제
다음 코드를 고려하십시오.
Integer i1 = 5;
Integer i2 = 5;
i1 == i2; // Currently would be false.
거짓일 거야.연산자는 과부하가 되어 버립니다.그 결과, 중대한 재작성이 발생합니다.
- 느리다
오브젝트 래퍼는 원시 래퍼보다 상당히 느립니다.
오브젝트는 원시 유형보다 훨씬 무겁기 때문에 래퍼 클래스의 인스턴스보다 원시 유형이 훨씬 효율적입니다.
원시 유형은 매우 간단합니다. 예를 들어 int는 32비트이며 메모리에서 정확히 32비트를 차지하며 직접 조작할 수 있습니다.Integer 개체는 완전한 개체로, (다른 개체와 마찬가지로) 힙에 저장해야 하며 해당 개체에 대한 참조(포인터)를 통해서만 액세스할 수 있습니다.또, 32비트(4바이트) 이상의 메모리를 소비하는 경우가 대부분입니다.
그러나 자바가 원시형과 비원시형을 구별한다는 점도 자바 프로그래밍 언어의 시대적 징후다.새로운 프로그래밍 언어에는 이러한 구분이 없습니다.이러한 언어의 컴파일러는 단순한 값을 사용하는지, 더 복잡한 개체를 사용하는지를 스스로 파악할 수 있습니다.
예를 들어 Scala에는 원시 유형이 없습니다. 정수에 대한 클래스 Int가 있으며 Int는 실제 개체(메서드 등 사용 가능)입니다.컴파일러는 코드를 컴파일할 때 백그라운드에서 원시 int를 사용하기 때문에 Int를 사용하는 것은 Java에서 원시 int를 사용하는 것만큼 효율적입니다.
다른 사람이 말한 것 외에 원시 로컬 변수는 힙에서 할당되지 않고 스택에 할당됩니다.그러나 개체는 힙에서 할당되므로 가비지 수집해야 합니다.
어떤 종류의 최적화가 진행되고 있는지 알 수 없습니다.
로컬에서 사용하는 경우, Null 값을 제외하고 컴파일러가 최적화를 할 수 있는 충분한 정보를 가지고 있을 때, 성능은 같거나 비슷할 것으로 예상합니다.
그러나 기본 요소의 배열은 상자에 들어 있는 기본 요소의 집합과 매우 다릅니다.이는 컬렉션 내에서 가능한 최적화가 극히 적다는 점을 고려할 때 의미가 있습니다.
더 나아가,Integer에 비해 논리적인 오버헤드가 훨씬 높다.int: 지금 고민할 필요가 있습니다.int a = b + c;예외가 발생합니다.
가능한 한 원시 요소를 사용하고 공장 방법과 자동 상자에 의존하여 필요할 때 의미론적으로 더 강력한 박스 유형을 제공합니다.
int loops = 100000000;
long start = System.currentTimeMillis();
for (Long l = new Long(0); l<loops;l++) {
//System.out.println("Long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around Long: "+ (System.currentTimeMillis()- start));
start = System.currentTimeMillis();
for (long l = 0; l<loops;l++) {
//System.out.println("long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around long: "+ (System.currentTimeMillis()- start));
'100000000'을 1바퀴 도는 데 걸리는 시간(밀리초): 468
'100000000'을 길게 반복하는 데 걸리는 시간: 31
덧붙여서, 나는 이런 것이 자바에 들어가는 것을 보는 것을 꺼리지 않을 것이다.
Integer loop1 = new Integer(0);
for (loop1.lessThan(1000)) {
...
}
여기서 for 루프는 loop1을 0에서1000으로 자동으로 증가시킵니다.
Integer loop1 = new Integer(1000);
for (loop1.greaterThan(0)) {
...
}
여기서 for 루프는 loop1 1000을 0으로 자동으로 감소시킵니다.
프리미티브 타입에는 다음과 같은 장점이 있습니다.
- 쓰기 쉬운 코드
- 변수의 개체를 인스턴스화하지 않기 때문에 성능이 향상됩니다.
- 오브젝트에 대한 참조가 아니므로 null을 확인할 필요가 없습니다.
- 복싱 기능을 활용할 필요가 없는 한 원시 유형을 사용하십시오.
- 수학적 연산을 하려면 원소가 필요합니다.
- 프리미티브는 위의 답변과 같이 메모리 소모가 적고 퍼포먼스가 향상됩니다.
클래스/오브젝트 유형이 필요한 이유를 묻습니다.
오브젝트 타입이 있는 이유는 컬렉션을 취급할 때 우리의 생활을 편리하게 하기 위해서입니다.원본을 목록/맵에 직접 추가할 수 없으며 래퍼 클래스를 작성해야 합니다.Readymade Integer Classes는 Integer.pareseInt(str)와 같은 많은 유틸리티 메서드를 갖추고 있습니다.
이전 답변에 동의합니다. 프리미티브 래퍼 개체를 사용하면 비용이 많이 들 수 있습니다.그러나 애플리케이션에서 성능이 중요하지 않은 경우에는 개체를 사용할 때 오버플로를 방지할 수 있습니다.예를 들어 다음과 같습니다.
long bigNumber = Integer.MAX_VALUE + 2;
가치bigNumber는 -2147483647 이며, 2147483649 가 됩니다.코드상의 버그이며, 다음의 조작에 의해서 수정됩니다.
long bigNumber = Integer.MAX_VALUE + 2l; // note that '2' is a long now (it is '2L').
그리고.bigNumber2147483649 입니다.이러한 종류의 버그는 놓치기 쉽고 불분명한 동작이나 취약성을 일으킬 수 있습니다(CWE-190 참조).
래퍼 개체를 사용하면 동등한 코드가 컴파일되지 않습니다.
Long bigNumber = Integer.MAX_VALUE + 2; // Not compiling
따라서 원시 래퍼 개체를 사용하면 이러한 문제를 쉽게 방지할 수 있습니다.
당신의 질문은 이미 답변이 끝난 상태이기 때문에, 이전에 언급되지 않았던 정보를 조금 더 추가하기 위해 회신합니다.
Because JAVA performs all mathematical operations in primitive types. Consider this example:
public static int sumEven(List<Integer> li) {
int sum = 0;
for (Integer i: li)
if (i % 2 == 0)
sum += i;
return sum;
}
Here, reminder and unary plus operations can not be applied on Integer(Reference) type, compiler performs unboxing and do the operations.
So, make sure how many autoboxing and unboxing operations happen in java program. Since, It takes time to perform this operations.
Generally, it is better to keep arguments of type Reference and result of primitive type.
The primitive types are much faster and require much less memory. Therefore, we might want to prefer using them.
On the other hand, current Java language specification doesn’t allow usage of primitive types in the parameterized types (generics), in the Java collections or the Reflection API.
When our application needs collections with a big number of elements, we should consider using arrays with as more “economical” type as possible.
*For detailed info see the source: https://www.baeldung.com/java-primitives-vs-objects
To be brief: primitive types are faster and require less memory than boxed ones
ReferenceURL : https://stackoverflow.com/questions/5199359/why-do-people-still-use-primitive-types-in-java
'programing' 카테고리의 다른 글
| ## 프리프로세서 오퍼레이터와 gotcha의 어플리케이션은 무엇입니까? (0) | 2022.07.26 |
|---|---|
| C++에서 로컬 환경 변수 설정 (0) | 2022.07.26 |
| C의 구조 부재 기본값 (0) | 2022.07.26 |
| Java 11에서의 String trim() 메서드와 strip() 메서드의 차이 (0) | 2022.07.26 |
| malloc과 calloc의 차이점? (0) | 2022.07.26 |