C++와 Java의 "일반" 유형의 차이점은 무엇입니까?
Java는 제네릭스를 가지고 있으며 C++는 매우 강력한 프로그래밍 모델을 제공합니다.templates. 그렇다면 C++와 Java 제네릭스의 차이점은 무엇일까요?
그들 사이에는 큰 차이가 있다.C++ 에서는, 범용 타입의 클래스나 인터페이스를 지정할 필요는 없습니다.그렇기 때문에 타이핑이 느슨하다는 경고와 함께 진정한 범용 함수와 클래스를 만들 수 있습니다.
template <typename T> T sum(T a, T b) { return a + b; }
위의 메서드는 동일한 유형의 개체를 2개 추가하여 "+" 연산자를 사용할 수 있는 모든 유형 T에 사용할 수 있습니다.
Java에서는 전달된 객체에 대해 메서드를 호출하려면 다음과 같은 유형을 지정해야 합니다.
<T extends Something> T sum(T a, T b) { return a.add ( b ); }
C++에서는 범용 함수/클래스는 헤더에만 정의할 수 있습니다.컴파일러는 (호출되는) 타입에 따라 다른 함수를 생성하기 때문입니다.그래서 컴파일이 느립니다.Java에서는 컴파일에 큰 패널티가 없지만 Java는 실행 시 범용 타입이 지워지는 "삭제"라는 기술을 사용합니다.실제로 실행 시 Java가 호출하고 있습니다.
Something sum(Something a, Something b) { return a.add ( b ); }
따라서 Java의 범용 프로그래밍은 그다지 유용하지 않습니다.새로운 foreach 구조에 도움이 되는 것은 약간의 구문설탕일 뿐입니다.
편집: 유용성에 대한 위의 의견은 젊은 자신에 의해 작성되었습니다.Java의 제네릭스는 물론 활자 안전에 도움이 됩니다.
Java Generics는 C++ 템플릿과는 크게 다릅니다.
기본적으로 C++ 템플릿은 미화된 프리프로세서/매크로 세트입니다(주의: 유추를 이해할 수 없는 사람도 있기 때문에 템플릿 처리가 매크로라고 하는 것은 아닙니다).Java에서는 기본적으로 물체의 보일러 플레이트 주조를 최소화하기 위한 통사 설탕입니다.다음은 C++ 템플릿과 Java 범용 템플릿에 대한 꽤 괜찮은 소개입니다.
이 점에 대해 자세히 설명하자면, C++ 템플릿을 사용하는 경우 기본적으로는 다른 코드 복사본을 만듭니다.#define매크로를 사용하면, 예를 들면, specific, specific, specialint어레이 크기를 결정하는 템플릿 정의의 매개 변수입니다.
자바는 그런 식으로 동작하지 않습니다.Java에서는 모든 객체가 java.lang에서 확장됩니다.목적: 제네릭 이전 버전에서는 다음과 같이 코드를 작성합니다.
public class PhoneNumbers {
private Map phoneNumbers = new HashMap();
public String getPhoneNumber(String name) {
return (String) phoneNumbers.get(name);
}
}
왜냐하면 모든 Java 컬렉션 타입이 오브젝트를 베이스 타입으로 사용했기 때문에 어떤 것이든 넣을 수 있기 때문입니다.Java 5는 다음과 같은 작업을 수행할 수 있도록 일반 기능을 추가합니다.
public class PhoneNumbers {
private Map<String, String> phoneNumbers = new HashMap<String, String>();
public String getPhoneNumber(String name) {
return phoneNumbers.get(name);
}
}
Java Generics는 이것뿐입니다.객체 캐스팅용 래퍼입니다.그것은 자바 제네릭스가 세련되지 않았기 때문이다.그들은 활자 지우기를 사용합니다.이 결정은 Java Generics가 너무 늦게 나왔기 때문에 하위 호환성을 무너뜨리고 싶지 않았기 때문에 내려졌습니다(aMap<String, String>언제든지 사용할 수 있습니다.Map요구됩니다).와 비교합니다.유형 삭제가 사용되지 않는 Net/C#에서는 모든 종류의 차이가 발생합니다(예: 원시 유형 및IEnumerable그리고.IEnumerable<T>관계가 없다).
Java 5+ 컴파일러로 컴파일된 범용 클래스를 JDK 1.4에서 사용할 수 있습니다(Java 5+를 필요로 하는 다른 기능이나 클래스를 사용하지 않는 경우).
그것이 자바 제네릭스가 통사설탕이라고 불리는 이유이다.
그러나 제네릭스의 실행 방법에 대한 이 결정은 매우 큰 영향을 미쳤기 때문에 Java Generics에 대해 사람들이 가지고 있는 많은 의문점에 대한 답변을 제공하는 Java Generics FAQ가 생겨났다.
C++ 템플릿에는 Java Generics에는 없는 많은 기능이 있습니다.
primitive type 인수 사용.
예를 들어 다음과 같습니다.
template<class T, int i> class Matrix { int T[i][i]; ... }Java에서는 제네릭스에서 원시 형식 인수를 사용할 수 없습니다.
Java는 인수의 경계를 허용합니다.
예를 들어 다음과 같습니다.
public class ObservableList<T extends List> { ... }
다른 인수를 가진 템플릿 호출은 실제로 다른 유형임을 강조할 필요가 있습니다.그들은 심지어 정적 멤버도 공유하지 않는다.Java에서는 그렇지 않습니다.
범용과의 차이 외에도 완전성을 위해 C++와 Java(및 다른 것)의 기본적인 비교를 소개합니다.
그리고 자바어로 생각하는 것도 제안할 수 있습니다.C++ 프로그래머로서 오브젝트와 같은 많은 개념들은 이미 제2의 천성이지만 미묘한 차이가 있기 때문에 여러분이 일부를 훑어보더라도 소개문을 갖는 것이 가치가 있을 수 있습니다.
Java를 배울 때 배우게 될 많은 것은 모든 라이브러리입니다(스탠다드 라이브러리(JDK에 포함되어 있는 것)와 비표준 라이브러리(Spring 등 일반적으로 사용되는 것 포함).Java 구문은 C++ 구문보다 상세하고 C++ 기능(연산자 오버로드, 다중 상속, 파괴자 메커니즘 등)이 많지 않지만 엄밀하게는 C++의 서브셋이 되지 않습니다.
C++에는 템플릿이 있습니다.Java에는 C++ 템플릿처럼 보이는 제네릭스가 있지만 매우 다릅니다.
템플릿은 이름에서 알 수 있듯이 컴파일러에 (대기) 템플릿을 제공하여 템플릿 파라미터를 입력하여 타입 세이프 코드를 생성할 수 있습니다.
제네릭스는 반대로 작동합니다.유형 파라미터는 컴파일러가 사용하는 코드가 안전한지 확인하기 위해 사용되지만 결과 코드는 전혀 유형 없이 생성됩니다.
C++ 템플릿은 정말 좋은 매크로 시스템이고 Java 범용은 자동으로 타입캐스트를 생성하기 위한 도구라고 생각하십시오.
C++ 템플릿에는 Java 제네릭에는 없는 또 다른 기능이 있습니다.이를 통해 특정 유형에 대해 다른 구현을 수행할 수 있습니다.예를 들어 int에 대해 고도로 최적화된 버전을 가지면서도 나머지 유형에 대해서는 일반 버전을 유지할 수 있습니다.또는 포인터와 비포인터 유형의 버전이 다를 수 있습니다.이 기능은 포인터를 건네줄 때 참조되지 않은 오브젝트를 조작하려는 경우에 편리합니다.
모리스 나프탈린, 필립 와들러의 자바 제네릭스와 컬렉션에 이 주제에 대한 훌륭한 설명이 있습니다.저는 이 책을 강력히 추천합니다.견적 내용:
Java의 제네릭은 C++의 템플릿과 유사합니다....구문은 의도적으로 비슷하고 의미론도 의도적으로 다릅니다.의미론적으로 Java 제네릭은 소거에 의해 정의되며 C++ 템플릿은 확장에 의해 정의됩니다.
자세한 내용은 이쪽에서 읽어주세요.

(출처 : oreilly.com )
기본적으로 AFAIK, C++ 템플릿은 유형별로 코드의 복사본을 만들지만 Java 제네릭은 동일한 코드를 사용합니다.
네, C++ 템플릿은 Java 범용 개념과 동등하다고 할 수 있습니다(단, Java 범용은 C++ 개념과 동등하다고 하는 것이 더 적절합니다).
C++의 템플릿 메커니즘을 잘 알고 있다면 제네릭은 비슷하지만 유사성은 피상적인 것이라고 생각할 수 있습니다.제네릭은 각 전문분야에 대해 새로운 클래스를 생성하지 않으며 "템플릿 메타프로그래밍"도 허용하지 않습니다.
출처: Java Generics
Java(및 C#) 제네릭은 단순한 런타임 유형 대체 메커니즘으로 보입니다.
C++ 템플릿은 필요에 따라 언어를 변경할 수 있는 컴파일 시간 구성입니다.실제로는 컴파일러가 컴파일 중에 실행하는 순수 기능 언어입니다.
C++ 템플릿의 또 다른 장점은 전문화입니다.
template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
Special sum(const Special& a, const Special& b) { return a.plus(b); }
포인터를 사용하여 sum을 호출하면 두 번째 메서드가 호출되고 포인터가 아닌 오브젝트를 사용하여 sum을 호출하면 첫 번째 메서드가 호출됩니다.sum와 함께Special세 번째 오브젝트가 호출됩니다.자바에서는 불가능할 것 같아요.
한 문장으로 요약하겠습니다.템플릿은 새로운 타입을 만들고 제네릭은 기존 타입을 제한합니다.
아래 답변은 "코딩 인터뷰 솔루션 크래킹"이라는 책에서 13장에 나온 것으로, 저는 매우 좋다고 생각합니다.
Java 제네릭스의 구현은 '유형 삭제:'라는 아이디어에 뿌리를 두고 있습니다.이 기술은 소스 코드가 Java Virtual Machine(JVM; Java 가상 머신) 바이트 코드로 변환될 때 매개 변수화된 유형을 제거합니다.예를 들어 다음과 같은 Java 코드가 있다고 가정합니다.
Vector<String> vector = new Vector<String>();
vector.add(new String("hello"));
String str = vector.get(0);
컴파일 중에 이 코드는 다음 위치에 다시 쓰여집니다.
Vector vector = new Vector();
vector.add(new String("hello"));
String str = (String) vector.get(0);
Java 제네릭스의 사용은 우리의 능력에 큰 변화를 준 것이 아니라 단지 상황을 조금 더 아름답게 만들었다.이러한 이유로 자바 제네릭스는 때때로 "통사설탕:"이라고 불립니다.
이것은 C++와는 상당히 다릅니다.C++에서 템플릿은 기본적으로 미화된 매크로 세트이며 컴파일러는 각 유형에 대한 템플릿 코드의 새로운 복사본을 만듭니다.MyClass 인스턴스가 MyClass와 정적 변수를 공유하지 않는다는 것이 그 증거입니다.그러나 MyClass의 두 인스턴스는 정적 변수를 공유합니다.
/*** MyClass.h ***/
template<class T> class MyClass {
public:
static int val;
MyClass(int v) { val v;}
};
/*** MyClass.cpp ***/
template<typename T>
int MyClass<T>::bar;
template class MyClass<Foo>;
template class MyClass<Bar>;
/*** main.cpp ***/
MyClass<Foo> * fool
MyClass<Foo> * foo2
MyClass<Bar> * barl
MyClass<Bar> * bar2
new MyClass<Foo>(10);
new MyClass<Foo>(15);
new MyClass<Bar>(20);
new MyClass<Bar>(35);
int fl fool->val; // will equal 15
int f2 foo2->val; // will equal 15
int bl barl->val; // will equal 35
int b2 bar2->val; // will equal 35
Java에서는 스태틱 변수는 다른 유형의 파라미터에 관계없이 MyClass 인스턴스 간에 공유됩니다.
Java 범용 템플릿과 C++ 템플릿에는 그 밖에도 많은 차이가 있습니다.여기에는 다음이 포함됩니다.
- C++ 템플릿은 int와 같은 원시 유형을 사용할 수 있습니다.Java는 Integer를 대신 사용할 수 없습니다.
- Java에서는 템플리트의 유형 매개변수를 특정 유형으로 제한할 수 있습니다.예를 들어 Generic을 사용하여 CardDeck를 구현하고 유형 파라미터를 CardGame에서 확장하도록 지정할 수 있습니다.
- C++에서는 type 파라미터를 인스턴스화할 수 있지만 Java는 이를 지원하지 않습니다.
- Java에서는 유형 파라미터(MyClass의 Foo)는 MyClass와 MyClass 간에 공유되기 때문에 정적 메서드 및 변수에 사용할 수 없습니다.C++에서는 이러한 클래스는 서로 다르기 때문에 type 파라미터를 스태틱메서드와 변수에 사용할 수 있습니다.
- Java에서는 유형 매개 변수에 관계없이 MyClass의 모든 인스턴스가 동일한 유형입니다.유형 매개 변수는 런타임에 지워집니다.C++에서는 타입 파라미터가 다른 인스턴스는 다른 타입입니다.
@키스:
이 코드는 실제로는 잘못된 것이며 작은 결함과는 별개입니다.template생략, 특수화 구문은 다르게 표시됨) 부분 특수화는 함수 템플릿에서는 작동하지 않으며 클래스 템플릿에서만 작동합니다.단, 이 코드는 부분 템플릿 지정 없이 동작하며 플레인오래된 오버로드를 사용합니다.
template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
템플릿은 매크로 시스템에 불과합니다.구문설탕.컴파일러는 실제 컴파일 전에 완전히 확장됩니다(또는 적어도 컴파일러는 실제 컴파일러인 것처럼 동작합니다).
예:
예를 들어 두 가지 기능이 필요합니다.한 함수는 두 개의 수열(리스트, 배열, 벡터 등)을 가져와서 그 내적을 반환합니다.다른 함수는 길이를 지정하여 해당 길이의 두 시퀀스를 생성하여 첫 번째 함수에 전달하고 결과를 반환합니다.단, 두 번째 함수가 잘못될 수 있으므로 두 함수의 길이가 동일하지 않습니다.이 경우 컴파일러가 경고를 해줘야 합니다.프로그램이 실행 중일 때가 아니라 컴파일 중일 때입니다.
Java에서는 다음과 같은 작업을 수행할 수 있습니다.
import java.io.*;
interface ScalarProduct<A> {
public Integer scalarProduct(A second);
}
class Nil implements ScalarProduct<Nil>{
Nil(){}
public Integer scalarProduct(Nil second) {
return 0;
}
}
class Cons<A implements ScalarProduct<A>> implements ScalarProduct<Cons<A>>{
public Integer value;
public A tail;
Cons(Integer _value, A _tail) {
value = _value;
tail = _tail;
}
public Integer scalarProduct(Cons<A> second){
return value * second.value + tail.scalarProduct(second.tail);
}
}
class _Test{
public static Integer main(Integer n){
return _main(n, 0, new Nil(), new Nil());
}
public static <A implements ScalarProduct<A>>
Integer _main(Integer n, Integer i, A first, A second){
if (n == 0) {
return first.scalarProduct(second);
} else {
return _main(n-1, i+1,
new Cons<A>(2*i+1,first), new Cons<A>(i*i, second));
//the following line won't compile, it produces an error:
//return _main(n-1, i+1, first, new Cons<A>(i*i, second));
}
}
}
public class Test{
public static void main(String [] args){
System.out.print("Enter a number: ");
try {
BufferedReader is =
new BufferedReader(new InputStreamReader(System.in));
String line = is.readLine();
Integer val = Integer.parseInt(line);
System.out.println(_Test.main(val));
} catch (NumberFormatException ex) {
System.err.println("Not a valid number");
} catch (IOException e) {
System.err.println("Unexpected IO ERROR");
}
}
}
C#에서도 거의 같은 것을 쓸 수 있습니다.C++로 다시 쓰려고 하면 컴파일되지 않고 템플릿의 무한 확장이 불만입니다.
여기서 질문의 차이를 인용하고 싶습니다.
C++와 Java의 주요 차이점은 플랫폼에 대한 의존성에 있습니다.C++는 플랫폼에 의존하는 언어이지만 Java는 플랫폼에 의존하지 않는 언어입니다.
위의 스테이트먼트가 C++가 진정한 범용 타입을 제공할 수 있는 이유입니다.Java는 엄격한 체크를 하고 있기 때문에 C++가 허용하는 제네릭스를 사용할 수 없습니다.
언급URL : https://stackoverflow.com/questions/36347/what-are-the-differences-between-generic-types-in-c-and-java
'source' 카테고리의 다른 글
| 매크로 값의 문자열화 (0) | 2022.08.28 |
|---|---|
| VueJS 메서드가 Axios에서 응답을 반환하지 않음 (0) | 2022.08.28 |
| Java: sun.security.provider.certpath.SunCertPathBuilder예외: 요청된 대상에 대한 올바른 인증 경로를 찾을 수 없습니다. (0) | 2022.08.28 |
| Vuex 내 구성 요소가 상태 변경에 반응하지 않음 (0) | 2022.08.28 |
| 앵커 태그가 있는 VueJ @click (0) | 2022.08.28 |