十四、泛型與其他API
1、系統結構圖(xmind)
——泛型:
——2.其他API
2、tips
——1.泛型
1.JDK1.5的集合類希望在定義集合時,明確表明你要向集合中裝入那種類型的數據,無法加入指定類型以外的數據
2.泛型是提供給javac編譯器使用的可以限定集合中的輸入類型說明的集合時,會去掉“類型”信息,使程序運行效率不受影響,對參數化的泛型類型,getClass()方法的返回值和原始類型完全一樣。
3.由於編譯生成的字節碼會去掉泛型的類型信息,只要能跳過編譯器,就可以往某個泛型集合中加入其它類型的數據,如用反射得到集合,再調用add方法即可。
4.沒有使用泛型時,只要是對象,不管是什麼類型的對象,都可以存儲進同一個集合中。使用泛型集合,可以將一個集合中的元素限定爲一個特定類型,集合中只能存儲同一個類型的對象,這樣更安全;並且當從集合獲取一個對象時,編譯器也可以知道這個對象的類型,不需要對對象進行強制類型轉換,這樣更方便。泛型就是把原來的類名進行了延長!在JDK 1.5中,你還可以按原來的方式將各種不同類型的數據裝到一個集合中,但編譯器會報告unchecked警告。
5.通常在集合框架中很常見,只要見到<>就要定義泛型。其實<>就是用來接收類型的。當使用集合時,將集合中要存儲的數據類型作爲參數傳遞到<>中即可。
6.編譯器不允許創建泛型變量的數組。即在創建數組實例時,數組的元素不能使用參數化的類型,如:Vector<Integer>vectorList[] = new Vector<Integer>[10];//錯誤的。
7.Collection<?> a可以與任意參數化的類型匹配,但到底匹配的是什麼類型,只有以後才知道,所以:a=newArrayList<Integer>和a=new ArrayList<String>都可以,但a.add(new Date())或a.add(“abc”)都不行。
8.語法格式:
class Utils<XX>
{
private XX s;
public void setxx(XX s)
{
this.s=s;
}
public XX getXX()
{
return s;
}
}
總結:
對泛型的定義:
第一、定義泛型:當又不確定的類型需要傳入到集合中,需要定義泛型。
第二、定義泛型類:如果類型確定後,所操作的方法都是屬於此類型,則定義泛型類。
第三、定義泛型方法:如果定義的方法確定了,裏面所操作的類型不確定,則定義泛型方法。
——2.編譯器的泛型
1、編譯器判斷範型方法的實際類型參數的過程稱爲類型推斷,類型推斷是相對於知覺推斷的,其實現方法是一種非常複雜的過程。
2、根據調用泛型方法時實際傳遞的參數類型或返回值的類型來推斷,具體規則如下:
1)當某個類型變量只在整個參數列表中的所有參數和返回值中的一處被應用了,那麼根據調用方法時該處的實際應用類型來確定,這很容易憑着感覺推斷出來,即直接根據調用方法時傳遞的參數類型或返回值來決定泛型參數的類型。
慄:swap(new String[3],3,4)
——> static <E> voidswap(E[] a, int i, int j)
2)當某個類型變量在整個參數列表中的所有參數和返回值中的多處被應用了,如果調用方法時這多處的實際應用類型都對應同一種類型來確定,這很容易憑着感覺推斷出來
慄:add(3,5)
——> static<T> T add(T a, T b)
3)當某個類型變量在整個參數列表中的所有參數和返回值中的多處被應用了,如果調用方法時這多處的實際應用類型對應到了不同的類型,且沒有使用返回值,這時候取多個參數中的最大交集類型,例如,下面語句實際對應的類型就是Number了,編譯沒問題,只是運行時出問題:
慄:fill(new Integer[3],3.5f)
——> static<T> void fill(T[] a, T v)
4)當某個類型變量在整個參數列表中的所有參數和返回值中的多處被應用了,如果調用方法時這多處的實際應用類型對應到了不同的類型,並且使用返回值,這時候優先考慮返回值的類型,例如,下面語句實際對應的類型就是Integer了,編譯將報告錯誤,將變量x的類型改爲float,對比eclipse報告的錯誤提示,接着再將變量x類型改爲Number,則沒有了錯誤:
慄: intx =(3,3.5f)
——> static<T> T add(T a, T b)
5)參數類型的類型推斷具有傳遞性,下面第一種情況推斷實際參數類型爲Object,編譯沒有問題,而第二種情況則根據參數化的Vector類實例將類型變量直接確定爲String類型,編譯將出現問題:
慄: copy(newInteger[5],new String[5])
——> static<T> void copy(T[] a,T[] b);
copy(newVector<String>(), new Integer[5])
——> static<T> void copy(Collection<T> a , T[] b);
——3.實例
import java.util.*;
//人 父類
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
//學生 繼承父類
class Student extends Person
{
Student(String name)
{
super(name);
}
}
class Demo
{
public static void main(String[] args)
{
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
printColl(al);//父類對象的元素集合可以調用
ArrayList<Student> al1 = new ArrayList<Student>();
al1.add(new Student("abc--1"));
al1.add(new Student("abc--2"));
al1.add(new Student("abc--3"));
printColl(al1); //子類對象的元素集合也可以調用
}
//定義一個上限的泛型方法
public static void printColl(Collection<? extends Person> al)
{
Iterator<? extends Person> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
——4.System類
——5.Runtime類
2、方法
——7.Calendar類
方法:
/**
* 需求:編寫程序,該程序啓動後用戶可以按“yyyy-MM-dd”的格式輸入一個日期,程序計算這一
* 天是星期幾,並且計算出是一年中的第幾天。
*/
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Scanner;
import java.util.Date;
class DateDemo
{
public static void main(String[] args)throws Exception
{
//運用scanner接收鍵盤輸入
Scanner sc = new Scanner(System.in);
System.out.print("請輸入日期(格式爲yyyy-MM-dd):");
OutputDate(sc);
sc.close();
}
public static void OutputDate(Scanner sc)throws Exception
{
//定義格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//scanner獲取的格式進行解析存入d這個日期值中
Date d = sdf.parse(sc.next());
//定義一個Calendar日曆用於獲取需要的兩個值
Calendar cd = Calendar.getInstance();
//將需要輸出的時間值存於日曆中
cd.setTime(d);
//獲取並輸出星期
getWeek(cd);
System.out.println(",是今年的第"+cd.get(Calendar.DAY_OF_YEAR)+"天。");
}
public static void getWeek(Calendar cd)
{
//獲取星期的值用於查找表相對應的字符串並輸出
int num = cd.get(Calendar.DAY_OF_WEEK);
String[] week = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
System.out.print("今天是:"+week[num-1]);
}
}