| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
C++ |
Java |
---|---|
// destructor ~MyObject() { delete field1; delete field3; } // pointer field adoption void setField1 (Foo* newValue) { delete field1; field1 = newValue; } // pointer field aliasing void setField2 (Foo* newValue) { field2 = newValue; } // pointer field assignment void setField3 (const Foo& newValue) { delete field3; field3 = NULL; aValue = new Foo(newValue); } |
// no destructor // field assignment void setField1 (Foo newValue) { field1 = newValue; } // pointer field aliasing void setField2 (Foo newValue) { field2 = newValue; } // field assignment void setField2 (Foo newValue) { aValue = newValue.clone(); } |
If the object is not going out of scope or going to be reset soon, then you should replace a deletion by setting to null. That allows the garbage collector to get rid of the object without waiting for it to go out of scope. For example:
C++ |
Java |
---|---|
// big block with lots of stuff { ... Foo x = new Foo(); ... delete x; ... } |
// no destructor { ... Foo x = new Foo(); ... x = null; ... } |
The only case you have to worry about is where your destructor must also
release system resources (such as open files), or perform some other global
action (such as removing a corresponding object from a global list). In
that case, you may need to put some of the guts of your destructor into
a finalize
method. Unfortunately, you can't control when this
method gets called very well, so you may instead have to add an explicit
release method, and call it in all the places where your object
was destroyed in C++.
In C++, you generally define a copy constructor and an assignment operator.
Both of these should be closely linked in the way they work. In Java, you
could replace them both by the use of clone
. However, to minimize
the changes to your C++ code on the calling side (especially for output
parameters), it is often easier to go ahead and write an assign
method.
An assign method may also be faster, since it avoids the cost of making a new object.
You must be careful when writing correct clone, equals, and hashCode operators--see Well-Mannered Objects for more information.
C++ |
Java |
---|---|
// defining Foo(const Foo& other) { field1 = other.field1; field2 = ::Copy(other.field2); } Foo& operator= (const Foo& other) { if (&other != this) { SuperOfFoo::operator=(other); field1 = other.field1; ::ReplaceByCopy (field2,other.field2); } return *this; } // using Foo a = Foo(c); a = b; void getStuff(Foo& foo, Bar& bar) { foo = otherFoo(); bar = otherBar(); } |
// defining public Object clone (Object other) { Foo result = (Foo) super.clone(); field2 = other.field2.clone(); return result; } public Foo assign (Foo other) { if (other != this) { super.assign(other); field1 = other.field1; field2 = other.field2.clone(); } return this; } // using Foo a = c.clone(); a = b.clone(); public void getStuff(Foo foo, Bar bar) { foo.assign(otherFoo()); bar.assign(otherBar()); } |
Double-colons occur in two places in C++: with
statics and with direct base class methods. In both cases, Java has a different
syntax, but there are few opportunities for error since the compiler will
catch most mistakes. All statics must be defined in a class, so you
have to move your "unclassy" static data or global functions into
an appropriate class, or make up a new class such as
Decolonization
Globals
.
Statics & Base Class Methods
C++
Java
// declaring
class Foo {
static Foo x;
void someMethod();
}
int myGlobalFunction() {...
static Foo y;
// using
a = Foo::x;
b = y;
c = myGlobalFunction();
// declaring
class Fii : Foo {
void someMethod() {
Foo::someMethod();
}
}
// declaring
class Foo {
static Foo x;
void someMethod();
}
class Globals {
static int myGlobalFunction() {...
static Foo y;
}
// using
a = Foo.x;
b = Globals.y;
c = Globals.myGlobalFunction();
// declaring
class Fii extends Foo {
void someMethod() {
super.someMethod();
}
}
In Java, above the immediate superclass, you can't call base class methods directly. Luckily, calling higher base classes is rarely done in C++, so you should have few instances of it. If you do run into a case like this, then you will have to introduce some artificial methods of the class you want to call.
Conditionals look very similar, except that Java
enforces the type boolean. If the condition is flagged as an error
by the compiler, then put it in parentheses, and add != 0.
It's
all conditional
Fixing Conditionals
C++
Java
if (x == 3) {}
if (x++) {}
if (x = y) {}
if (x == 3) {}
if ((x++) != 0) {}
if ((x = y) != 0) {}
Java has no #if or #ifdef. In many cases, these conditionals are not required since they are often used for marking machine-specific code, which is not a problem for Java. Generally, these macro conditionals can be replaced by use of a simple conditional, since Java optimizes away conditionals that evaluate to false at compile time.
C++ |
Java |
---|---|
#define DEBUG false #if DEBUG ... #endif |
class Globals { static final boolean DEBUG = false; } if (DEBUG) { ... } |
However, where you have commented out parts of a block or more than one method, there is just no good substitute for #ifdef in Java . Occasionally, /*...*/ will substitute; but you have to be careful of premature termination since these marks do not nest, and people often have these comment blocks at the front of each method. The last resort is to copy the commented-out material to another file to preserve it, and then to put a comment in pointing to that file.
As a side issue, there is one slight change you might have to make to for statements, since declarations inside a for statement are scoped slightly differently for older C++ compilers. If there are outside dependencies you might have to pull the declarations out to a higher level, as shown below. The compiler will warn you of these.
C++ |
Java |
---|---|
for (int i = 0; i < j; ++i) { x += i * i; } z = i; |
int i; for (i = 0; i < j; ++i) { x += i * i; } z = i; |
The Java primitives do not have signed and unsigned
variants. The char type is always Once you have removed signed, take a look
at the unsigned types. If you really need the range they provide,
then you will have to change them to the next higher type. If your C++ code was portable, you made few assumptions
about the sizes of The C and C++ languages officially say that bitwise
operations on signed integers are not portable. People do it anyway, assuming
that all machines are now two's-complement. Thankfully, Java officially
defines signed integers to be two's-complement, and bitwise operations
on them are reliably portable. Once you are done, drop the unsigned keywords.
A
sign from above
unsigned
, while
the others are signed
. First remove all signed
keywords. (Since the char type in Java is larger than char
in C++, removal of signed
doesn't make a difference. This discussion
presumes that you have already converted non-character C++ char
to be byte, as in To protect
the innocent).
int
since it could be 16, 32, or even 64
bits wide in C++, and the only one to watch for is unsigned short
.
Unsigned
C++
Java
// can be > 2,147,483,648
unsigned int x;
// otherwise
unsigned int x;
// can be > 32,767
unsigned short x;
// otherwise
unsigned short x;
signed int y;
z = x >> 1;
z = y >> 1;
long x;
int x;
int x;
short x;
int y;
z = x >>> 1;
z = y >> 1;
![]() |
If you are right-shifting an unsigned value, you will need to change to use >>>. Search for all instances of >>, and check the type of the arguments. Luckily, most code doesn't use this construct very much. Also, watch out for number-wrapping assumptions. For example, with a 16-bit C++ int, (x >> 8) gives the high byte. With a 32-bit Java int, you need to mask off possible garbage in the top bits with ((x >> 8) & 0xFF) to get the same result. |
Java does not have default parameters. If you really
want them, you have to use overloaded methods, one for each defaulted parameter.
(You can make them final, which with a good compiler will remove
the overhead of overload.) You may find it simpler to replace the call sites
instead, depending on your code.
Defaults
Default Parameters
C++
Java
int method(int x = 3,
char c = 'a');
public int method(int x, char c) {
...
}
public final int method(int x) {
return method(x,'a');
}
public final int method() {
return method(3,'a');
}
The exception mechanism works pretty much the same
in C++ and Java. The main differences are that--
Exceptional situations
Exceptions
C++
Java
void someMethod() {
try {
...
throw RangeException();
...
} catch (const RangeException& e) {
...
} catch (...) {
...
}
}
void otherMethod() {
...
throw BadNewsException();
...
}
void someMethod() {
try {
...
throw new RangeException();
...
} catch (RangeException e) {
...
} catch (Exception e) {
...
}
}
void otherMethod()
throws BadNewsException {
...
throw BadNewsException();
...
}
Unfortunately, Java has no enums. You will have to replace all of your enums by constants, and you will get no type-checking, and no overloading of methods based on the difference in types. Since you have no type-checking, callers are not prevented from mistakenly passing in some random integer instead of an enum value.
C++ |
Java |
---|---|
class Button { enum ButtonState {inactive, active, mixed, inherited}; ... void method1(ButtonState newState) { if (newState == inactive) {... } // usage x.setState(Button::inactive); |
class Button { // ButtonStates public static final byte INACTIVE = 0; public static final byte ACTIVE = 1; public static final byte MIXED = 2; public static final byte INHERITED = 3; ... void method1(byte newState) {... if (newState == INACTIVE) {... } // usage x.setState(Button.INACTIVE); |
C++ |
Java |
---|---|
class Button { enum ButtonState {inactive, active, mixed, inherited}; void method1(ButtonState newState) { if (newState == inactive) {... } |
class Button {... void method1(ButtonState newState) {... if (newState == ButtonState.INACTIVE) {... } final class ButtonState { public static final ButtonState INACTIVE = new ButtonState(0); public static final ButtonState ACTIVE = new ButtonState(1); public static final ButtonState MIXED = new ButtonState(2); public static final ButtonState INHERITED = new ButtonState(3); public int toInt() { return state; } private ButtonState(int state) { this.state = (byte) state; } private byte state; } |
For simple text-only applications, or for debugging, you will want to know how to deal with arguments and how to print from the console.
C++ |
Java |
---|---|
// fetching command-line arguments int main(int argc, char *args[]) { for (i = 1; i < argc; ++i) { doSomething(args[i]); } ... // C-style simple output printf("%s%i", "abc", 3); // C-style file output FILE* output = fopen("aFile","r"); if (output == NULL) { handleProblem(); } fprintf(output, "%s%i", "abc", 3); fclose(output); // C++-style simple output cout << "abc" << 3; |
// fetching command-line arguments public class MyApplication { public static void main(String args[]) { for (i = 0; i < args.length; ++i) { doSomething(args[i]); } ... // simple output System.out.print("abc" + 3); // file output try { PrintStream output = new PrintStream( new FileOutputStream("aFile")); output.print("abc" + 3); output.close(); } catch (java.io.IOException e) { handleProblem(); } // simple output System.out.print("abc" + 3); |
Unfortunately, an array doesn't have a meaningful toString, despite the fact that it would be easy to iterate over the contents. For debugging it is useful to code a replacement, as shown below:
// definition static String arrayToString(Object[] array) { StringBuffer result = new StringBuffer("<"); for (int i = 0; i < array.length; ++i) { if (i != 0) result.append(", "); result.append(array[i].toString()); } result.append('>'); return result.toString(); } // usage System.out.println(arrayToString(foo2)); |
This example also illustrates a common idiom: allocating a StringBuffer, successively appending to it, then returning its conversion to a String. This is much, much faster than using String concatenation, since the equivalent result += array[i].toString() constantly creates new objects.
JavaTM is a trademark of Sun Microsystems, Inc.
Other companies, products, and service names may be trademarks or service marks of others.
Copyright
Trademark
Java Education | Java Home |
![]() ![]() ![]() ![]() ![]() |