|HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | NEWSLETTER | CONTACT | | ||
Comparing Java and C++ - Whitepaper
Really Understanding Java
Myths and Truths Comparing C++ and Java
When I got first interested in Java I came across the following statement that George Paolini, Director of Corporate Marketing at JavaSoft, made in an interview that was published in JavaREPORT 5/98:
A: I think we’re winning them over now. On the programming language side, C++ programmers are probably the most adept at picking up Java. For them it’s basically about leaving out a lot of the trapdoors that were developed in C++ and unlearning a lot of bad habits.
It is true that Java shares many of the syntactical elements with C++, and that indeed makes C++ programmers feel familiar with Java almost immediately. Yet, when you dig deeper you discover that Java is a programming language with its own rules and idioms. Some idioms are common to all object oriented languages, some are similar to rules and idioms in C++, and some are completely Java specific. Just forgetting the complicated stuff from C++ does not imply that you've understood Java. Actually, being a C++ programmer lures you into certain traps. Some of these pitfalls are explored in the following.
Comparison of variables
In Java, the result of applying the operator == to two variables of non-primitive type is true , if the operand values are both null or if they both refer to the same object or array; otherwise, the result is false . Remember that in Java all non-primitive types are reference types, and the operator == checks the identity of both referred objects. In C++, in contrast, the operator == checks for equality of both operands.
The pitfall here is that the syntax of the comparison operator is exactly the same in both languages, yet the meaning is entirely different.
The precise meaning of equals() always depends on the specific class and its implementation. equals() must not mean "check for equality "; it can equally well mean anything else. For instance, all classes that do not override the equals() function exhibit the default behaviour inherited from class Object which is "check for identity ". Not even the JDK (the huge standard Java library) defines equals() consistently. Consider the following examples using the string and the string buffer classes from the JDK:
String s1 = new String(s);
String s2 = new String(s);
StringBuffer sb2 = new StringBuffer(s);
The bottom line is: forget value semantics all together. Don't assume that an operator, such as operator ==, that looks the same in C++ and Java has the same meaning in both languages. Don't believe that Java mechanisms, like the equal() function, would help retain value semantics. It is not consistently used. Lots of pitfalls here! But these are not the only ones.
Assignment. Assignment of variables comes with similar surprises, because assignment is value assignment in C++ and reference assignment in Java. The clone() function again looks like it would get us back value semantics, but by default it does a shallow copy. Again, it depends on each single class what clone() actually means and it is not used consistently.
Reference variables . The type system itself makes for surprises because Java reference variables look like C++ references, but behave like C++ pointers. For instance, in C++ a reference must be initialised to refer to an existing object, and only pointers can have a null value indicating that it does not refer to anything valid. In Java, reference variables are by default initialised with a null reference, which makes them behave pretty much like C++ pointers: you always have to check for the null value before any access.
Construction/destruction . Object construction works differently in both languages. So does object destruction, or its Java counterpart: finalization. It turns out that resource management cannot be reliably done in Java, because you do not know whether a finalizer is invoked at all, and if so when. Even means that were obviously designed to mitigate this problem, like runFinalizersOnExit() have a quite suspicious track record: It did not work in JDK 1.0, it was supposed to work in JDK 1.1, and meanwhile for platform two (JDK 1.2) it is deprecated, because they realised it cannot be reliably implemented.
Polymorphism is different because non-virtual in C++ does not mean final in Java. Function overloading works differently for member functions in an inheritance tree because of the different name lookup rules. The concept of constness in C++ is similar to the semantics of final in Java, yet different. Even exception handling is different in both languages.
So why did Mr. Paolini feel that C++ programmers just
have to leave out a lot of the trapdoors that were developed in C++? Java
opens quite a number of new trapdoors, especially to C++ programmers. But
then, Java would be boring without these challenges, right? ;-)
|© Copyright 1995-2003 by Angelika Langer. All Rights Reserved. URL: < http://www.AngelikaLanger.com/Articles/Papers/JavaGotchas/JavaProceedings.htm> last update: 23 Oct 2003|