Differences between Java and C++
Ease of use
Need for rules
Sandbox security model
This article intends to provide technical insights into
differences between the Java and C++ programming languages.
There's no claim of completeness.
Knowledge of either Java or C++ is assumed.
The status of this article is ongoing.
This article addresses mainly the
less the runtime environments (virtual machines, hosted, embedded),
and not the library frameworks.
Only typically Java is compiled to
byte code and run on virtual machine;
only typically C++ is used without garbage-collection.
The C++ programming language is far more complex
than the Java language.
Due to this, C++ coding is more error prone
than Java code.
This has impacts on
and feasibility of large projects
less memory models
- Java allocates all its objects on the heap
(all managed by the garbage collector);
C++ additionally offers stack based instantiation
(including temporary objects), and static instantiation.
Stack objects are automatically deleted (when they go out of scope),
so a programmer has to assure no references are kept further
(e.g. in a container, registry, etc.).
Instantiation order with static instantiation is difficult to predict,
and therefore error-prone, less portable, and restricted.
no temporary objects
- [Based on non-trivial rules] C++ language will chose
either a cast or temporary object
(including object construction)
to [implicitly] coerce one type into another,
sometimes leading to unwanted effects or unwanted overhead.
no copy constructor and assignment operator needed
- Due to Java's memory model,
no copy constructor and assignment operator are needed,
and therefore can't become a source of bugs.
no explicit cast code supported
- C++ increases the number of routes for type coercion
by allowing to defined explicit cast code.
no ambiguity between int, boolean, and null pointer
- Due to
both being distinct from
there's no ambiguity if used
e.g. as parameters
in overloaded methods3.
no default parameters
- As not supported, there can't be an ambiguity between methods
with default parameters and other overloaded methods.
no unsigned integers
- As unsigned integers
don't really buy anything (in C/C++ neither, decent casts can be used),
const not supported
- Object immutability is in Java at most considered
The more intuitive
allows to implement first-level constness
on variables and fields
(again being more intuitive than C++'s reference fields).
expression evaluation order
- Evaluation order within expression
is stricter defined in Java,
leading to more deterministic behavior,
and avoiding a specific source of problems.
C++ compiler however may allow options
to warn about undefined semantics outside of sequence points.
no macro pitfalls
- Macros offer call-by-name semantics
and therefore allow unwanted side effects,
e.g. with multiple evaluation (
or precedence issues
Ease of use
no splitting between declaration and definition
- As Java doesn't split the interface and its implementation
(in C++ into header files and implementation files),
there's less overhead with the duplication of
critical section handling built-in
- Support for critical section handling,
typically needed with multithreaded code,
is closely built into the Java language;
methods synchronize on their [
simply by specifying the
regions of code use a
- Java's garbage collection
largely avoids the need for
some useful interaction with the garbage collector
(however their use increases code complexity).)
Unreferenced/unreachable objects are not occurring in Java.
Garbage-collected environments allow
(immutable) copy-on-write data structures,
which are useful for lock-free (fast) implementations
of concurrent algorithms.
no destructor code needed
- Destructor code is not needed in Java,
mainly due to its garbage collection memory model.
prevents the types of memory leaks found in C++.
keeping backward compatibility
- If a class [during code changes] grows in data size,
the using C++ code has to be recompiled,
since it's the instantiator's task to allocate memory
(and thus needs knowledge about size),
which is not the case in Java;
it's easier to keep compatibility in Java.
no cross-compilation needed
- Since the compiled bytecode is hardware-platform independent,
there's no need for cross-compilation
or having access to different platforms.
- Java incorporates more keywords where
to enhance readability:
abstract, extends, implements, interface, super, null.
- Java explicitly distinguishes
between integers and boolean,
as well as between bytes and characters:
and defines the literals
Need for rules
Being more complex and less restricted,
C++ typically needs policies and coding rules,
whereas Java does so in a much minor extend.
Due to being optionally less dynamic, C++ is more optimizable
(assuming the now usual modus of compiling each Java class on its own
(to follow the model of loading each class on its own),
i.e. omitting global analysis and global optimization).
Some of C++'s optimizability arises from omitted method calls and dispatching,
some optimizations are possible by knowing more code context;
optimizability affects performance
and space requirements.
C++ allows more control over compile-time optimization,
whereas Java depends on the specific runtime optimization used,
e.g. with just-in-time optimizing virtual machines.
Just-in-time compilers may be able to consider the details
of CPU instruction sets (at runtime)
and therefore translate to more efficient native code.
In C++ such optimizations are often done by providing
many platform-specific dynamic libraries
(the decision which to load/use done at runtime);
however code layout has to be planned to isolate such parts
and compile with a set of different platform-specifying options.
Dynamic compilers might be better suited to consider
to rearrange code accordingly (similar to [lower level] branch prediction).
no inlining or macros
- Inlining code allows to consider it in a specific context,
to optimize specifically, over more code
(without generally breaking [object-oriented] encapsulation).
no template instantiation
- Template instantiation generates type specific code
that is more optimizable than its generic counterpart
(that merely does type checks only).
- Allows to omit dispatch calls and to inline specific code
(and hence to optimize over more code).
no on-stack instantiation
- Allows to omit memory management.
Just-in-time compilers may consider on-stack instantiation though.
no composite object
- Unlike with Java, C++ allows to directly compose objects,
which avoids indirection (via references),
and makes exact types known
(possibly further avoiding method dispatch indirection).
Optimization generally and inlining specially
make it harder to reverse-engineer binaries;
so implementation secrets are stronger protected in C++ than in Java.
These [language] safety issues
affect [program] reliability
(and the cost to make software work).
C++ programs crash
where Java issues useful diagnostic information
(stack traces of causing and detecting code).
Many of the aspects make
problem analysis harder in C++,
due to deferred problem detection.
Undetected error conditions,
especially with [user provided] data input,
cause security problems,
no uninitialized pointers and data
- Java implicitly initializes data fields
[if not done explicitly [by the programmer],
to useful defaults (null, false, 0, ...)],
and forces explicit initialization on local variables.
Though C++ compilers may take care on this
or issuing warnings.
no dangling/stale pointers
- Java's garbage collection prevents dangling references.
array bounds checks
- Boundary violation with arrays are checked at runtime,
leading to an
in error case.
Two issues make this detail very important:
[stack] data overwrites [with 'garbage'] in C++ get noticed [much] later,
making problem analysis [more] difficult;
and [stack] buffer overwrites are a major source of security problems.
null pointer handling
- In Java, dereferencing a null pointer generates
which may be reasonably caught.
As with [all] Java exceptions, a stack trace is included,
to help identifying culprit code locations,
and enhancing error diagnostics.
C++ code often just crashes dereferencing
a null pointer11.
type cast checks
- Java only allows casts between object types
if permitted by class hierarchy relationship,
i.e. with objects only the equivalent of C++'s
dynamic_cast is supported.
unchecked error conditions avoided through exceptions
- Since in Java error conditions are
[more consequently] propagated through exceptions,
they cannot be easily
Ignoring error conditions at their place of appearance
can cause [more] harm to the program's internal state
and, as problems are reacted on only later,
makes [deferred] problem analysis more difficult.
explicit boolean type
- In Java
boolean is an explicit type,
Also the constants
false are provided.
This feature disables integer assignments in conditionals
(though [optionally] also checked
with C++ compilers13).
link vs. runtime compatibility
- Class [linking vs. runtime] incompatibilities
are detected at their origin,
and can even be caught (and handled) at runtime.
C++ issues 'unpredictable' behavior
(e.g. in the case of a shorter or reorganized method dispatch table).
memory model strictly defined
- Java's memory model is defined to cover all
stack trace with exceptions
- Java exceptions include a stack trace,
to help identifying originating buggy code locations;
the given [call stack] context often provides hints
for problem solution/avoidance.
linked exception chain
- If a lower level exception triggers an upper level exception
(since it's caught and transformed to an application-level exception),
the originating exception is linked,
thus providing information needed
for analysis of all software layers.
- Java runtime environments provide
thread dumps with stack traces of all threads,
to allow analysis of such things as deadlock conditions or starvations;
these thread dumps include information
about monitors held or waited for.
VM runtime information
- Java runtime environments further may provide
information about memory use, garbage collection, locks.
C++ runtime environments are free to offer similar,
however likely not provided in many environments.
Sandbox security model
Besides the language safety aspects,
Java [typically] offers a sandbox model
of runtime program execution:
certain code may be restricted from using
certain parts of the APIs.
The model however adds complexity
(if used explicitly by the [application] programmer).
C++'s model makes the prevention of
[arbitrary/unallowed] memory accesses infeasible;
C++'s security typically is implemented by means
of crossing process/system boundaries
([Solaris] door calls, or system call interfaces).
- Permissions for
can be specified in a sufficiently fine-granular way,
and are enforced by the runtime environment.
E.g. [web] applets may not be allowed to read/write [local] files.
Code often is not allowed to change the classloader
(to not compromise the rest of the security).
- Java offers the treatment of
'trusted' [privileged] package namespaces.
These are enforced by the classloader.
- 'Trusted' types may be confined
modifier on classes and methods
(preventing further polymorphism),
to make references on the type
predictable/safe in use
byte code verifier
- The class loaders typically verify byte code
for violations that may affect security
or would lead to VM crashes.
Java implements metadata,
to support observing reflection (and introspection).
dynamic code invocation
- Dynamic invocation allows to dynamically bind code
e.g. application containers.
This allows for deployment of code
with less overhead than e.g. with
RMI or CORBA.
- Inspectable data objects
yield simple data interfaces.
Samples are Java beans.
Default serialization uses this feature too.
- The length of an array object is accessible through
making 'end-element' policies
and allowing for more safety
(bounds violations can be checked).
- With annotations, Java supports structured meta data,
e.g. meta information that helps ensure
C++ may do some (but not all)
of the policies via pragmas.
Java incorporates some design decisions
that make the language simpler
or more comfortable to use.
- Strict single inheritance is enforced in Java,
which makes the design clearer.
Instead of multiple inheritance the more controlled
(pure abstract class)
- All classes are single-rooted by
This enables such things as the use of mixed-type containers.
useful root class methods
- Methods, that are needed for the [mixed-type or not] containers,
(i.e. that are of importance to building data structures),
are predefined [for each class]:
Likewise, string representation is [usually] done via
no global data
- Global data (outside class blocks) is not supported.
This makes the interfaces less complex.
However, static class data in (possibly uninstantiable) classes
no operator overloading
- Overloaded operators, which may be hard or unintuitive to read,
are not supported in Java.
goto is not supported.
multilevel break and continue
- The control flow in nested loops is enhanced with multilevel
no reference parameters
- Java lacks reference parameters,
establishing the need for holder objects,
returning object arrays, or introducing helper objects,
or keeping objects mutable.
nested classes and inner classes
- Java allows to further partition namespace
and enhance encapsulation
private static [nested]
and eases accesses of outer context
- In-source code documentation comments are provided.
Documentation keywords are supported as well:
@author, @version, @since, @param, @see, etc.
It's however easy to use extractable documentation comments in C++ too.
portability to other [computer] platforms,
and to other programming languages.
sizes of the integer types defined
- The sizes of the integer types
byte, short, int and
are defined to be 1, 2, 4 and 8 bytes.
The choice of integer type doesn't need platform considerations.
byte order defined
- The well defined network byte order is used
to write primitive data types to file
no alignment and padding
- As [native] memory can't be directly written to file or network,
no portability problems with different alignments or paddings arise.
- Java provides
for [composed] data types (objects, classes),
also considering version compatibility issues.
- Serializable container classes
make it easy to ship complex data across platforms.
- Unicode is used as the character type and
as base for strings.
It supports a large set of scripts.
Within a software engineering point of view,
Java seems to be the more robust programming language
The language catches some of the ugly design and
implementation features that C++ offers.
The memory management based on garbage collection
makes code more robust and might allow faster development.
Concerning highly optimized code,
C++ may be the choice.
Neglecting (at the time unknown) pitfalls,
which are more prevalent in C++ than Java,
will make code buggier during maintenance phase.
Resources are always limited,
being used on the urgent projects only...
don't have required
available at all...
However there's still ambiguity between pointer types,
see e.g. Java's suboptimal interpretation of
Object constness/immutability rather being a policy
than a direct language construct;
also, C++ is not strict in considering constness physical (vs. conceptual).
C++ of course offers inlining
instead of the problematic macros
Due to Java's dispatch model and memory model,
private implementation details even generate less dependencies
than in C++17.
The [recent] additions of
allow more flexibility
(e.g. non-blocking atomic operations, fairness),
and are syntactically used the same way C++ uses synchronization.
It's wise to de-reference
internal data that is no longer needed
(e.g. unneeded elements
java.util.Vector's object array
holding the references18),
to avoid [transient] memory leaks.
Based on compiling settings.
Having data unconditionally initialized
will lead to more deterministic behavior,
which is interesting for problem analysis.
A core dump at least allows for
As C++ can [still] use C paradigms [too],
errors are often signalled in return values
instead of exceptions.
However, the [silly] C++ expression
likely still isn't caught...
(e.g. C string's NUL or C pointer array's NULL)
too allows for
efficient sub-array/sub-string implementations
int offset, count).
In fact, the native byte order is not
[and does not need to be] visible to the Java programmer.
Time and space inefficient.
In C++ holder [facade] objects are needed
to shield the implementation details.
Vector's allocated capacity
is often larger than its [externally visible] size.
The Java Language Specification,
James Gosling, Bill Joy, Guy Steele, Gilad Bracha,
3rd Ed. 2005,
The C++ Programming Language,
3rd Ed. 1997,
Java vs. C++, Java versus C++,
differences between Java and C++, differences between C++ and Java
Thu Feb 18 2010
(Thu Mar 27 1997)
back to the Java page
the Java f.a.q.