1. 程式人生 > 其它 >介面和內部類

介面和內部類

介面和內部類

介面

隨著軟體規模的日益龐大,我們需要把複雜系統劃分成小的組成部分,程式設計介面的設計十分重要。程式設計的實踐中,程式設計介面的設計首先要使系統的職責得到合理劃分。良好的介面設計可以降低系統各部分的相互依賴,提高組成單元的內聚性,降低組成單元間的耦合程度,從而提高系統的維護性和擴充套件性。

1.關於介面的理解。

介面從更深層次的理解,應是定義(規範,約束)與實現(名實分離的原則)的分離。

介面的本身反映了系統設計人員對系統的抽象理解。

介面應有兩類:第一類是對一個體的抽象,它可對應為一個抽象體(abstract class);

第二類是對一個體某一方面的抽象,即形成一個抽象面(interface);

一個體有可能有多個抽象面。

抽象體與抽象面是有區別的。

面向介面程式設計

在一個面向物件的系統中,系統的各種功能是由許許多多的不同物件協作完成的。在這種情況下,各個物件內部是如何實現自己的,對系統設計人員來講就不那麼重要了;而各個物件之間的協作關係則成為系統設計的關鍵。小到不同類之間的通訊,大到各模組之間的互動,在系統設計之初都是要著重考慮的,這也是系統設計的主要工作內容。面向介面程式設計就是指按照這種思想來程式設計。

Java介面特性學習

在Java中看到介面,第一個想到的可能就是C++中的多重繼承和Java中的另外一個關鍵字abstract。從另外一個角度實現多重繼承是介面的功能之一,介面的存在可以使Java中的物件可以向上轉型為多個基型別,並且和

抽象類一樣可以防止他人建立該類的物件,因為介面不允許建立物件。

interface關鍵字用來宣告一個介面,它可以產生一個完全抽象的類,並且不提供任何具體實現。interface的特性整理如下:

\1. 介面中的方法可以有引數列表和返回型別,但不能有任何方法體。

\2. 介面中可以包含成員變數,但是會被隱式的宣告為static和final。public static final

\3. 介面中的成員變數只是被儲存在該介面的靜態儲存區域內,而不屬於該介面。

\4. 介面中的方法可以被宣告為public或不宣告,但結果都會按照public型別處理。

\5. 當實現一個介面時,需要將被定義的方法宣告為public型別的

,否則為預設訪問型別,Java編譯器不允許這種情況。

\6. 如果沒有實現介面中所有方法,那麼建立的仍然是一個介面。

\7. 擴充套件一個介面來生成新的介面應使用關鍵字extends,實現一個介面使用implements。

interface在某些地方和abstract有相似的地方,但是採用哪種方式來宣告類主要參照以下兩點:

\1. 如果要建立不帶任何方法定義和成員變數的基類,那麼就應該選擇介面而不是抽象類。

\2. 如果知道某個類應該是基類,那麼第一個選擇的應該是讓它成為一個介面,只有在必須要有方法定義和成員變數的時候,才應該選擇抽象類。因為抽象類中允許存在一個或多個被具體實現的方法,只要方法沒有被全部實現該類就仍是抽象類。

以上就是介面的基本特性和應用的領域,但是介面絕不僅僅如此,在Java語法結構中,介面可以被巢狀,既可以被某個類巢狀,也可以被介面巢狀。這在實際開發中可能應用的不多,但也是它的特性之一。需要注意的是,在實現某個介面時,並不需要實現巢狀在其內部的任何介面,而且,private介面不能在定義它的類之外被實現。

如何定義介面?

格式:
[訪問修飾符] interface 介面名 [extends 父介面1,父介面2…] {
常量定義 //總是public static final
方法定義 //總是:public abstract
}

如何實現介面

子類通過implements來實現介面中的規範
介面不能建立例項,但是可用於宣告引用變數型別。
一個類實現了介面,必須實現介面中所有的方法,並且這些方法只能是public的。
Java的類只支援單繼承,介面支援多繼承

介面相關規則

介面中所有方法都是抽象的。
即使沒有顯式的將介面中的成員用public標示,也是public訪問型別的
介面中變數預設用 public static final標示,所以介面中定義的變數就是全域性靜態常量。

可以定義一個新介面,用extends去繼承一個已有的介面
介面不能繼承普通類
可以定義一個類,用implements去實現一個介面中所有方法。
可以定義一個抽象類,用implements去實現一個介面中部分方法。

案例

//介面
package interfacePractect;

public interface UsbInterface {
	void power();
}
//實現類
package interfacePractect;

public class Mouse implements UsbInterface {

	@Override
	public void power() {
		System.out.println("插上滑鼠");
	}
}
//
package interfacePractect;

public class Fan implements UsbInterface{

	@Override
	public void power() {
		System.out.println("插上風扇");	
	}
}
//
package interfacePractect;

public class UPan implements UsbInterface{

	@Override
	public void power() {
		System.out.println("插上U盤");
	}
}

//表現類
package interfacePractect;

public class Computer {
	private UsbInterface usb;//將介面變為成員變數
	public void func() {
		usb.power();//通過介面呼叫方法
	}
	//返回值是介面,多型的表現形式
	public UsbInterface getUsb() {
		return usb;
	}
	//引數是介面,多型的表現形式
	public void setUsb(UsbInterface usb) {
		this.usb = usb;
	}
	
}
//測試類
package interfacePractect;

public class Test {
	public static void main(String[] args) {
		Fan fan = new Fan();
		Computer com = new Computer();
		com.setUsb(fan);//引數是介面,可以用實現類的引用傳遞過去
		com.func();
	}
}

內部類

成員內部類

package out$in;
/**
 * 成員內部類		class可以用訪問修飾符類修飾訪問許可權
 * 定義在外部類裡面,方法外面
 * 內部類可以直接使用外部類的成員變數,反之則不行
 * 當外部類的成員變數與內部類的成員變數重名時,
 * 要想使用外部類的成員變數,則需要通過	外部類名.this.成員變數 	來使用
 * @author lgx
 *
 */
public class OuterClass {
	private String name = "外";//外部類成員變數
	//成員內部類
	class InnerClass{
		//內部成員變數
		private String name = "內";
		//內部成員方法
		public void test() {
			System.out.println("內部類方法" + OuterClass.this.name);
		}
	}
	public void test() {//外部類成員方法
		System.out.println("外部類的成員方法");
	}
}


//測試類
package out$in;

import out$in.OuterClass.InnerClass;

/**
 * 成員內部類建立物件
 * 		OuterClass oc = new OuterClass();
 * 		InnerClass in = oc.new  InnerClass();
 * @author lgx
 *
 */
public class Test {
	public static void main(String[] args) {
		
		OuterClass oc = new OuterClass();
		InnerClass in = oc.new  InnerClass();
		in.test();
		oc.test();
		
	}
}

靜態內部類

package out$in;
/**
 * 靜態內部類
 * 在外部類裡面,方法外面,使用static修飾。
 * 當內部類的成員有static時,該內部類必須是靜態內部類
 * 在外部類的方法使用內部類時,可以直接通過		外部類.內部類		來使用內部的靜態成員
 * @author lgx
 *
 */
public class OuterClass02 {
	private int age;
	static class InnerClass{
		static int age = 20;
		String name = "內";
		public void test() {
			System.out.println("內部類方法");
		}
	}
	public void test() {
		System.out.println("外部方法"+OuterClass02.InnerClass.age);
	}
}


//測試類
package out$in;

import out$in.OuterClass02.InnerClass;

/**
 * 靜態內部類建立物件
 * 可以直接通過內部類名直接new出來
 * InnerClass in = new InnerClass();
 * @author lgx
 *
 */
public class Test02 {
	public static void main(String[] args) {
		InnerClass in = new InnerClass();
		in.test();
		OuterClass02 oc = new OuterClass02();
		oc.test();
	}
}

方法內部類

package out$in;
/**
 * 方法內部類
 * 在成員方法裡面建立一個類,該內部類只作用於該方法內,出了方法無效
 * 所以class前面不能有訪問修飾符,也不可以用static修飾,
 * 當方法有引數時,引數必須用final修飾
 * @author lgx
 *
 */
public class OuterClass03 {
	private int age;
	public void test(final int a) {
		class InnerClass{
			private int age = 20;
			public void test() {
				System.out.println("內部類方法"+ a);
			}
		}
		//要想使用內部類的成員變數和方法,必須先建立內部類的物件
		InnerClass in = new InnerClass();
		in.test();
	}

}

//測試類
package out$in;
/**
 * 方法內部類不能再其他類中建立物件,因為方法內部類的作用域只在那個方法裡面
 * @author lgx
 *
 */
public class Test03 {
	public static void main(String[] args) {
		OuterClass03 oc = new OuterClass03();
		oc.test(2);
	}
}	

匿名內部類

//介面
package out$in;

public interface MyInterface {
	void test();
}

//測試類
package out$in;
/**
 * 匿名內部類
 * 適用於只需要使用一次物件的類
 * 但使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個介面
 * 
 * 
 * @author lgx
 *
 */
public class Test04 {
	public static void main(String[] args) {
		//通過介面來接收一個沒有名字的類,
		//原理是匿名內部類先實現了介面,然後再建立物件
		MyInterface mi = new MyInterface() {
			@Override
			public void test() {
				System.out.println("匿名內部類");
			}
		};
		//mi是引用,可以呼叫裡面的方法
		mi.test();
	}
}

垃圾回收機制

物件空間的分配:

使用new關鍵字建立物件即可

物件空間的釋放:

傳統的C/C++語言,需要程式設計師負責回收已經分配記憶體。顯式回收垃圾回收的缺點:
程式忘記及時回收,從而導致記憶體洩露,降低系統性能。
程式錯誤回收程式核心類庫的記憶體,導致系統崩潰。
Java語言不需要程式設計師直接控制記憶體回收,是由JRE在後臺自動回收不再使用的記憶體,稱為垃圾回收機制(Garbage Collection)。
可以提高程式設計效率。
保護程式的完整性。
其開銷影響效能。Java虛擬機器必須跟蹤程式中有用的物件,確定哪些是無用的。

垃圾回收機制關鍵點

垃圾回收機制只回收JVM堆記憶體裡的物件空間。
對其他物理連線,比如資料庫連線、輸入流輸出流、Socket連線無能為力

現在的JVM有多種垃圾回收實現演算法,表現各異。
垃圾回收發生具有不可預知性,程式無法精確控制垃圾回收機制執行。
可以將物件的引用變數設定為null,暗示垃圾回收機制可以回收該物件。
程式設計師可以通過System.gc()或者Runtime.getRuntime().gc()來通知系統進行垃圾回收,會有一些效果,但是系統是否進行垃圾回收依然不確定。

垃圾回收機制回收任何物件之前,總會先呼叫它的finalize方法(如果覆蓋該方法,讓一個新的引用變數重新引用該物件,則會重新啟用物件)。
永遠不要主動呼叫某個物件的finalize方法,應該交給垃圾回收機制呼叫。