-
C++與Java異同
1、指針★★★★★
C C++中的指針,提供了很大的靈活性,但是靈活也帶來了危險,對指針操作的不當容易造成內存洩漏或是空懸指針等問題。
Java取消了指標。但實際上,java中聲明的所有引用資料類型的名稱,可以理解為就是一個指標。這個名稱儲存在堆疊記憶體上,指向對記憶體上使用new開闢的空間。
如:
int[] array = new int[10]
整數陣列名稱array在堆疊記憶體上,在堆疊記憶體上開闢了10*4位元組的空間,用array指向該區塊記憶體。
可以把array理解為指針,裡面存放的位址就是new出來的空間。
如:
class Person{
……
}
Person p = new Person() ;
物件名p開闢在棧內存,用new為對像在堆內存開闢空間,對象名p指向該堆內存。
但實際上呢,該名稱並不像C++中的指針,特別是在進行參數傳遞的時候。
java已經宣告:參數傳遞都是值傳遞。
但是當引用資料型別作為函數參數的時候,把一個已宣告的物件p1傳進來的時候,其實是產生了一個該物件的副本p2,這個p2指向p1,所以透過p2呼叫p1的成員時,可以完成修改,等函數呼叫結束,保留修改。如:
class Person{
public String name ;
public int age ;
public Person(String name ,int age){
this.name = name ;
this.age = age ;
}
}
public class Test{
public static void main(String[] args){
Person p = new Person("張三" , 10) ;
System.out.println("修改前-->姓名:"+ p.name+",年齡:"+p.age) ;
changePro(p) ; //物件p傳進來,這時產生p的一個副本,假設是p1,它指向p。 //透過這個副本p1,可以呼叫p的成員。
System.out.println("修改後-->姓名:"+ p.name+",年齡:"+p.age) ;
}
public static void changePro(Person p){ //透過副本可以呼叫原始物件的成員
p.name = "李四" ;
p.age = 30 ;
}
}
結果:
修改前-->姓名:張三,年齡:10
修改後-->姓名:李四,年齡:30
但當你把p1傳進來之後,產生副本p2,然後試圖透過p2來改變p1的指向,顯然是不可能的,這時改變的只是p2的指向,函數呼叫結束之後,p1的指向不變。如:
class Person{
public String name ;
public int age ;
public Person(String name ,int age){
this.name = name ;
this.age = age ;
}
}
public class Test{
public static void main(String[] args){
Person p = new Person("張三" , 10) ;
System.out.println("修改前-->姓名:"+ p.name+",年齡:"+p.age) ;
changeObj(p) ; //物件p傳進來,這是產生p的副本,假設是p1,它指向p。 //在函數中,改變的只是這個副本的指向。
System.out.println("修改後-->姓名:"+ p.name+",年齡:"+p.age) ;
}
public static Person newP = new Person("李四", 30) ;
public static void changeObj(Person p){
p = newP ; //企圖改變指向,實際改變的是副本的指向,
//函數結束後,原始物件的指向不會改變
}
}
結果:
修改前-->姓名:張三,年齡:10
修改後-->姓名:張三,年齡:10
2、記憶體動態分配
在C++中使用new和delete進行記憶體的動態分配和回收,new則是在堆記憶體上開闢空間,記憶體使用完畢之後,必須手動使用delete來回收。
Java中只要是宣告了引用資料型,在使用之前,就必須先使用new進行記憶體空間的開啟。但是在對象消亡之後,不用手工的進行記憶體回收。 Java自有的記憶體回收機制會自動回收垃圾對象(所謂垃圾對象,是指先前開闢的對象內存,不再被棧內存所引用了)。當然也可以透過System.gc()方法進行手工的回收。
3、析構函數
C++析構函式(無參,無回傳值)的作用是釋放à建構函式中動態分配的記憶體空間,也就是呼叫(此呼叫可以透過物件.析構函式調用,也可以等物件生存期結束時系統自動調用)析構函數。
Java中沒有析構函數,透過垃圾回收機制,自動回收垃圾物件。不過可以透過覆寫Object類別中的fanalize()方法,實現與C++中析構函數一樣的效果,當手動或自動銷毀物件時,會自動呼叫fanalize()方法。
4.空類中的內容
C++的空類別一定還有4個函數:預設建構函數,預設析構函數,預設拷貝建構函數,
Java的空類別中有:預設建構函數,從Object類別繼承來的方法,如
類別中預設屬性C++類別中的成員存取權限三種:public>protected>private。不聲明的話,預設為private權限。
Java類別中的成員存取權四種:public>protected>defalt>private。預設是default權限。
5.類別中成員函數的實現
C++中是習慣在. h頭檔的類別中宣告函數;在類別外的. cpp檔中實作函數,要#include頭檔。
如:
//demo.h
Class Person{
Public:
Void fun() ; //類別中聲明
}
//demo.cpp
#include “demo.h”
Void Person ::fun(){ //類別外實現
。 。 。 。 //實作體
}
Java是類別中宣告+實作方法。如果不在類別中實現,再加上abstract關鍵字就是抽象方法了。
如:
class Person{
Public void fun(){//類別中宣告+實現
。 。 。 。 //實作體
}
}
6、物件的實例化
class Person{
private :
int age ;
public :
Person(){}
Person(int a){
age = a ;
}
void fun(){….}
}
。 。 。 。 //主函數開始
Person p1 ; //呼叫的是無參的建構函數
Person p2(18) ; //呼叫帶參建構子
p1.fun() ; //呼叫成員函數
p2.fun() ;
java中實例化對象,必須使用new關鍵字。
class Person{
private String name ;
private int age ;
public Person(){}
public Person(String name, int age){
this.name = name ;
this.age = age ;
}
public void fun() {…..}
}
。 。 。 。 。 //主函數開始
Person p1 = null ;
p1 = new Person() ; //必須使用new關鍵字開啟記憶體空間,呼叫無參構造。
Person p2 = new Person(“張三”, 18) ; //呼叫帶參構造。
p1.fun() ; //呼叫方法
p2.fun() ;
7、This關鍵字
C++中叫this指針,實例化一個物件時,會預設產生一個this指標指向這個對象,作用是編譯器用來區別同一類的不同對象。即當對象.成員函數時,透過this指標知道是哪個對象,呼叫成員函數來操作該對象的成員屬性。
Java中this有3個用途:
1、表示本類中的屬性或方法。如this.方法,this.屬性。
2、表示當前對象。
3、呼叫本類別的建構方法。如this(),this(參數1,參數2.。。。)。
【其中用途1、2的作用類似C++中的this指標。 】
8、對象成員的調用
C++透過物件.成員函數,或是類別指標->成員函數來呼叫。
Java中只能透過物件.成員函數呼叫。
二者中Static屬性的成員,可以直接透過類別名稱.成員函數直接呼叫。
9.子類別-->父類別,建構子的傳參共同點:子類別中的建構子如果不明確指出呼叫父類別的哪個建構子時,系統預設去呼叫父類別的無參建構子。同時,如果父類別中自己定義了帶參的建構函數,最好再定義一個無參的建構函數。
class Person{
private :
int age ;
public :
Person(){}
Person(int a){
age = a ;
}
}
class Student :public Person{
private :
int score ;
public :
Student(int a, int s) :Person(a){ //傳遞給父類別建構子
score = s ;
}
}
class Person{
private String name ;
private int age ;
public Person(){}
public Person(String name, int age){
this.name = name ;
this.age = age ;
}
}
class Student extends Person{
private int score ;
public Student(String name, int age, int score){
super(name,age) ; //傳遞
this.score = score ;
}
}
10.多態性
C++中的多態性必須靠【虛函數或純虛函數+子類別對虛函數或純虛函數的覆蓋】來實現。
虛函數用virtual聲明,
如:
virtual void fun() ;//類別內聲明
void 類別名稱:fun() {….}//類別外實現
Java透過子類別對一般父類別中普通方法的覆寫、子類別對抽象類別中普通方法或抽象方法的覆寫、子類別對介面中抽象方法的覆寫。 +向上轉型。
抽象方法用abstract聲明,且沒有內容實作。
如:
abstract void fun() ; //類別內無實現
11、抽象類別二者的抽象類別都不能實例化物件。純虛函數和抽象方法概念類似,作用類似。
C++中也可以說有抽象類,帶有純虛函數的類別。
純虛函數是沒有內容實現,且有「=0」的虛函數,不能實例化物件。
如:
virtual void fun() = 0 ; //類別內宣告為=0,類別外也不實作。
Java中的抽象類別是用abstract關鍵字宣告的類,其中包含了抽象方法。不能實例化物件。
Java中的介面是一種特殊的類,或者說一種特殊的抽象類別。是由全部的靜態常數和抽象函數所構成。
12、存取權限
C++透過3種繼承方式來改變子類別與父類別間成員的存取權限。
class Student :public Person{
public :
。 。 。 。 。 。
Private :
。 。 。 。 。 。
};
class worker :protected Person{
public :
。 。 。 。 。 。
Private :
。 。 。 。 。 。
};
Class farmer :private Person{
public :
。 。 。 。 。 。
Private :
。 。 。 。 。 。
};
Java透過套件機制實作不同類別之間成員的存取權限。
Package org.tyut.a
class Person{
private …..
private …
public …….
public …
}
package org.tuyt.b
class Person{
private …..
private …
public …….
public …
}
package org.tuyt.c
class Person{
private …..
private …
public …….
public …
}
13.C++預處理&java導入包二者的想法是一樣的:想使用目前類別以外的類別時,
C++中,在類別定義前使用#include預編譯指令,將要包含的類別庫包含進來。
標準類別庫用尖括號< >,不帶h。自訂類別庫用雙引號“”,帶h,會先從目前路徑找到。
如:
#include <iostream>
#include “demo.h”
Java中,將要使用的類別匯入進來,使用import指令,要註明類別所在的套件。
如:
imort java. Lang. * ;
import org. tyut. * ;