1.1 類與對象
1.1.1 類與對象的關係
在面向對象中,類和對象是最基本、最重要的組成單元。類實際上是表示一個客觀世界某類羣體的一些基本特徵抽象。對象就是表示一個個具體的東西。例如,在顯示生活中,人就可以表示一個類,因爲人本省屬於一種廣義的概念,並不是一個具體的。而某一個具體的人,就可以稱爲對象,可以通過各種信息完整的描述這個具體的人,如這個人的姓名、年齡、性別等信息,這些信息在面向對象的概念中就稱爲屬性;當然人是可以吃飯、睡覺的,這些人的行爲在類中就稱爲方法。也就是說如果要使用一個類,就一定有產生對象, 每個對象之間是靠各個屬性的不同來進行區分的,而每個對象所具備的操作就是類中規定紅啊的方法。類與對象的關係如圖:
1.1.2 類的定義
類是由屬性和方法組成的。屬性中定義類一個個的具體信息,實際上一個屬性就是一個變量,而方法是一些操作的行爲,但是在程序設計中,定義類也是要按照具體的語法要求完成的,語法如下:
class 類名稱{
數據類型 屬性;
public 返回值的數據類型 方法名稱(參數1, 參數2){
程序語句;
return 表達式;
}
}
下面根據以上的格式定義一個Person類:
class Person{
String name;
int age;
public void tell(){
System.out.println("姓名:" + name + ",年齡:" + age);
}
}
在上面程序中,Person類定義了name和age兩個屬性,分別表示人的姓名和年齡,然後定義一個tell方法,此方法的功能就是打印這兩個屬性的內容。
此處的方法並沒有加上static關鍵字,這是因爲此時定義的方法將由對象調用,而不像之前那樣與主方法定義在一個類中且由主方法直接調用。
類的定義可以用圖表示出來:
1.第一層表示類的名稱,類的名稱要求開頭是字母大寫。
2.第二層表示屬性的的定義,按照“訪問權限 屬性名稱: 屬性類型”的格式定義,在本類中因爲聲明屬性處沒有寫任何的訪問權限,所以前面暫時不加任何的符號。
3.第三層表示類中方法的定義,按照“訪問權限 方法名稱():方法返回值”的格式定義,在本來中方法的聲明處加上了public(此爲訪問權限,表示任何地方都可以訪問),所以使用“+”表示。另外,如果方法中有傳遞參數,則方法定義格式爲“訪問權限 方法名稱(參數名稱:參數類型,參數名稱:參數類型,…):方法返回值”。
1.1.3 對象的創建及使用
在上面已經創建好了一個Person類,要想使用一個類則必須有對象。對象的創建格式:
類名 對象名稱 = null;
對象名稱 = new 類名();
用以上格式產生對象分爲聲明對象和實例化對象兩步。
當然可以直接通過類名 對象名稱 = new 類名();
創建具體範例:
class ClassDemo01{
public static void main(String[] args) {
Person p = new Person();
}
}
以上程序在主方法中實例化了一個Person對象,對象名爲p。與前面的數組開闢空間一樣,對象的實例化也是要劃分堆、棧空間的,具體的內存分配如圖:
所有的對象名稱都在棧內存中保存,而對象的具體內容則保存在對應的堆內存之中,必須使用new關鍵字才能開闢堆內存空間,此時,因爲p對象剛剛被實例化,所以對象中的屬性內容都是默認值,字符串的默認值爲null,整數的默認值爲0。
訪問對象中的屬性或方法:
訪問屬性:對象名稱.屬性名
方位方法:對象名稱.方法名()
爲對象的屬性設置內容,同時調用tell方法把內容輸出:
class ClassDemo03{
public static void main(String[] args) {
Person p = new Person();
p.name = "張三";
p.age = 12;
p.tell();
}
}
運行結果:
姓名:張三,年齡:12
屬性賦值完成之後的內存如圖:
對象使用前必須實例化。
1.1.4 創建多個對象
創建兩個對象:
class ClassDemo04{
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "張三";
p1.age = 12;
p1.tell();
Person p2 = new Person();
p2.name = "李四";
p2.age = 13;
p2.tell();
}
}
運行結果:
姓名:張三,年齡:12
姓名:李四,年齡:13
程序分別實例化了兩個Person對象,那麼也就一味着p1和p2對象分別指向各自的堆內存空間,如圖:
類屬於引用數據類型,而且從數組的使用上也可以發現,引用數據類型就是指一段堆內存空間可以同時被多個棧內存指向。
引用傳遞的簡單範例:
class ClassDemo05{
public static void main(String[] args) {
Person p1 = null;
Person p2 = null;
p1 = new Person();
p2 = p1;
p1.name = "張三";
p1.age = 12;
p2.age = 13;
p1.tell();
p2.tell();
}
}
運行結果:
姓名:張三,年齡:13
姓名:張三,年齡:13
兩個對象的輸出內容是一樣的,實際上所謂的引用傳遞,就是將一個堆內存空間的使用權給多個棧內存空間,每個棧內存空間都可以修改堆內存的內容,內存如圖:
從圖中可以發現內存空間的堆、棧指向的變化,程序最後由per2將age的值修改爲13,所以最終結果per1中的age屬性值也是13。
class ClassDemo06{
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p1.name = "張三";
p1.age = 12;
p2.name = "李四";
p2.age = 13;
p2 = p1;
p1.tell();
p2.tell();
}
}
運行結果:
姓名:張三,年齡:12
姓名:張三,年齡:12
內存變化圖:
關於垃圾空間的釋放:
Java本身提供垃圾收集機制(Garbage Collection,GC),會不定期地釋放不用的內存空間,只要對象不使用了,就會等待GC釋放空間。
一個棧內存空間只能指向一個堆內存空間,如果要想再指向其他的堆內存空間,則必須先斷開已有的指向才能分配新的指向。