Jump to content

Comparison of Java and C++

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by CmdrRickHunter (talk | contribs) at 23:51, 6 July 2006 (Syntax: expounded if statments). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

This is a comparison of the Java programming language with the C++ programming language. While C++ and Java share many common traits, their differences can make a simple task extremely difficult if the wrong language is chosen. For example, Java does not work well when it is forced to work directly with hardware, and C++ does not work well when reflection is required. If features from both languages are required, a programmer can use JNI to bridge between them, but that is outside of the scope of this article.

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 on embedded systems. Java was designed to address several qualities not present in C++ at the language level: portable, robust, secure, multi-threaded and distributed. The syntax of Java was chosen to be familiar to C programmers, but direct compatibility with C was not maintained. Java also was specifically designed to be simpler than C++.

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

C++ Java
execution efficiency developer productivity
trusts the programmer protects the programmer
arbitrary memory access possible memory access only through objects
concise expression explicit operation
can arbitrarily override types type safety
procedural and object-oriented object-oriented
redefine operators meaning of operators immutable
very feature rich feature rich, and easy to use

These principles combined with C++'s C heritage are responsible for most concrete language differences between Java and C++.

Language features

Syntax

  • Java has simpler syntax than C++, although the addition of inner classes and generics has eroded the simplicity somewhat. Conversely, C++ has more powerful syntax than Java. In many cases, the differences enable C++ code to be syntactically concise where Java enforces explicitness.
    • Conditional expressions (if, while and the exit condition in for) in Java are type boolean; in C++ these are scalar expressions. C++ uses this to simplify the syntax for if statements regarding pointers -- if(ptrToObject) -- but this also opens the door for the typo if(a = 5) when if(a == 5) was desired. Java will catch this error at compile time.
  • 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 '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= annotherRectangle //ILLEGAL r = annotherRectangle; // 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 does not, but its labelled break provides some structured goto-like functionality. In fact, Java enforces structured control flow, with the goal of code being easier to understand.
  • Many C++ compilers support inline assembler. In Java, assembly code can only be accessed as libraries, through the Java Native Interface. However, there is significant overhead for each call.

Semantics

  • For passing parameters to functions, C++ supports both true pass-by-reference and pass-by-value. As in C, the programmer can simulate by-reference parameters with by-value parameters and indirection. In Java, all parameters are passed by value, but object (non-primitive) parameters are reference values, meaning indirection is built-in.
  • The semantics of C++ are more dependent on the host machine's platform:
    • The ranges of C++ fundamental types are platform dependent but subject to restrictions in the language standard. Java primitive types have fixed ranges.
    • The rounding and precision of floating point values and operations in C++ are platform dependent. Java provides a strict floating-point model that guarantees consistent results across platforms, though normally a more lenient mode of operation is used to allow optimal floating-point performance.
    • The encoding of string and character literals in C++ is platform dependent. The encoding of string and character literals in Java is fixed.
  • 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++ 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. C++ has templates.
  • 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). However, in C++ this distinction is far less extensive.
  • C++ supports multiple inheritance of arbitrary classes. Java supports multiple inheritance of types, but only single inheritance of implementation. In Java a class can derive from only one class, but a class can implement multiple interfaces.
  • 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. While mutex lock mechanisms are available through libraries in C++, the lack of language semantics makes writing thread safe code more difficult and error prone.

Memory management

  • Java has automatic garbage collection. Memory management in C++ is usually done by hand, or through smart pointers. The C++ standard permits garbage collection, but does not require it; garbage collection is rarely used in practice. When permitted to relocate objects, modern garbage collectors can improve overall application space and time efficiency over using explicit deallocation.
  • C++ can allocate arbitrary blocks of memory. Java only allocates memory through object instantiation. (Note that in Java, an array is an object. An arbitrary block of memory can be allocated by allocating an array of bytes.)
  • Java and C++ use different idioms for resource management. Java relies mainly on garbage collection, 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's 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 is performed 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 an object that is allocated, but unreachable. An unreachable object is one that has no reachable references to it. An unreachable object cannot be destructed (deallocated), and results in a memory leak. By contrast, in Java an object cannot be deallocated until it becomes unreachable. Still it's possible to have memory leaks in java, via cross-referencing, on most JVM implementations. Two unused object (not referenced anymore by the main application) could reference themselves so they are still marked as used and not garbage-collected. (Note: weak references are supported, which work with the Java garbage collector to allow for different strengths of reachability.)

Libraries

  • Java has a considerably larger standard library than C++. The C++ standard library only provides components that are relatively general purpose, such as strings, containers, and I/O streams. The Java standard library includes components for networking, graphical user interfaces, XML processing, logging, database access, cryptography, and many other areas. This additional functionality is available for C++ by (often free) third party libraries, but third party libraries do not provide the same ubiquitous cross-platform functionality as standard libraries.
  • C++ is mostly backward compatible with C, and C libraries (such as the APIs of most operating systems) are directly accessible from C++. In Java, the richer functionality of the standard library provides cross-platform access to many features typically available in platform-specific libraries. Direct access from Java to native operating system and hardware functions requires the use of the Java Native Interface.

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. Some JVMs employ dynamic recompilation, which can provide even greater optimizations than optimizations available to static compilers.
  • Due to the lack of constraints in the use of some C++ language features (e.g. unchecked array access, raw pointers), programming errors can lead to low-level buffer overflows, page faults, and segmentation faults. Many of these errors can be avoided, although usually not eliminated, by adopting good development practices or using the C++ Standard Template Library containers (like vector, list and map). 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.
  • In Java, bounds checking is implicitly performed for all array access operations. In C++, array access operations on native arrays are not bounds-checked, and bounds checking for random-access element access on standard library collections like std::vector and std::deque is optional.

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. 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 a textual preprocessing phase, while Java does not. Java supports many optimizations that mitigate the need for a preprocessor, but some users add a preprocessing phase to their build process for better support of conditional compilation.
  • In Java, because an array is an object, you can easily pass it to another method. In C++, because arrays are data stored in consecutive memory, to pass an array to a function, you must pass a pointer to the array to the function, and then increment the pointer as necessary. Also, in Java, if you don't know the number of elements in an array, you can easily figure it out by using the length method that the array inherits from the Object class (since, in Java, arrays are Objects).
  • Java's division and modulus operators are well defined to "truncate to zero." C++ does not specify whether or not your "truncate to zero" or "truncate to -infintiy". -3/2 will always be -1 in java, but a C++ compiler will either return -1 or -2, depending on the platform. C99 defines division in the same fashion as java. Both languages guarentee that (a/b)*b+a(%b)=a for all a and b (b != 0). The C++ version will be sometimes be faster, as it is allowed to pick whichever truncation mode is native to the processor.
  • The size of an integer is defined in Java (int is 32-bit, long is 64-bit), while C++ leaves it platform dependant. This means code written carefully in C++ to work on both 32-bit and 64-bit machines will be able to take advantage of the 64-bit processors capabilities while catering to the 32-bit processor when compiled for it. Java forces you to either use 64-bit constructs on the 32-bit platform(using long), which can run native on the 64-bit machine, or to use 32-bit constructs, and loose 64-bit capabilities. However, Java written without concern for a processor's word size will run on either machine exactly the same, while C++ code written without concern for a processor's word size often fails to function properly. There are also at least 3 different variants of 64-bit C++ types, adding to the confusion (sometimes int is 32-bit, sometimes its 64, depending on the OS).

See also

External references