从C++到java
C++和java都号称是面向对象的语言,虽然C++不完全算是。学习过C++如何快速对java有个大体的掌握,可以通过对比来进行了解。
首先还是来高大上一下,看看他们的使命:
· C++ 被设计成主要用在系统性应用程序设计上的语言,对C语言进行了扩展。对于C语言这个为运行效率设计的过程式程序设计语言, C++
特别加上了以下这些特性的支持:静态类型的面向对象程序设计的支持、异常处理、RAII以及泛型。另外它还加上了一个包含泛型容器和算法的C++库函数。
· Java
最开始是被设计用来支持网络计算。它依赖一个虚拟机来保证安全和可移植性。Java 包含一个可扩展的库用以提供一个完整的的下层平台的抽象。Java
是一种静态面向对象语言,它使用的语法类似C++,但与之不兼容。为了使更多的人到使用更易用的语言,它进行了全新的设计。
总体的了解一下java和C++在语义上的区别:
·C++ 允许给函数/方法的参数设置缺省值, Java 不提供这个特性. 但是方法重载可以达到同样的效果.
·C++ 里最小的编译单位是一个函数; Java 里最小的编译单位是一个类. 在 C++ 里, 函数可以被单独编译. 在 Java 里, 要编译和维护单独的方法需要把它们移到超类或子类或者使用其他的代码重构的技巧.
·C++ 允许基本类型之间的一些隐式的转换, 也允许程序员对于用户自定义类型相关的隐式转换规则. 在 Java 里, 只有基本类型之间变宽类型的转换可以是隐式的; 其余的转换需要显式的类型转换语法.
·这造成的一个后果是,虽然在 Java 和 C++ 里循环的条件(if, while 和 for 里的退出条件)预期的都是一个布尔表达式, 但 if(a = 5) 这样的代码在 Java 里会导致编译错误,因为没有从整型到布尔的隐式变窄转换. 如果代码是 if(a == 5) 的输错的情况那么是很方便发现这个错误的. 而目前的 C++ 编译器一般来说只会针对这种情况产生一个警告.
·对于传参数给函数的情况, C++ 支持引用传递和值传递. 在 Java 里, 参数总是值传递的. 但在 Java 里,所有的非基本类型的值都只是对于对象的引用 (用 C++ 的术语来说, 它们是智能指针). 对象在 Java 里不是作为值直接被使用的,只有对象的引用可以被直接操作; 习惯于将对象当做值直接使用的 C++ 开发者经常会把这个跟引用传递搞混.
·Java 内建的类型在字节宽度和取值范围上是被虚拟机定义好的; 在 C++ 里, 内建的类型有定义一个最小取值范围, 但是其他的部分(字节宽度)可以被映射成具体平台上支持的原生类型.
·举个例子, Java 字符是16位的Unicode字符, 字符串是由这样的字符组成的串行. C++ 提供窄和宽两种字符,但实际的字符宽度是和平台相关的, 视所用的字符集而定. 字符串可以由这两种字符中的一种组成.
·浮点数及其操作的精度和舍入方式在 C++ 里是平台相关的. Java 提供了一个可选的严格的浮点数模型,保证跨平台的一致性,不过可能会导致运行时效率比较差.
·在 C++ 里, 指针可以作为内存地址直接操作. Java 没有指针 — 它只有对象引用和数组引用,这两者都不允许直接用来访问内存地址. 在 C++ 里可以构造一个指向指针的指针,而 Java 的引用只能指向对象.
·在 C++ 里, 指针可以指向函数或者方法(函数指针). 在 Java 里的等价物是对象或者接口的引用.
·虽然有使用栈内存分配的对象, C++ 还是支持区域资源管理, 一个用来自动管理内存和其他系统资源的技术,此技术支持确定性对象销毁(deterministic object destruction). 不过,区域资源管理在 C++ 里是不被保证的;它只是一个设计模式,所以需要依赖程序员遵守相关的规则. Java 通过使用垃圾搜集来支持自动内存管理,但对于其他的系统资源(窗口,通讯端口,线程),如果垃圾搜集器无法决定它们是否不再被用到,那通常还是需要显式的释放的.
· C++ 的用户可自定义操作符重载的特性在 Java 里是不支持的. 唯一在 Java 里可以重载的操作符是 "+" 和 "+=" 操作符, 在字符串里重载为连接字符串.
·Java 的标准应用程序接口支持反射和动态加载任意代码.
·C++ 支持静态和动态的库连接.
·Java 支持泛型, 其主要目的是提供类型安全的容器. C++ 支持模板, 在泛型编程方面提供了更强的支持.
·Java 和 C++ 都对基本类型(也叫"内建"类型)和用户自定义类型(也叫"复合"类型). 在 Java 里, 基本类型只有值的语义,复合类型只有引用的语义. 在 C++ 里所有的值都有值语义,可以创建对于任何类型的引用,这样就允许通过引用语义来操作对象.
·C++ 支持任意类型的多重继承. 在 Java 里一个类只能从单个的类继承而来,但一个类可以实现多个的接口(换句话说,它支持类型的多重继承,但对于实现只能单继承(it supports multiple inheritance of types, but only single inheritance of implementation))。
·Java 对于类和接口是显式区分的. 在 C++ 里多重继承和纯虚函数使得定义出类似于 Java 的接口的类是可能的,不过会有少许区别.
·Java 在语言和标准库都对多线程有良好的支持. synchronized 这个 Java 的关键字为了支持多线程应用提供了简单而安全的互斥锁 ,但同步(synchronized)区只能用 LIFO 的顺序离开. Java 也为更高阶的多线程同步提供了健壮而复杂的库. 在 C++ 里没有专门为多线程定义的内存模型; 但第三方库提供了和 Java 差不多的功能; 不过这些 C++ 库之间差异较大,一致性不好.
·C++ 方法可以声明为虚函数, 虚函数是在运行期根据对象的类型才确定的. C++ 方法缺省情况下不是虚的. 在 Java 里, 方法缺省情况下是虚的, 但可以使用final关键字使之声明为非虚的.
·C++ 枚举属于基本类型,支持和其他整数类型之间的转换和比较. Java 枚举实际上是类的实例(它们从 java.lang.Enum<E> 扩展而来),象其他的类一样可以定义构造函数,数据成员及方法.
看完上面这些可能与实际的语言语法比较脱离,比如什么“反射”这种动态语言的特性在C++里面是不存在的,下面来看一下简单的总结:
main 函数
C++
int main( int argc, char* argv[])
{
printf( "Hello,
world" );
}
Java
// 每个函数都必须是一个类的一部分;当java
<class>运行是一个特定类的主函数会被调用
// (因此你可以让每个类都有一个main函数,这在写单元测试是很有用)
class
HelloWorld
{
public static void main(String
args[])
{
System.out.println( "Hello, World" );
}
}
类的声明
除了
Java 不要求用分号外几乎是相同的。
C++
class Bar
{};
Java
class Bar {}
方法声明
都相同的,
除了在Java,方法必须总是 某个类的一部分并且可能public/private/protected 作为修饰
构造函数和析构函数
构造函数都是相同的 (即类的名字),
Java没有准确意义上的的析构函数
静态成员函数和变量
方法声明是相同的, 但 Java 提供静态初始化块来来初始化静态变量 (不需要在源文件中声明):
class Foo
{
static private int x;
// 静态初始化块
{ x = 5; }
}对象的声明C++ // 在栈中
myClass x;
//或者在堆中
myClass *x = new myClass;
Java
// 总是在对堆中声明
myClass
x = new myClass();
继
承
C++
class Foo : public Bar
{ ...
};
Java
class Foo extends
Bar
{ ... }
访问级别 (abstraction
barriers)
C++
public:
void foo();
void
bar();
Java
public void
foo();
public void bar();
虚函数
C++
virtual
int foo(); // 或者非虚函数写作 int
foo();
Java
// 函数默认的就是虚函数;
用final关键字防止重载
int foo(); // 或者, final int foo();
内存管理
大体上是相同的--new 来分配, 但是 Java没有
delete,因为它有垃圾回收器。
NULL vs
null
C++
//
初始化一个指针为 NULL
int *x =
NULL;
Java
// 编译器将捕获使用未初始化的引用
//但是如果你因需要初始化一个引用而赋一个null,那么这是无效的
myClass x =
null;
布尔型
Java有一点罗嗦:
你必须写 boolean而不止是 bool.
C++
bool
foo;
Java
boolean foo;
常
量
C++
const int x = 7;
Java
final int x = 7; (final
关键字修饰类的方法的时候表示该方法不可被子类重新定义,因为在java中的方法都是默认virtual的)
抛异常
首先,Java在编译器强制抛异常—如果你的方法可能会抛异常你必需明确报告
C++
int
foo() throw (IOException)
Java
int foo() throws
IOException
数
组
C++
int x[10];
// 或
int *x
= new x[10];
// 使用 x,然后归还内存
delete[]
x;
Java
int[] x = new
int[10];
// 使用 x,
内存有垃圾回收器回收或
//或在程序生命周期尽头归还给系统
集合和迭代器
C++
迭代器是类的成员。范围的开始是<容器>.begin(), 结束是 <容器>.end()。 用++ 操作符递增, 用
*操作符访。
vector myVec;
for ( vector<int>::iterator itr =
myVec.begin();
itr != myVec.end();
++itr
)
{
cout <<
*itr;
}
Java
迭代器只是一个接口。
范围的开始是 <集合>.iterator,你必须用itr.hasNext()来查看是否到达集合尾。
使用itr.next()(是在C++中使用操作符++ 和*操作的结合)来获得下一个元素。
ArrayList myArrayList =
new ArrayList();
Iterator itr = myArrayList.iterator();
while (
itr.hasNext() )
{
System.out.println( itr.next() );
}
// 或, 在Java 5中
ArrayList myArrayList = new
ArrayList();
for( Object o : myArrayList ) {
System.out.println( o
);
}
抽象类
C++
// 只需要包含一个纯虚函数
class Bar { public: virtual void foo() = 0; };
Java
// 语法上允许显示的声明!
abstract class Bar { public abstract void foo(); }
// 或者你也可以声明一个接口
interface Bar { public void foo(); }
// 然后让一个类继承这个接口:
class Chocolate implements Bar
{
public void foo() { /* do something */ }
}
引用 vs 指针
C++
//引用不可改变,通过使用指针来获得更多的灵活性
int bar = 7, qux = 6;
int& foo = bar;
Java
// 引用是可变的,仅存储对象地址;
//没有指针类型
myClass x;
x.foo(); // error, x is a null ``pointer‘‘
// 注意你要总是用 . 来访问域,也就是说不会出现 ->
注 释
两种语言是一样的 (// 和 /* */ 可以用)