C ++과 Java에서 "일반"유형의 차이점은 무엇입니까?
Java에는 제네릭이 있으며 C ++은 templates를 사용 하여 매우 강력한 프로그래밍 모델을 제공합니다 . 그렇다면 C ++과 Java 제네릭의 차이점은 무엇입니까?
그들 사이에는 큰 차이가 있습니다. C ++에서는 제네릭 형식에 대한 클래스 나 인터페이스를 지정할 필요가 없습니다. 그렇기 때문에 타이핑이 느슨해지면 진정한 일반 함수와 클래스를 만들 수 있습니다.
template <typename T> T sum(T a, T b) { return a + b; }
위의 방법은 동일한 유형의 두 객체를 추가하며 "+"연산자를 사용할 수있는 모든 유형 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매크로 를 사용하는 것처럼 다른 코드 사본을 작성 합니다. 이를 통해 int배열의 크기 등을 결정하는 템플릿 정의에 매개 변수 가있는 것과 같은 작업을 수행 할 수 있습니다 .
Java는 그런 식으로 작동하지 않습니다. Java에서는 모든 객체가 java.lang.Object 에서 확장 되므로 pre-Generics는 다음과 같은 코드를 작성합니다.
public class PhoneNumbers {
private Map phoneNumbers = new HashMap();
public String getPhoneNumber(String name) {
return (String)phoneNumbers.get(name);
}
...
}
모든 Java 콜렉션 유형이 Object를 기본 유형으로 사용했기 때문에 무엇이든 넣을 수 있기 때문입니다. 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가 정제되지 않았기 때문입니다. 그들은 유형 삭제를 사용합니다. 이 결정은 Java Generics가 너무 늦게 나왔기 때문에 이전 버전과의 호환성을 깨뜨리고 싶지 않았습니다 (a Map<String, String>가 필요할 때마다 사용할 수 있음 Map). 형의 삭제를 사용하지 않을 경우, 닷넷 / C #이 비교되는 차이점의 모든 종류 (예를 들어, 당신이하고 기본 유형을 사용할 수 있습니다로 리드 IEnumerable하고 IEnumerable<T>서로 아무 관계도지지 않습니다).
Java 5+ 컴파일러로 컴파일 된 제네릭을 사용하는 클래스는 JDK 1.4에서 사용할 수 있습니다 (Java 5+가 필요한 다른 기능이나 클래스를 사용하지 않는다고 가정).
그렇기 때문에 Java Generics를 구문 설탕 이라고 합니다.
그러나 제네릭을 수행하는 방법에 대한이 결정은 많은 영향을 미쳤으므로 (최고의) Java 제네릭 FAQ 가 사람들이 Java 제네릭에 대해 가지고있는 많은 질문에 대답하기 위해 생겨났습니다.
C ++ 템플릿에는 Java Generics에없는 많은 기능이 있습니다.
기본 유형 인수 사용
예를 들면 다음과 같습니다.
template<class T, int i> class Matrix { int T[i][i]; ... }Java는 제네릭 형식에서 기본 형식 인수를 사용할 수 없습니다.
기본 유형 인수를 사용합니다 . Java에서 놓칠 수있는 기능 중 하나이지만 이전 버전과의 호환성 이유가 있습니다.
- Java는 인수의 경계를 허용합니다.
예를 들면 다음과 같습니다.
public class ObservableList<T extends List> {
...
}
다른 인수를 가진 템플릿 호출은 실제로 다른 유형이라는 점을 강조해야합니다. 정적 멤버도 공유하지 않습니다. Java에서는 그렇지 않습니다.
제네릭과의 차이점 외에도 완전성을 위해 C ++과 Java (및 다른 것 ) 의 기본 비교가 있습니다.
그리고 Thinking in Java 도 제안 할 수 있습니다 . C ++ 프로그래머로서 객체와 같은 많은 개념은 이미 제 2의 특성이지만 미묘한 차이점이 있으므로 부품을 훑어 보더라도 소개 텍스트를 갖는 것이 좋습니다.
Java를 배울 때 배우게 될 많은 것들이 모든 라이브러리 (JDK에 포함 된 표준 라이브러리)와 스프링과 같이 일반적으로 사용되는 것을 포함하는 비표준 라이브러리입니다. Java 구문은 C ++ 구문보다 더 장황하며 많은 C ++ 기능 (예 : 연산자 오버로드, 다중 상속, 소멸자 메커니즘 등)을 갖지 않지만 C ++의 하위 집합으로 만들어지는 것은 아닙니다.
C ++에는 템플릿이 있습니다. Java에는 제네릭이 있는데 C ++ 템플릿과 비슷하지만 매우 다릅니다.
템플릿은 이름에서 알 수 있듯이 템플릿 매개 변수를 입력하여 형식이 안전한 코드를 생성하는 데 사용할 수있는 (기다리는 중 ...) 템플릿을 컴파일러에 제공하여 작동합니다.
제네릭은 내가 이해하는 것처럼 다른 방법으로 작동합니다. 유형 매개 변수는 컴파일러에서 사용하여 코드를 사용하여 코드가 안전한지 확인하지만 결과 코드는 전혀 유형없이 생성됩니다.
C ++ 템플릿은 정말 좋은 매크로 시스템으로, Java 제네릭은 자동으로 타입 캐스트를 생성하는 도구로 생각하십시오 .
C ++ 템플릿의 또 다른 기능으로는 Java 제네릭에는없는 특수화 기능이 있습니다. 이를 통해 특정 유형에 대해 다른 구현을 가질 수 있습니다. 예를 들어 int에 대해 고도로 최적화 된 버전을 유지하면서도 나머지 유형에 대한 일반 버전을 유지할 수 있습니다. 또는 포인터 및 비 포인터 유형에 대해 다른 버전을 가질 수 있습니다. 포인터를 넘길 때 역 참조 된 객체를 조작하려는 경우에 유용합니다.
Java Generics and Collections의 Maurice Naftalin, Philip Wadler 에이 주제에 대한 훌륭한 설명이 있습니다. 나는이 책을 강력히 추천한다. 인용 :
Java의 제네릭은 C ++의 템플릿과 유사합니다. ... 구문은 의도적으로 유사하며 시맨틱은 의도적으로 다릅니다. ... 의미 적으로 Java 제네릭은 삭제에 의해 정의되며 C ++ 템플릿은 확장에 의해 정의됩니다.

(출처 : oreilly.com )
기본적으로 AFAIK, C ++ 템플릿은 각 유형에 대한 코드 사본을 생성하는 반면 Java 제네릭은 정확히 동일한 코드를 사용합니다.
Yes, you can say that C++ template is equivalent to Java generic concept ( although more properly would be to say Java generics are equivalent to C++ in concept )
If you are familiar with C++'s template mechanism, you might think that generics are similar, but the similarity is superficial. Generics do not generate a new class for each specialization, nor do they permit “template metaprogramming.”
from: Java Generics
Java (and C#) generics seem to be a simple run-time type substitution mechanism.
C++ templates are a compile-time construct which give you a way to modify the language to suit your needs. They are actually a purely-functional language that the compiler executes during a compile.
Another advantage of C++ templates is specialization.
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); }
Now, if you call sum with pointers, the second method will be called, if you call sum with non-pointer objects the first method will be called, and if you call sum with Special objects, the third will be called. I don't think that this is possible with Java.
I will sum it up in a single sentence: templates create new types, generics restricts existing types.
@Keith:
That code is actually wrong and apart from the smaller glitches (template omitted, specialization syntax looks differently), partial specialization doesn't work on function templates, only on class templates. The code would however work without partial template specialization, instead using plain old overloading:
template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
The answer below is from the book Cracking The Coding Interview Solutions to Chapter 13, which I think is very good.
The implementation of Java generics is rooted in an idea of"type erasure:'This technique eliminates the parameterized types when source code is translated to the Java Virtual Machine (JVM) bytecode. For example, suppose you have the Java code below:
Vector<String> vector = new Vector<String>();
vector.add(new String("hello"));
String str = vector.get(0);
During compilation, this code is re-written into:
Vector vector = new Vector();
vector.add(new String("hello"));
String str = (String) vector.get(0);
The use of Java generics didn't really change much about our capabilities; it just made things a bit prettier. For this reason, Java generics are sometimes called"syntactic sugar:'.
This is quite different from C++. In C++, templates are essentially a glorified macro set, with the compiler creating a new copy of the template code for each type. Proof of this is in the fact that an instance of MyClass will not share a static variable withMyClass. Tow instances of MyClass, however, will share a static variable.
/*** 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
In Java, static variables are shared across instances of MyClass, regardless of the different type parameters.
Java generics and C ++ templates have a number of other differences. These include:
- C++ templates can use primitive types, like int. Java cannot and must instead use Integer.
- In Java, you can restrict the template's type parameters to be of a certain type. For instance, you might use generics to implement a CardDeck and specify that the type parameter must extend from CardGame.
- In C++, the type parameter can be instantiated, whereas Java does not support this.
- In Java, the type parameter (i.e., the Foo in MyClass) cannot be used for static methods and variables, since these would be shared between MyClass and MyClass. In C++, these classes are different, so the type parameter can be used for static methods and variables.
- In Java, all instances of MyClass, regardless of their type parameters, are the same type. The type parameters are erased at runtime. In C++, instances with different type parameters are different types.
Templates are nothing but a macro system. Syntax sugar. They are fully expanded before actual compilation (or, at least, compilers behave as if it were the case).
Example:
Let's say we want two functions. One function takes two sequences (list, arrays, vectors, whatever goes) of numbers, and returns their inner product. Another function takes a length, generates two sequences of that length, passes them to the first function, and returns it's result. The catch is that we might make a mistake in the second function, so that these two functions aren't really of the same length. We need the compiler to warn us in this case. Not when the program is running, but when it's compiling.
In Java you can do something like this:
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");
}
}
}
In C# you can write almost the same thing. Try to rewrite it in C++, and it won't compile, complaining about infinite expansion of templates.
'Programming' 카테고리의 다른 글
| Ruby on Rails : 문자열을 HTML로 렌더링하는 방법? (0) | 2020.06.12 |
|---|---|
| 두 날짜 사이의 근무일 계산 (0) | 2020.06.12 |
| jquery check 버튼으로 모든 확인란을 선택 취소하십시오. (0) | 2020.06.12 |
| 다차원 배열의 너비와 높이를 어떻게 얻습니까? (0) | 2020.06.12 |
| 반응 양식의 소품 변경 상태 업데이트 (0) | 2020.06.12 |