全部章節 >>>>
本章目錄
8.1 內部類
8.1.1 內部類概述
- 爲實現程序設計的需要,需要將一個類放在另一個類的內部定義,定義在其他類內部的類就稱爲內部類,包含內部類的類也被稱爲外部類,內部類的作用如下:
- 內部類提供了更好的封裝,可以將內部類隱藏在外部類內,不允許同一個包中的其他類訪問該類。
- 內部類成員可以直接訪問外部類的私有數據,因爲內部類作爲其外部類成員,同一個類的成員之間可以相互訪問。但外部類不能訪問內部類的實現細節,如內部類的成員變量。
- 匿名內部類適用於創建那些僅需要一次使用的類。
8.1.2 內部類使用
語法:
public class OutClass{
……
//定義內部類
public class innerClass{
}
}
內部類分爲兩種:靜態內部類和非靜態內部類,使用static修飾的內部類稱爲靜態內部類,沒有使用static修飾的內部類則稱爲非靜態內部類。
8.1.3 實踐練習
8.2 靜態內部類
8.2.1 靜態內部類的實現
- 使用static修飾的內部類,被稱爲靜態內部類,靜態內部類屬於外部類本身,而不屬於外部類的某個對象。
- 靜態內部類可以包含靜態成員,也可以包含非靜態成員。
- 依據靜態成員不能訪問非靜態成員的規則,靜態內部類不能訪問外部類的實例成員,只能訪問外部類的類成員。即使是靜態內部類的實例方法,也不能訪問外部類的實例成員,只能訪問外部類的靜態成員。
示例: 演示靜態內部類的定義
public class OutClass {
private int outPro=5;
private static int outPro2=9;
private static class InnerClass{
private static int innerPro=10;//靜態內部類中可以定義靜態成員
private int innerPro2=100;//靜態內部類中的實例屬性
public void accessOutPro(){
/*以下代碼在編譯時出現錯誤靜態內部類無法直接訪問外部類的實例成員*/
//System.out.println(outPro);
//可通過外部類實例訪問外部類實例屬性
System.out.println("外部類實例屬性outPro="+new OutClass().outPro);
//訪問外部類的靜態成員,代碼正確
System.out.println("外部類的靜態屬性outPro2="+outPro2);
}
}
//未完接下一頁
}
public class OutClass {
//接上一頁
public void accessInnerPro(){
//System.out.println(innerPro);
//以上代碼出現錯誤,應修改爲如下形式,即通過類名訪問靜態內部類的類成員
System.out.println("內部類的靜態屬性innerPro="+InnerClass.innerPro);
//System.out.println(innerPro2);
//以上代碼出現錯誤,應修改爲如下格式
InnerClass ic=new InnerClass();
System.out.println("內部類實例屬性innerPro2="+ic.innerPro2);
ic.accessOutPro();//調用靜態內部類的實例方法
}
public static void main(String[] args) {
OutClass oc=new OutClass();
oc.accessInnerPro();
}
}
8.2.2 實踐練習
8.3 匿名內部類
8.3.1 匿名內部類的實現
匿名內部類適用於僅需要一次使用的類,匿名內部類的語法較爲特別,創建匿名內部類時,會立即創建一個該類的實例,創建完畢之後該類的定義會立即消失。
如果匿名內部類需要訪問外部類的局部變量,則必須使用final修飾符修飾外部類的局部變量,否則系統將報錯。
語法:
new 父類構造器(參數列表)| 實現接口(){
//匿名內部類的類體部分
}
匿名內部類必須繼承一個父類,或實現一個接口,但最多隻能繼承一個父類,或實現一個接口。
提醒:匿名內部類的兩條規則
- 匿名內部類不能是抽象類,因爲系統在創建匿名內部類時,會立即創建匿名內部類的對象,因此不允許將匿名內部類定義成抽象類。
- 匿名內部類不能定義構造器,因爲匿名內部類沒有類名,所以無法定義構造器,但匿名內部類可以定義實例化初始塊,通過實例化初始塊來完成構造器需要完成的事情。
示例: 演示匿名內部類的定義
//匿名內部類需要實現的接口
public interface Product {
double getPrice();
String getName();
}
public class Anonymous {
public void execute(Product product){
System.out.println("購買了一個:"+product.getName()+" 花費:"+product.getPrice());
}
public static void main(String[] args) {
Anonymous aym=new Anonymous();
/*調用execute()方法時,需要創建一個Product類型參數,此處傳入匿名實現類的實例*/
aym.execute(new Product() {
public double getPrice() {
return 98.29;
}
public String getName() {
return "費列羅巧克力";
}
});
}
}
示例:將匿名內部類更改爲內部類
public class Consumer {
public void execute(Product product){
System.out.println("購買了一個:"+product.getName()+" 花費:"+product.getPrice());
}
public class MyProduct implements Product{ //內部類
public double getPrice() {
return 98.29;
}
public String getName() {
return "費列羅巧克力";
}
}
public static void main(String[] args) {
Consumer consumer = new Consumer(); //實例化一個外部類對象
//通過外部類對象創建內部類對象
Product product = consumer.new MyProduct();
consumer.execute(product);
}
}
8.3.2 實踐練習
8.4 泛型
8.4.1 泛型概述
沒有使用泛型時取出集合元素
List listUser = new ArrayList();
listUser.add(new User(“張三”,20)) ;
User user = (User)listUser.get(0) ; //使用了強制類型轉換。
使用泛型時取出集合元素
List<User> listUser = new ArrayList<User>();
listUser.add(new User(“張三”,20)) ;
User user = listUser.get(0) ; //把類型轉換交給了編譯器
泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。
泛型的原理就是參數化類型
- 泛型把類型看做參數,也就是說把所要操作的數據類型看做參數,就像方法的形式參數是運行時傳遞的值的佔位符一樣。
- 泛型中的類型變量扮演的角色就如同一個參數,它提供給編譯器用來類型檢查的信息。
泛型的分類
- 泛型類
- 泛型方法
8.4.2 泛型應用
1、泛型類:就是具有一個或多個類型變量的類。
示例: 定義泛型類並實例化泛型類
public classPair<T>{
private T first
public Pair(T first){this.first=first;}
public void setFirst(T newValue){first=newValue;}
public T getFirst(){return first;}
}
public class PairTest{
public static void main(String[] args){
//用具體的類型替換類型變量就可以實例化泛型類型
Pair<String> pair=new Pair<String>("Hello");
System.out.println("first="+pair.getFirst());
}
}
2、泛型方法:
- 帶有參數類型的方法即泛型方法,泛型方法使得該方法能夠獨立於類而產生變化。
- 泛型方法所在的類可以是泛型類,也可以不是泛型類。
示例:聲明一個f(T x)泛型方法,用於返回調用該方法時,所傳入的參數類型的類名
class GenericMethod{
//T是泛型類型參數
public <T> void f(T x){
System.out.println(x.getClass().getName());
}
}
public class GenericMethodTest{
public static void main(String[] args){
GenericMethod gm=new GenericMethod();
gm.f(" ");
gm.f(1);
gm.f(1.0f);
gm.f('c');
gm.f(gm);
}
}
3、泛型定義:泛型定義包括泛型類定義和泛型對象定義,其中泛型對象定義的應用最爲普遍。
語法:
類名稱<具體類> 對象名稱 = new 類名稱<具體類>();
例如:
List<String> citys = new ArrayList<String>(); //城市列表
List<Address> empAdds = new ArrayList<Address>(); //員工住址列表
Map<String, Emp> empnoToEmp = new HashMap<String, Emp>(); //員工編號到員工映射
示例: 泛型集合List<T>與Map<K,V>應用
List<String> strList=new ArrayList<String>(); //聲明泛型集合,該集合元素爲String類型
//strList集合中只能添加字符串元素,否則無法通過編譯
strList.add("apple");
strList.add("peer");
strList.add("banana");
//strList.add(new Date());此處如果不將其註釋,在編譯時系統報錯
//集合使用泛型後,從集合中獲取數據無須強制類型轉換
String str=strList.get(strList.size()-1);
//創建Map泛型集合,map的Key爲String類型,value爲Date類型
Map<String,Date> map=new HashMap<String,Date>();
//向集合中添加數據
map.put("Java", new Date(60000));
map.put("C#", new Date(300000000));
map.put("MySQL", new Date(1000000));
//調用keySet()方法返回裝有所有Key值的Set集合
Set<String> keySet=map.keySet();
//通過keySet獲取Iterator迭代器
Iterator<String> iter=keySet.iterator();
while(iter.hasNext()){//遍歷迭代器
String key=iter.next();
System.out.println("Map["+key+"]="+map.get(key));
}
8.4.3 實踐練習
總結:
- 內部類提供了更好的封裝,可以將內部類隱藏在外部類內。內部類成員可以直接訪問外部類的私有數據,但外部類不能訪問內部類的成員變量。
- 使用static修飾的內部類,被稱爲靜態內部類,靜態內部類屬於外部類本身,而不屬於外部類的某個對象。
- 匿名內部類適用於創建那些僅需要一次使用的類,匿名內部類不能是抽象類,不能定義構造器,但是可以通過實例化初始塊來完成構造器需要完成的事情。
- 泛型的原理就是參數化類型,泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。