程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java與C++編程的不同

Java與C++編程的不同

編輯:關於JAVA

1.數據類型和變量

C++ 中的變量類型與Java很相似。像Java一樣,C++ 有int 和 double 類型。但是這些數字類型的取值范圍是依賴於機器的。比如在16位系統上,例如運行DOS 或Windows 3.x的PC機上,int 是雙字節(2-byte)的,取值范圍比Java的4-byte的int 要小很多。在這些機器上,如果 int 不夠用的話,你需要使用長整型long.

C++ 有 short 和 unsigned 類型來更有效的存儲數字。(我認為所謂有效是指更高的空間利用率。) 最好是盡量避免使用這些類型除非是空間利用的有效性對你的系統真的非常重要。

在C++中布爾型用 bool 表示,而不像在Java中用boolean.

C++ 中字符串類型用 string 表示。它與Java中的String 類型非常相似,但是,還是要逐一以下幾點不同之處:

1.C++ 字符串存儲ASCII 碼字符,而不是標准碼Unicode 字符

2.C++ 字符串是可以被修改的,而Java字符串的內容是不可修改的(immutable)。

3.取子字符串的操作在 C++ 中叫做substr,這個命令s.substr(i, n) 從字符串s中取得從位置 i 始長度為n的子字符串。

4.在C++中,你只能夠將字符串與其它字符串對象相串聯(concatenate),而不能夠與任意的對象相串聯。

5.C++中可以直接使用關系操作符 ==、 !=、 <、 <=、 >、 >= 來進行字符串比較,其中後面四個操作符是按字母順序進行比較的。 這比Java中使用函數equals和compareTo來比較要方便很多。

2.變量和常量

在C++中,本地變量的定義看起來與Java中相同,例如:

int n = 5;

實際上這正是C++和Java的一個重要不同之處。C++編譯器不對本地變量進行初始化檢驗,所以在C++中很容易忘記初始化一個變量,這種情況下,變量的值該變量所占內存區域中剛好當前存在隨機值。這顯然是很容易產生程序出錯的地方。

與Java一樣, C++中類可以有數據域和靜態變量。不同的是,C++中變量可以在函數甚至是類的外面定義,這些所謂的全局變量可以在程序的任何函數中被訪問,因而不易被很好的管理。所C++中應該盡量避免使用全局變量。

在C++中,常量可以在任何地方被定義(記得在Java中,常量必須是類的靜態數據static data)。 C++ 使用關鍵字 const 來定義常量,而Java中是 final。例如:

const int DAYS_PER_YEAR = 365;

3.類C++

中對類的定義與Java有些不同,這裡是一個例子:一個C++ 版本的Point 類:

class Point /* C++ */
{
public:
Point();
Point(double xval, double yval);
void move(double dx, double dy);
double getX() const;
double getY() const;
private:
double x;
double y;
};

這裡幾點重要的不同是:

1.C++的類定義中分為公共和私有部分,分別以關鍵字 public 和 private開始。而在Java中,每一個元素都必須標明 public 或 private;

2.C++中類的定義只包含函數的聲明,真正的實現另外單獨列出;

3.訪問函數(accessor methods)標有關鍵字 const ,表明這個函數不會改變本對象的元素值;

4.類定義的結尾處有分號。

類中函數的實現跟在類的定義之後。因為函數是在類外面定義的,所以每一個函數的名字前面要加類名稱作為前綴,並使用操作符雙冒號::來分割類的名稱和函數的名稱。不改變隱含參數值(即當前對象的值)的訪問函數用 const標明。如下所示是上面類定義中的函數的實現:

Point::Point() { x = 0; y = 0; }
void Point::move(double dx, double dy)
{
x = x + dx;
y = y + dy;
}
double Point::getX() const
{
return x;
}

4.對象

Java與C++最主要的不同在於對象變量的使用。在C++中,對象變量存儲的是真正的對象的值,而不是對象引用(reference)。注意在C++中構造一個對象的時候是不使用關鍵字new的,只需要在變量的名字後面直接賦予構造函數的參數就可以了,例如:

Point p(1,2); /* 構造對象 p */

如果不跟參數賦值,則使用默認構造函數,例如:

Time now; /* 默認使用構造函數 Time::Time() */

這一點與Java很不同。在Java中,這個命令僅僅生成一個沒有初始化的reference,而在C++中,它生成一個實際的對象。

當一個對象被賦給另一個對象變量的時候,實際的值將被拷貝。而在Java中,拷貝一個對象變量只不過是建立了另外一個指向對象的reference.拷貝一個C++的對象就像在Java中調用clone這個函數一樣,而修改拷貝的值不會改變原對象的值。例如:

Point q = p; /* 拷貝p到q */
q.move(1, 1); /* 移動q而p不動,即q的值變了,而p的不變*/

多數情況下,C++中這種對象直接對值操作的特性使用起來很方便,但是也有些時候不盡如人意:

1.當需要一個函數中修改一個對象的值,必須記住要使用按引用調用call by reference (參見下面函數部分);

2.兩個對象變量不能指向同一個對象實體。如果你要在C++中實現這種效果,必須使用指針pointer(參見下面指針部分);

3.一個對象變量只能存儲一種特定的類型的值,如果你想要使用一個變量來存儲不同子類的對象的值(多態ploymorphism),則需要使用指針;

4.如果你想在C++中使用一個變量來或者指向null或者指向一個實際的對象,則需要使用指針。

5.函數

在Java中,每一個函數必須或者是對象函數(instance method),或者是靜態函數(static function)或稱類函數。C++同樣支持對象函數和靜態函數(類函數),但同時C++也允許定義不屬於任何類的函數,這些函數叫做全局函數(global functions)。

特別的是,每一個C++ 程序都從一個叫做 main的全局函數開始執行:

int main()
  { ...
  }

還有另外一個格式的main函數可以用來捕捉命令行參數,類似於Java的main函數,但是它要求關於C格式的數組和字符串的知識,這裡就不介紹了。

按照習慣,通常如果程序執行成功, main 函數返回0,否則返回非零整數。

同Java一樣,函數參數是通過值傳遞的(passed by value)。在Java中,函數無論如何都是可以修改對象的值的。然而在C++中,因為對象直接存儲的是實際的值,而不是指向值的reference,也就是說傳入函數的是一個實際值的拷貝,因此也就無法修改原來對象的值。

所以,C++ 有兩種參數傳遞機制,同Java一樣的按值調用(call by value) ,以及按地址調用(call by reference)。當一個參數是按reference傳遞時,函數可以修改其原始值。Call by reference 的參數前面有一個地址號 & 跟在參數類型的後面,例如:

void raiseSalary(Employee& e, double by)
  { ...
  }

下面是一個典型的利用call by reference的函數,在Java中是無法實現這樣的功能的。

void swap(int& a, int& b)
  { int temp = a;
  a = b;
  b = temp;
  }

如果使用 swap(x, y)來調用這個函數,則reference參數 a 和 b 指向原實際參數x 和 y的位置,而不是它們的值的拷貝,因此這個函數可以實現實際交換這兩個參數的值。

在C++中,每當需要實現修改原參數的值時你就可以使用按地址調用call by reference。

6.向量Vector

C++ 的向量結構結合了Java中數組和向量兩者的優點。一個C++ 的向量可以方便的被訪問,其容量又可以動態的增長。如果 T 是任意類型,則 vector 是一個元素為 T 類型的動態數組。下面的語句

vector a;

產生一個初始為空的向量。而語句

vector a(100);

生成一個初始有100個元素的向量。你可以使用push_back 函數來添加元素:

a.push_back(n);

調用a.pop_back() 從a中取出最後一個元素(操作後這個元素被從a中刪掉), 使用函數size 可以得到當前a中的元素個數。

你還可以通過我們熟悉的[]操作符來訪問向量中元素,例如:

for (i = 0; i < a.size(); i++) {
  sum = sum + a[i];
  }

同Java中一樣,數組索引必須為 0 和 a.size() - 1之間的值。但是與Java不同的是,C++中沒有runtime的索引號合法性檢驗。試圖訪問非法的索引位置可能造成非常嚴重的出錯。

就像所有其它C++ 對象一樣,向量也是值。如果你將一個向量賦值給另外一個向量變量,所有的元素都會被拷貝過去。

vector b = a; /* 所有的元素都被拷貝了 */

對比Java中的情況,在Java中,一個數組變量是一個指向數組的reference.拷貝這個變量僅僅產生另外一個指向同一數組的reference,而不會拷貝每一個元素的值。

正因如此,如果一個C++函數要實現修改向量的值,必須使用reference參數:

void sort(vector& a)
   { ...
   }

7.輸入和輸出

在C++中,標准的輸入輸出流用對象cin 和cout 表示。我們使用<< 操作符寫輸出,例如:

cout << “Hello, World!”;

也可以連著輸出多項內容,例如:

cout << “The answer is ” << x << “\n”;

我們使用 >> 操作符來讀入一個數字或單詞,例如:

double x;
cout << “Please enter x: ”;
cin >> x;
string fname;
cout << “Please enter your first name: ”;
cin >> fname;

函數getline可以讀入整行的輸入,例如:

string inputLine;
getline(cin, inputLine);

如果到達輸入的結尾,或者一個數字無法被正確的讀入,這個流對象會被設置為failed 狀態,我們可以使用函數 fail 來檢驗這個狀態,例如:

int n;
cin >> n;
if (cin.fail()) cout << “Bad input”;

一旦一個流的狀態被設為failed,我們是很難重置它的狀態的,所以如果你的程序需要處理錯誤輸入的情況,應該使用函數getline 然後人工處理得到的輸入數據。

8.指針pointer

我們已經知道在C++中,對象變量直接存儲的是對象的值。這是與Java不同的,在Java中對象變量存儲的是一個地址,該地址指向對象值實際存儲的地方。有時在C++中也需要實現這樣的布置,這就用到了指針pointer.在C++中,一個指向對象的變量叫做指針。如果T是一種數據類型,則T* 是指向這種數據類型的指針。

就像Java中一樣,一個指針變量可以被初始化為空值NULL,另外一個指針變量的值,或者一個調用new生成的新對象:

Employee* p = NULL;
Employee* q = new Employee(“Hacker, Harry”, 35000);
Employee* r = q;

實際上在C++中還有第四種可能,那就是指針可以被初始化為另外一個對象的地址,這需要使用地址操作符&:

Employee boss(“Morris, Melinda”, 83000);
Employee* s = &boss;

這實際上並不是什麼好主意。保險的做法還是應該直接讓指針指向使用 new生成的新對象。

到目前為止,C++ 指針看起來非常像Java 的對象變量。然而,這裡有一個很重要的語法的不同。我們必須使用星號操作符 * 來訪問指針指向的對象。如果 p 是一個指向Employee對象的指針,則 *p 才代表了這個對象:

Employee* p = ...;
Employee boss = *p;

當我們需要執行對象的函數或訪問對象的一個數據域時,也需要使用 *p :

(*p)。setSalary(91000);

*p外面的括號是必需的,因為 .操作符比 * 操作符有更高的優先級。C的設計者覺得這種寫法很難看,所以他們提供了另外一種替代的寫法,使用 -> 操作符來實現 * 和 .操作符的組合功能。表達式:

p->setSalary(91000);

可以調用對象*p的函數setSalary .你可以簡單的記住 .操作符是在對象上使用的,-> 操作符是在指針上使用的。

如果你不初始化一個指針,或者如果一個指針為空值 NULL 或指向的對象不再存在,則在它上面使用 * 或 -> 操作符就會出錯。 不幸的是C++ runtime 系統並不檢查這個出錯。如果你范了這個錯誤,你的程序可能會行為古怪或死機。

而在Java中,這些錯誤是不會發生的。所有的reference都必須初始化,所有的對象只要仍有reference指向它就不會被從內存中清除,因此你也不會有一個指向已被刪除的對象的reference.Java的runtime系統會檢查reference是否為空,並在遇到空指針時拋出一個null pointer的例外(exception)。

C++和Java還有一個顯著的不同,就是Java 有垃圾回收功能,能夠自動回收被廢棄的對象。而在C++中,需要程序員自己管理內存分配回收。

C++中當對象變量超出范圍時可以自動被回收。但是使用new生成的對象必須用delete操作符手動刪除,例如:

Employee* p = new Employee(“Hacker, Harry”, 38000);
...
delete p; /* 不在需要這個對象 */

如果你忘記刪除一個對象,那麼你的程序有可能最終用光所有內存。這就是我們常說的內存洩漏 (memory leak)。更重要的是,如果你如果刪除了一個對象,然後又繼續使用它,你可能覆蓋不屬於你的數據。如果你剛巧覆蓋了用於處理內存回收的數據域,那麼內存分配機制就可能運轉失常而造成更嚴重的錯誤,而且很難診斷和修復。因此,在C++中最好盡量少用指針。

9.繼承

C++和Java中繼承的基本語法是很相似的。在C++中,使用 : public 代替Java中的extends 來表示繼承關系 .(C++ 也支持私有繼承的概念,但是不太有用。

默認情況下,C++中的函數不是動態綁定的。如果你需要某個函數實現動態綁定,需要使用virtual聲明它為虛函數,例如:

class Manager : public Employee
  {
  public:
  Manager(string name, double salary, string dept);
  virtual void print() const;
  private:
  string department;
  };

同Java一樣,構造函數中調用父類的構造函數有特殊的語法。 Java使用關鍵字 super.C++中必須在子類的構造函數體外調用父類的構造函數。下面是一個例子:

Manager::Manager(string name, double salary, string dept)
  : Employee(name, salary) /* 調用父類的構造函數 */
  { department = dept;
  }

Java 中在子類函數中調用父類的函數時也使用關鍵字super .而在C++中是使用父類的名稱加上操作符 ::表示,例如:

void Manager::print() const
  { Employee::print(); /* 調用父類的函數 */
  cout << department << “\n”;
  }

一個C++對象變量只能存儲特定類型的對象值。要想在C++中實現多態(polymorphism),必須使用指針。一個T*指針可以指向類型為T或T的任意子類的對象,例如:

Employee* e = new Manager(“Morris, Melinda”, 83000, “Finance”);

你可以將父類和不同子類的對象混合收集到一個元素均為指針的向量中,然後調用動態綁定的函數,如下所示:

vector staff;
  ...
  for (i = 0; i < staff.size(); i++)
  staff[i]->print();

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved