자바와 C++의 비교
위키백과 ― 우리 모두의 백과사전.
프로그래밍 언어의 비교 |
일반
|
언어별
|
이 글은 자바 프로그래밍 언어와 C++ 프로그래밍 언어의 비교에 대한 글이다.
목차 |
[편집] 설계 목표
C++과 자바 언어의 차이는 각각의 탄생 역사에서 부터 찾을 수 있다.
- C++는 이름에서 나타나듯이 C 프로그래밍 언어를 더 확장하여 만들었다. 절차적 프로그래밍 언어에 효율적인 실행을 목표로 설계되었다. 정적 자료형 검사 객체 지향 프로그래밍, 예외 처리, RAII, 제네릭 프로그래밍을 지원한다. 범용 컨터이너와 알고리즘을 포함한 C++ 표준 라이브러리도 추가 되었다.
- 자바는 처음에는 가전제품에 탑재되어 네트워크 컴퓨팅을 지원하기 위해서 만들었다. 가상 머신위에서 실행되기 때문에 안전성을 가지며 또한 이식성이 높다. 하위 플랫폼을 완벽히 추상화 시켜주는 광대한 분량의 라이브러리를 가지고 있다. 자바는 C와 비슷한 문법을 사용할뿐 직접적인 호환성은 없다. 사용하기 편하고 많은 사람이 이해하기 쉬운 언어를 목표로 설계되었다.
두 언어는 개발의 목적이 다르기 때문에 결과적으로 서로 다른 원리, 방침, 설계에서 트레이드오프에 차이가 생겼다.
C++ | Java |
---|---|
C 소스 코드와 하위 호환성 | 다른 언어와 소스코드 호환성은 없음 |
직접적인 시스템 라이브러리 호출 가능 | Java Native Interface를 이용 |
저수준 시스템 접근 가능 | 안전하게 보호되는 가상 머신위에서 실행됨 |
선택적 자동 경계 검사 | 항상 자동 경계 검사함 |
부호없는(unsigned) 연산 지원 | 부호없는 연산 지원 안함 |
값에 의한 매개변수 전달 또는 참조에 의한 매개변수 전달 | 항상 값에 의한 매개변수 전달. 매개변수로 객체에 대한 참조값을 사용할 수는 있다. 참조 대상의 내용을 변경할 수는 있지만, 참조값 자체는 변경할 수 없다; 메서드 호출 후에도 참조하는 객체는 다른 객체로 바뀌지 않을 것이다. |
명시적 메모리 관리, 가비지 콜렉션은 추가적으로 라이브러리를 이용해야 함 | 항상 자동 가비지 콜렉션 |
명시적인 자료형 재정의 허용 | 자료형 안전성에 엄격함 |
C++ 표준 라이브러리는 적절한 범위까지 지원함 | 광대한 분량의 라이브러리 |
연산자 오버로딩 | 연산자는 재정의 할 수 없음 |
C++는 강력하지만 복잡하고 어려운 언어로, 성능 위주의 응용 프로그램이나 라이브러리에 적당하다. 자바는 대게 배우기 쉽지만, 플랫폼 자체가 가지는 전체 기능 이용이나 완벽한 성능 활용을 기대하기는 어렵다.
[편집] 언어의 특징
[편집] 문법
- 자바 문법은 간단한 LALR 파서에 의해 해석될 수 있는 문맥 자유 문법이다. C++ 해석은 약간 더 복잡하다. 예를 들면,
Foo<1>(3);
인 문장을 해석할 때 Foo가 변수라면 연속된 비교문 이지만, Foo가 클래스 템플릿 이름이라면 객체를 생성하게 된다. - C++은 이름 공간 레벨에 상수, 변수, 함수가 있을 수 있다. 자바에서는 모든 상수, 변수, 함수는 반드시 클래스나 인터페이스에 속해 있어야 한다.
- C++에 있는 const는 개념적으로 '읽기 전용' 데이터임을 명시하며 자료형에 적용된다. 자바에 있는 final은 변수가 다시 할당될 수 없음을 나타낸다. 기본 자료형에 대해서는 const int 와 final int 처럼 동일하지만, 복잡한 클래스에서는 조금 다른다:
C++ | Java |
---|---|
const Rectangle r; |
final Rectangle r = new Rectangle(); |
r = anotherRectangle; // 잘못 |
r = anotherRectangle; // 잘못 |
r.x = 5; // 잘못, r은 상수 Rectangle |
r.x = 5; // 올바름, r은 여전히 같은 Rectangle 객체를 참조하고 있다. |
- C++은 goto 문을 지원한다. 자바는 코드를 읽기 쉽도록 구조적 제어 흐름을 강요한다. goto 문을 지원하지 않지만, goto와 비슷한 기능을 하는 레이블 break 와 레이블 continue를 제공한다.
- C++은 자바에는 없는 저수준 기능을 제공한다. C++에서는, 포인터를 이용하면 저수준으로 운영 체제 컴포넌트에 쓰기 작업을 할 수 밖에 없는 경우 특정한 메모리 위치에서 데이터를 조작하는데 사용될 수 있다. 또한, 많은 C++ 컴파일러는 어셈블리어를 지원한다. 자바에서는, 그런 코드는 모두 외부 라이브러리에 배치해야하며 상당한 오버헤드를 가지는 Java Native Interface를 통해서만 접근이 가능하다.
[편집] 의미론(Semantics)
- C++은 기본 자료형 사이에 암시적 형변환을 허용하며, 사용자 정의 자료형에 대한 암시적 형변환도 가능하다. 자바에서는 기본 자료형 사이에 오직 넓은 범위로의 암시적 형변환을 허용하며, 다른 경우는 모두 cast를 통한 명시적 형변환만 가능하다.
- 이런 영향은 불린 자료형이 필요한 조건문(
if
,while
그리고for
의 탈출 조건)에도 나타난다. 자바는 int를 boolean으로 좁힐 수 있는 암시적 형변환이 안되기 때문에if(a = 5)
와 같은 코드는 컴파일 오류가 발생한다(앞의 코드는if(a == 5)
의 오타일 것이다). 요즘의 C++ 컴파일러는 대부분 경고를 발생한다.
- 이런 영향은 불린 자료형이 필요한 조건문(
- 함수에 인자를 전달할때, C++은 참조 호출과 값 호출 방식을 모두 지원한다. 자바에서는 인자는 항상 값 호출로 전달된다. [1]
- 자바의 내장 자료형은 가상 머신에 의해 결정된 일정한 크기와 범위를 가진다. 반면 C++의 내장 자료형은 최소한의 범위는 결정되어 있지만, 크기와 범위에 대한 정확한 표현은 작동하는 플랫폼의 지원에 따라 달라질 수 있다.
- 예를 들어, 자바의 문자형(char)은 16비트 유니코드 방식이고 문자열은 이런 문자형의 연속으로 이루어진다. C++은 반각 문자와 전각 문자를 모두 지원하지만 이런 문자형의 실제 크기는 사용되는 플랫폼에 종속적이다.
- 부동 소수점 연산에 있어서 C++은 플랫폼 종속적이다. 자바는 각기 다른 플랫폼에서 같은 결과를 보장한다. 하지만 수행 성능의 저하가 있을 수 있다.
- C++의 포인터는 메모리 주소 값으로 직접 조작할 수 있다. 자바에는 포인터가 없다 — 객체에 대한 참조와 배열 참조가 있지만, 메모리 주소에 대한 직접 접근은 허용되지 않는다. C++은 포인터에 대한 포인터를 만들 수도 있지만, 자바의 참조는 객체에 대한 접근 기능만 제공한다.
- C++의 포인터는 함수나 메서드를 가리킬 수 있다(함수 포인터나 펑터). 자바에서는 같은 메카니즘으로 객체에 대한 참조나 인터페이스에 대한 참조를 이용한다.
- C++은 RAII 자원관리를 사용 할 수 있다. 이 기술은 객체의 소멸에 맞추에 자동으로 메모리와 시스템 자원을 관리해준다. 자바는 가비지 콜렉션에 의해 자동 메모리 관리가 이루어진다. 하지만 메모리를 제외한 다른 시스템 자원(윈도우, 포트, 쓰레드)에 대해서는 사용이 끝나면 명시적 해제가 필요하다.
- C++은 프로그래머가 연산자 오버로딩을 할 수 있다. 자바는 문자열 연결에 쓰이는 "
+
"와 "+=
"만 오버로딩되어 있을 뿐이다. - 자바는 리플렉션과 동적 로딩을 지원하는 표준 API를 가지고 있다.
- 자바는 제네릭 프로그래밍을 지원하는 제네릭형을 가진다. C++은 템플릿을 가지고 있다. 템플릿은 더 광범위한 지원을 해준다.
- 자바와 C++ 모두 기본 자료형(원시 자료형이나 내장 자료형으로도 불림)과 사용자 정의 자료형(복합 형)를 구분한다. 자바에서는 기본 자료형은 값으로의 의미만 있고, 사용자 정의 자료형은 참조로의 의미만 있다. C++에서는 모든 자료형이 값으로의 의미를 가지지만, 어떠한 자료형에 대해서도 참조(포인터)를 만들 수 있으므로 객체를 참조를 통해 다루는 것이 가능하다.
- C++은 클래스의 다중 상속을 지원한다. 자바에서는 한 클래스는 오직 하나의 클래스만 상속할 수 있지만 복수의 인터페이스를 구현할 수 있다(즉, 형태에 대한 다중 상속은 지원하지만 구현에 대해서 단일 상속만 가능하다).
- 자바에서 인터페이스와 클래스는 명시적으로 구별되는 개념이다. C++에서 자바의 인터페이스와 같은 역할을 하도록 하려면 클래스에 다중 상속과 순수 가상 함수를 적용하면 된다.
- 자바는 언어와 표준 라이브러리 차원에서 멀티스레드를 지원한다. 자바의
synchronized
키워드는 간단하고 안전한 뮤텍스를 지원한다. 반면 C++은 멀티스레드에 대한 일반적인 메모리 모델이 없으므로 라이브러리를 사용하여 비슷한 일을 할 수 있다.
[편집] 자원 관리
- 자바는 자동 가비지 콜렉션을 지원한다. C++의 메모리 관리는 일반적으로 스마트 포인터에 의해 이루어진다. C++ 에서도 가비지 콜렉션을 사용할 수 있지만, 일반적으로 잘 사용하지 않는다.
- C++은 임의의 블락 크기로 메모리를 할당할 수 있다. 자바는 객체를 생성하는 방식으로만 메모리를 할당할 수 있다. (자바에서 프로그래머는 임의의 크기로 메모리를 할당하기 위해 바이트 배열을 생성하면 된다. 자바에서 배열도 객체이다.)
- 자바와 C++은 자원 관리에서 서로 다른 관습이 있다. 자바는 주로 가비지 콜렉션에 의지해 메모리의 재생만을 할 수 있어 다른 자원상에서는 최근의 장면이 될지 모른다. 하지만,C++은 주로 RAII (Resource Acquisition Is Initialization) 라는 관습에 의지한다. 이것은 두 언어간의 아래와 같은 여러가지 차이가 나타나고 있다.
- C++에서는 복합형의 객체를 스택영역에 할당하여 영역을 벗어나면 소멸되는 방식으로 사용하기도 한다. 자바에서는 복합형은 항상 힙영역에만 할당되고 가비지 콜렉터에 의해 수거된다.
- C++에는 소멸자가 있다. 자바에는 종결자(Finalizer)가 있다. 둘 다 객체가 소멸되기 직전에 호출되지만, 확연한 차이가 있다. C++의 객체 소멸자는 암시적으로(스택영역 변수의 경우) 또는 명시적으로 객체를 할당 해제 할때 실행된다. 소멸자는 객체가 할당 해제 될때 동기적으로 실행된다. 자바에서 객체의 할당 해제는 가비지 콜렉터에 의해 암시적으로 처리된다. 자바의 객체 종결자는 마지막으로 그 객체에 접근한 시기보다 조금 후에 비동기적으로 호출된다. 대부분의 경우 종결자는 필요가 없다. 종결자는 할당 해제되기전에 반드시 정리해야 할 자원(주로 JVM 외부 자원)이 있는 객체에 대해서만 필요할 뿐이다. 자바에서 안전한 동기적 자원 할당 해제를 하기 위해서는 명시적으로 try/finally를 사용하여야 한다.
- C++에는 길잃은 포인터(dangling pointer, 이미 소멸된 객체를 가리키고 있는 포인터)가 문제가 될 수 있다. 만약 길잃은 포인터를 사용하려 한다면 프로그램은 오류가 발생하게 된다. 자바의 가비지 콜렉터는 참조중인 객체는 소멸시키지 않으므로 문제가 발생하지 않는다.
- C++에서는 초기화하지 않고 객체를 생성할 수 있다(쓰레기 값을 가지고 있다). 자바는 기본 초기화가 강제로 수행된다(0 등으로 초기화 된다).
- C++에는 메모리에 할당하였지만 접근 가능한 참조가 없는 객체가 있을 수 있다. 이런 접근 불가능한 객체는 소멸될 수도 없으므로 메모리 누수를 일으킨다. 반면, 자바에서는 접근 불가능한 객체가 되기전까지 그 객체는 가비지 콜렉터에 의해 소멸되지 않는다. 자바의 가비지 콜렉션은 대부분의 메모리 누수를 예방하지만, 어떤 상황에서는 여전히 메모리 누수 문제가 발생할 수 있다.[2]
- 자바는 메모리가 아닌 다른 자원의 누수에 대해서는 C++에 비해 상대적으로 취약하다.
[편집] 라이브러리
- 자바에는 C++에 비해서 상당히 거대한 표준 라이브러리가 있다. C++의 표준 라이브러리는 문자열, 컨테이너, 입출력 스트림 등의 비교적 범용적인 요소들만 제공한다. 자바 SE 표준 라이브러리는 컴퓨터 네트워크, 그래픽 사용자 인터페이스, XML 처리, 로깅, 데이터베이스 접근, 암호학, 기타 요소들을 모두 제공한다. 이런 추가 기능은 C++에서는 각자 구현할 필요없이 제3자(써드 파티) 라이브러리를 주로 이용한다.
- C++은 C와 가장 하위 호환성이 좋은 언어이다. C 라이브러리에 있는 운영 체제의 API 같은 것을 C++에서는 직접 사용할 수 있다. 자바에서는 주로 플랫폼 종속적인 라이브러리로 가능한 여러 기능들을 크로스 플랫폼 환경에서 대부분 가능하도록 하는 풍부한 표준 라이브러리를 제공한다. 하지만 자바에서 운영 체제나 하드웨어 기능에 직접 접근하려면 Java Native Interface를 이용하여야만 한다.
[편집] 런타임
- C++은 보통 기계어로 직접 컴파일 되고, 운영 체제에 의해 실행된다. 자바는 보통 바이트코드로 컴파일 되고, 자바 가상 머신에 의해 인터프리터 방식으로 실행되거나 또는 JIT 컴파일러 방식으로 기계어로 컴파일후 실행된다. 이론상 동적 재컴파일은 두 언어 모두에 적용가능하며 특히 자바에 유용하다. 하지만 현재 동적 재컴파일을 거의 사용되지 않는다.
- C++의 다소 자유로운 표현력(배열 범위 검사 없음, 미사용 포인터, 자료형 변환) 덕분에 컴파일시에 실뢰성 있는 검사가 안되고 런타임에 오류가 날 위험이 있다. 관련 오류로는 버퍼 오버플로, 페이지 폴트, 세그먼테이션 폴트가 있다. 하지만 STL이 제공하는 고수준 추상 개념(벡터, 리스트, 맵)을 사용하면 오류를 피할 수 있다. 자바에서는 이런 오류는 아예 발생하지 않거나 자바 가상 머신에 적발되어 예외 처리 형태로 애플리케이션에게 보고 된다.
- 자바는 배열의 범위를 벋어난 접근에 대해 명확하게 배열의 경계 검사를 요구한다. 이는 불안정성을 줄이기는 하지만 일반적으로 실행 속도에 나쁜 영향을 준다. 일부 경우, 컴파일러의 분석으로 이런 문제는 모두 제거되어서 경계 검사가 불필요한 일이 되기도 한다. C++은 배열의 범위를 벋어난 접근에 대해 아무런 행동도 하지 않으므로 배열의 경계 검사는 하지 않는다. C++ 표준 라이브러리의 벡터 같은 콜렉션의 경우 선택적으로 경계 검사를 제공한다. 요약하자면, 자바 배열은 "항상 안전하고, 엄격하게 검사하고, 가능하면 빠르게" 이고, C++ 배열은 "항상 빠르게, 전혀 검사하지 않고, 잠재적 위험이 있는" 것이다.
[편집] 기타
번역중...
- Java and C++ use different techniques for splitting up code in multiple source files. Java uses a package system that dictates the file name and path for all program definitions. In Java, the compiler imports the executable class files. C++ uses a header file source code inclusion system for sharing declarations between source files. (See Comparison of imports and includes.)
- Compiled Java code files are generally smaller than code files in C++ as Java bytecode is usually more compact than native machine code [출처 필요] and Java programs are never statically linked.
- C++ compilation features an additional textual preprocessing phase, while Java does not. Thus some users add a preprocessing phase to their build process for better support of conditional compilation.
- In both languages, arrays have a fixed size. In Java, arrays are first-class objects, while in C++ they are merely a continuous run of their base objects, often referred to using a pointer to their first element and an optional length. In Java, arrays are bounds-checked and know their length, while in C++ you can treat any subsequence as an array in its own right. Both C++ and Java both provide container classes (std::vector and java.util.Vector respectively) which are resizable and store their size.
- Java's division and modulus operators are well defined to truncate to zero. C++ does not specify whether or not these operators truncate to zero or "truncate to -infinity". -3/2 will always be -1 in Java, but a C++ compiler may return either -1 or -2, depending on the platform. C99 defines division in the same fashion as Java. Both languages guarantee that
(a/b)*b + (a%b) == a
for all a and b (b != 0). The C++ version will sometimes be faster, as it is allowed to pick whichever truncation mode is native to the processor. - The sizes of integer types is defined in Java (int is 32-bit, long is 64-bit), while in C++ the size of integers and pointers is compiler and ABI dependent within given constraints. Thus, carefully-written C++ code can take advantage of the 64-bit processor's capabilities while still functioning properly on 32-bit processors. However, care must be taken to write the C++ program in a portable manner. In contrast, Java's fixed integer sizes mean that programmer error in this regard shouldn't be possible. This may incur a performance penalty since Java code cannot run using an arbitrary processor's word size.
[편집] 성능
번역중...
This section compares the relative computing performance of C++ and Java on common operating systems such as Windows and Linux.
Early versions of Java were significantly outperformed by statically compiled languages such as C++. This is because the program statements of these two closely related languages may compile to a few machine instructions with C++, while compiling into several byte codes involving several machine instructions each when interpreted by a Java JVM. For example:
Java/C++ statement | C++ generated code (x86) | Java generated byte code |
---|---|---|
vector[i]++; | mov edx,[ebp+4h] mov eax,[ebp+1Ch] |
aload_1 iload_2 |
While this may still be the case for embedded systems because of the requirement for a small footprint, advances in just in time (JIT) compiler technology for long-running server and desktop Java processes has closed the performance gap.
Several studies of mostly numerical benchmarks argue that Java should be faster than C++ for a number of reasons:[3][4]
- pointers make optimization difficult since they may point to arbitrary data or code
- newly allocated memory is close together because garbage collection compacts memory and allocations are thus sequential in memory; and hence more likely to be 'in the cache'
- run-time compilation can do a better job because it knows what processor it is running on and what code is running - the hot spots
Static compilers can be given hints, using command-line switches or pragmas, regarding the processor and other optimization options, but these choices may be wrong for where and when the code is actually run. Just-in-time compilation, used in recent Java virtual machines, allows optimization using current run-time measurements.
One comprehensive study of microbenchmarks shows quite a large variation in results but indicates that, in general, Java outperforms C++ in operations such as memory allocation and file I/O while C++ outperforms Java in arithmetic and trigonometric operations.[5] For numerical processing, Java has shown significant gains with each new version but still lags C++ and Fortran, in part due to the requirement for reproducibility of floating-point results across all platforms.[6]
[편집] 참고자료
- ↑ James Gosling, Bill Joy, Guy Steele, and Gilad Bracha, The Java language specification, third edition. Addison-Wesley, 2005. ISBN 0-321-24678-0 (see also online edition of the specification).
- ↑ "Java memory leaks -- Catch me if you can" by Satish Chandra Gupta, Rajeev Palanki, IBM DeveloperWorks, 16 Aug 2005
- ↑ "Performance of Java versus C++" by J.P. Lewis and Ulrich Neuman, USC, Jan. 2003 (updated 2004)
- ↑ "Java will be faster than C++" by Kirk Reinholtz, JPL, Apr 2001
- ↑ "Microbenchmarking C++, C# and Java" by Thomas Bruckschlegel, Dr. Dobbs, June 17, 2005
- ↑ "Java and Numerical Computing" by Ronald F. Boisvert, José Moreira, Michael Philippsen and Roldan Pozo, NIST, Dec 2000
[편집] 바깥고리
- How Java Differs from C — excerpt from Java in a Nutshell by David Flanagan
- Java vs. C++ resource management comparison - Comprehensive paper with examples
분류: 출처 없는 문장이 포함된 문서 | 프로그래밍 언어의 비교 | 자바 프로그래밍 언어 | C++