Comparison of Java and C++

From Wikipedia, the free encyclopedia

The neutrality or factuality of this article or section may be compromised by weasel words.
You can help Wikipedia by improving weasel-worded statements
.
This article is part of
the Programming Language Comparison
series.
General Comparison
Basic Syntax
String Operations
String Functions

Evaluation strategy
List of "hello world" programs

Compatibility of C and C++
Comparison of C and Pascal
Comparison of C++ and Java
Comparison of C# and Java
Comparison of C# and Visual Basic .NET


This is a comparison of the Java programming language with the C++ programming language.

Contents

[edit] Design aims

The differences between the C++ and Java programming languages can be traced to their heritage.

  • Java was created initially to support network computing. It relies on a virtual machine to be secure and highly portable. It is bundled with an extensive library designed to provide a complete abstraction of the underlying platform. Java is a statically typed object-oriented language that uses a syntax similar to C, but is not compatible with it. It was designed from scratch, with the goal of being easy to use and accessible to a wider audience.

The different goals in the development of C++ and Java resulted in different principles and design tradeoffs between the languages.

C++ Java
backwards compatible with C source code incompatible with other languages
allows direct calls to native system libraries calling native system libraries is difficult
exposes low-level system facilities runs in a protected virtual machine
no automated bounds checking provides pervasive memory protection
support native unsigned arithematic no native support for unsigned arithematic
value-based semantics and explicit pointers reference semantics for user-defined objects
explicit memory management automatic garbage collection
allows explicitly overriding types type safety
Supports procedural, object-oriented, functional and generic programming paradigms object-oriented, with some support for generic programming
Standard C++ library has a decent scope (Language support, Diagnostics, General Utilities, Strings, Locales, Containers, Algorithms, Iterators, Numerics, Input/Output and Standard C Library. Platform specific libraries differ for threads, Network I/O and GUI Programming) Extensive language-specific library (also allows GUI programming, networking, etc)
operator overloading meaning of operators is immutable

Based on these differences, C++ can be described as a powerful but complex language, with a bias for performance-oriented applications and libraries. The Java language and libraries are probably easier to learn, but does not always provide full access to the features and performance of the platform that the software runs on.

[edit] Language features

[edit] Syntax

  • Java syntax has a context-free grammar which can be parsed by a simple LALR parser. Parsing C++ is somewhat more complicated; for example, Foo<1>(3); is a sequence of comparisons if Foo is a variable, but it creates an object if Foo is the name of a class template.
  • C++ allows namespace level constants, variables, and functions. All such Java declarations must be inside a class or interface.
  • const in C++ indicates data to be conceptually 'read-only,' and is applied to types. final in Java indicates that the variable is not to be reassigned. For basic types such as const int vs final int these are identical, but for complex classes, they are different
C++ Java
const Rectangle r; final Rectangle r = new Rectangle();
r= anotherRectangle; //ILLEGAL r = anotherRectangle; // ILLEGAL
r.x = 5; // ILLEGAL, r is a const Rectangle r.x = 5; // LEGAL, r still refers to the same rectangle
  • C++ supports goto statements; Java enforces structured control flow, and relies on labelled break and labelled continue statements to provide some goto-like functionality.
  • C++ provides low-level features which Java lacks. In C++, pointers can be used to manipulate specific memory locations, a task necessary for writing low-level operating system components. Similarly, many C++ compilers support inline assembler. In Java, such code has to reside in external libraries, and can only be accessed through the Java Native Interface with a significant overhead for each call.

[edit] Semantics

  • C++ allows a range of implicit conversions between native types, and also allows the programmer to define implicit conversions involving user-defined types. In Java, only widening conversions between native types are implicit; other conversions require explicit cast syntax.
    • A consequence of this is that although loop conditions (if, while and the exit condition in for) in Java and C++ both expect a boolean expression, code such as if(a = 5) will cause a compile error in Java because there is no implicit narrowing conversion from int to boolean. This is handy if the code was a typo for if(a == 5). Yet current C++ compilers usually generate a warning when such an assignment is performed within a conditional expression.
  • For passing parameters to functions, C++ supports both true pass-by-reference and pass-by-value. In Java, all parameters are passed using pass-by-value.
  • Java built-in types are of a specified size and range defined by the virtual machine; In C++, a minimal range of values is defined for built-in types, but the exact representation (number of bits) can be mapped to whatever native types are supported on a given platform.
    • For instance, Java characters are 16-bit Unicode characters, and strings are composed of a sequence of such characters. C++ offers both narrow and wide characters, but the actual size of each is platform dependent, as is the character set used. Strings can be formed from either type.
  • The rounding and precision of floating point values and operations in C++ is platform dependent. By default, Java provides a strict floating-point model that guarantees consistent results across platforms, though possibly at the cost of slower run-time performance.
  • In C++, pointers can be manipulated directly as memory address values. Java does not have pointers — it only has object references and array references, neither of which allow direct access to memory addresses. In C++ one can construct pointers to pointers, while Java references only access objects.
  • In C++ pointers can point to functions or methods (function pointers or functors). The equivalent mechanism in Java uses object or interface references.
  • C++ supports scoped resource management, a technique used to automatically manage memory and other system resources that supports deterministic object destruction. Java supports automatic memory management using garbage collection, but other system resources (windows, communication ports, threads) often have to be explicitly released.
  • C++ features programmer-defined operator overloading. The only overloaded operators in Java are the "+" and "+=" operators, which concatenate strings as well as performing addition.
  • Java features standard API support for reflection and dynamic loading of arbitrary new code.
  • Java has generics, whose main purpose is to provide type-safe containers. C++ has templates, which provide more extensive support for generic programming.
  • Both Java and C++ distinguish between native types (these are also known as "fundamental" or "built-in" types) and user-defined types (these are also known as "compound" types). In Java, native types have value semantics only, and compound types have reference semantics only. In C++ all types have value semantics, but a reference can be created to any object, which will allow the object to be manipulated via reference semantics.
  • C++ supports multiple inheritance of arbitrary classes. In Java a class can derive from only one class, but a class can implement multiple interfaces (in other words, it supports multiple inheritance of types, but only single inheritance of implementation).
  • Java explicitly distinguishes between interfaces and classes. In C++ multiple inheritance and pure virtual functions makes it possible to define classes that function just as Java interfaces do.
  • Java has both language and standard library support for multi-threading. The synchronized keyword in Java provides simple and secure mutex locks to support multi-threaded applications, though synchronized sections have to be left in LIFO order. While much more flexible mutex lock mechanisms are available through libraries in C++, there is currently no defined memory model for multi-threading.

[edit] Resource management

  • Java requires automatic garbage collection. Memory management in C++ is usually done through smart pointers. The C++ standard permits garbage collection, but does not require it; garbage collection is rarely used in practice.
  • C++ can allocate arbitrary blocks of memory. Java only allocates memory through object instantiation. (Note that in Java, the programmer can simulate allocation of arbitrary memory blocks by creating an array of bytes. Still, Java arrays are objects.)
  • Java and C++ use different idioms for resource management. Java relies mainly on garbage collection, which can only reclaim memory and may be a last shot at other resources, while C++ relies mainly on the RAII (Resource Acquisition Is Initialization) idiom. This is reflected in several differences between the two languages:
    • In C++ it is common to allocate objects of compound types as local stack-bound variables which are destructed when they go out of scope. In Java compound types are always allocated on the heap and collected by the garbage collector (except in virtual machines that use escape analysis to convert heap allocations to stack allocations).
    • C++ has destructors, while Java has finalizers. Both are invoked prior to an object's deallocation, but they differ significantly. A C++ object's destructor must be implicitly (in the case of stack-bound variables) or explicitly invoked to deallocate the object. The destructor executes synchronously at the point in the program at which the object is deallocated. Synchronous, coordinated uninitialization and deallocation in C++ thus satisfy the RAII idiom. In Java, object deallocation is implicitly handled by the garbage collector. A Java object's finalizer is invoked asynchronously some time after it has been accessed for the last time and before it is actually deallocated, which may never happen. Very few objects require finalizers; a finalizer is only required by objects that must guarantee some clean up of the object state prior to deallocation—typically releasing resources external to the JVM. In Java safe synchronous deallocation of resources has to be performed explicitly using the try/finally construct.
    • In C++ it is possible to have a dangling pointer – a reference to an object that has been destructed; attempting to use a dangling pointer typically results in program failure. In Java, the garbage collector won't destruct a referenced object.
    • In C++ it is possible to have uninitialized primitive objects, Java enforces default initialization.
    • In C++ it is possible to have an object that is allocated, but has no reachable reference to it. Such an unreachable object cannot be destructed (deallocated), and results in a memory leak. By contrast, in Java an object will not be deallocated by the garbage collector until it becomes unreachable (by the user program). (Note: weak references are supported, which work with the Java garbage collector to allow for different strengths of reachability.) Garbage collection in Java prevents many memory leaks, but leaks are still possible under some circumstances.[citation needed]
    • Java can easily leak non-memory resources, while idiomatic C++ makes that much harder.

[edit] Libraries

[edit] Runtime

  • C++ is normally compiled directly to machine code which is then executed directly by the operating system. Java is normally compiled to byte-code which the Java virtual machine (JVM) then either interprets or JIT compiles to machine code and then executes. In theory, dynamic recompilation can be used for either language, particularly Java, but at present, both languages are rarely, if ever dynamically recompiled.
  • Due to its unconstrained expressiveness, some C++ language features (e.g. unchecked array access, raw pointers, type punning) cannot be reliably checked at compile-time or without undue overhead at run-time. Related programming errors can lead to low-level buffer overflows, page faults, and segmentation faults. The Standard Template Library, however, provides higher-level abstractions (like vector, list and map) to help avoid such errors. In Java, such errors either simply cannot occur or are detected by the JVM and reported to the application in the form of an exception.
  • The Java language requires specific behavior in the case of an out-of-bounds array access, which generally requires bounds checking of array accesses. This eliminates a possible source of instability but usually at the cost of slowing down execution. In some cases, compiler analyses can prove a bounds check unnecessary and eliminate it. C++ has no required behavior for out-of-bounds access of native arrays, thus requiring no bounds checking for native arrays. C++ standard library collections like std::vector, however, offer optional bounds checking. In summary, Java arrays are "always safe; severely constrained; possibly fast" while C++ native arrays are "always fast; completely unconstrained ; potentially unsafe."

[edit] Miscellaneous

  • 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++. First, Java bytecode is usually more compact than native machine code[citation needed]. Second, templates and macros in C++, including those in the standard library, can result in duplication of similar code after compilation. Third, dynamic linking with standard libraries eliminates binding the libraries at compile time.
  • 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-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, C++ programs written without concern for a processor's word size may fail to function properly with some compilers.[citation needed] In contrast, Java's fixed integer sizes mean that programmers need not concern themselves with varying integer sizes, and programs will run exactly the same[citation needed]. This may incur a performance penalty since Java code cannot run using an arbitrary processor's word size.

[edit] Performance

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 Java generated byte code
vector[i]++; mov edx,[ebp+4h]

mov eax,[ebp+1Ch]
inc dword ptr [edx+eax*4]

aload_1

iload_2
dup2
iaload
iconst_1
iadd
iastore

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:[1][2]

  • 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. JIT technology has achieved the next level in compiler evolution; from hints and directives, through optimization based on historic measurement, to 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.[3] 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.[4]

[edit] References

  1. ^ "Performance of Java versus C++" by J.P. Lewis and Ulrich Neuman, USC, Jan. 2003 (updated 2004)
  2. ^ "Java will be faster than C++" by Kirk Reinholtz, JPL, Apr 2001
  3. ^ "Microbenchmarking C++, C# and Java" by Thomas Bruckschlegel, Dr. Dobbs, June 17, 2005
  4. ^ "Java and Numerical Computing" by Ronald F. Boisvert, José Moreira, Michael Philippsen and Roldan Pozo, NIST, Dec 2000

[edit] See also

[edit] External references

In other languages