jdk1.5的新特性
泛型是一種泛泛的類型,泛指某一種類型竟秫,是在創(chuàng)建對(duì)象或者調(diào)用方法或者實(shí)現(xiàn)接口才明確的類型娃惯。
泛型好處提高安全性(將運(yùn)行期的類型轉(zhuǎn)換錯(cuò)誤提前到編譯期),省去強(qiáng)轉(zhuǎn)的麻煩肥败。
泛型使用注意事項(xiàng)
- <>中放的必須是引用數(shù)據(jù)類型趾浅;
- 前后的泛型必須一致,或者后面的泛型可以省略不寫(1.7的新特性菱形泛型) (建議后面的也寫全);
- 在創(chuàng)建對(duì)象或者調(diào)用方法或者實(shí)現(xiàn)接口明確泛型的時(shí)候馒稍,盡量不要明確成Object皿哨,因?yàn)檫@樣做沒(méi)有意義(泛型的由來(lái)就是由Object的轉(zhuǎn)型的問(wèn)題得到的);
- 泛型是JDK1.5出現(xiàn)的纽谒。
代碼演示:
public static void demo1() {
ArrayList list = new ArrayList();
list.add(110);//添加一個(gè)Integer類型的 110证膨,在沒(méi)有使用泛型的時(shí)候 list可以添加任意的引用類型
list.add(true); //添加一個(gè)Boolean類型的 true
list.add(new Person("張三", 23)); //添加一個(gè)Person
Iterator it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next()); //將集合里面的元素打印出來(lái)
}
}
public static void demo2() {
ArrayList list = new ArrayList();
list.add(110);
list.add(true);
list.add(new Person("張三", 23));
Iterator it = list.iterator();
while(it.hasNext()) {
//如果我想使用Person的特有功能 需要強(qiáng)制轉(zhuǎn)換成Person類型
Person p = (Person)it.next();//編譯不報(bào)錯(cuò), 運(yùn)行的時(shí)候立刻報(bào)錯(cuò)鼓黔,因?yàn)榇鎯?chǔ)的 110 和 true 并不是Person類型 單卻強(qiáng)制轉(zhuǎn)換成Person類型 會(huì)報(bào)出類型轉(zhuǎn)換錯(cuò)誤
System.out.println(p.getName() + "..." + p.getAge());
}
}
//ArrayList存儲(chǔ)字符串并遍歷泛型版
public static void demo3() {
ArrayList<Person> list = new ArrayList<>(); //<Person>規(guī)定 list對(duì)象里面必須存儲(chǔ)Person類型的元素央勒,存儲(chǔ)其他類型的編譯就會(huì)報(bào)錯(cuò)
list.add(new Person("張三", 23));
list.add(new Person("李四", 24));
list.add(new Person("王五", 25));
list.add(new Person("趙六", 26));
Iterator<Person> it = list.iterator(); //獲取的迭代器也是Person類型的泛型
while(it.hasNext()) {
Person p = it.next(); //it.next()獲取到的元素 就不再是Object了,泛型里面規(guī)定的類型 it.next()就獲取什么樣類型的元素澳化,所以就不用強(qiáng)制類型轉(zhuǎn)換了
System.out.println(p.getName() + "..." + p.getAge());
}
}
public static void main(String[] args) {
//ArrayList<int> list = new ArrayList<int>(); //編譯報(bào)錯(cuò) <>中放的必須是引用數(shù)據(jù)類型
//ArrayList<Object> list = new ArrayList<Person>(); //編譯報(bào)錯(cuò) 集合的泛型要保證前后的數(shù)據(jù)類型一致
ArrayList<Object> list = new ArrayList<>();//泛型最好不要定義成Object,沒(méi)有意義崔步,1.7版本的新特性,菱形泛型,后面的<>可以不用填寫
list.add("aaa");
list.add(true);
}
泛型類: public class 類名<泛型類型1,泛型類型2,....>{}
public class Worker<QQ> {
public void show(QQ qq){
System.out.println(qq);
}
}
public class Worker<QQ,MM,DD,RR> { //可以寫一個(gè)泛型 也可以寫多個(gè)
public void show(QQ qq){
System.out.println(qq);
}
}
泛型非靜態(tài)方法: public <泛型類型> 返回類型 方法名(泛型類型 變量名){}
代碼演示:
public class Demo1_Generic {
public static void main(String[] args) {
/*Tool t = new Tool();
t.show("abc"); //調(diào)用show(String s)方法 傳入一個(gè)"abc"
t.show(100);*/ //調(diào)用show(Integer i)方法 傳入一個(gè)100
//如果想繼續(xù)接著調(diào)用一個(gè)show(Student s)方法缎谷, 就需要繼續(xù)修改Tool類刷晋,再繼續(xù)編寫一個(gè)show(Student s)方法 才能調(diào)用
//如果想繼續(xù)接著調(diào)用一個(gè)show(Animal a)方法, 就需要繼續(xù)修改Tool類,再繼續(xù)編寫一個(gè)show(Animal a)方法 才能調(diào)用
//如果想繼續(xù)接著調(diào)用一個(gè)show(Worker w)方法眼虱, 就需要繼續(xù)修改Tool類喻奥,再繼續(xù)編寫一個(gè)show(Worker w)方法 才能調(diào)用
//這樣修改 將無(wú)窮無(wú)盡,所以用下面的泛型類改進(jìn)代碼
/*Tool1<String> t = new Tool1<>(); //想調(diào)用show方法 傳入一個(gè)"abc" 那么就創(chuàng)建一個(gè)泛型為String的對(duì)象
t.show("abc");
Tool1<Integer> t1 = new Tool1<>(); //想調(diào)用show方法 傳入一個(gè)100 那么就創(chuàng)建一個(gè)泛型為Integer的對(duì)象
t1.show(100);
Tool1<Student> t2 = new Tool1<>(); //想調(diào)用show方法 傳入一個(gè)Student 那么就創(chuàng)建一個(gè)泛型為Student的對(duì)象
t2.show(new Student());*/
//如果想接著調(diào)用show方法 傳入一個(gè)Animal 就又要?jiǎng)?chuàng)建一個(gè)泛型為Animal的對(duì)象 捏悬,每次都要?jiǎng)?chuàng)建一個(gè)新的對(duì)象 浪費(fèi)空間 所以用下面的泛型方法改進(jìn)
Tool2 t = new Tool2();
t.show("abc"); //調(diào)用show方法的時(shí)候就明確了QQ是String類型
t.show(100);//調(diào)用show方法的時(shí)候就明確了QQ是Integer類型
t.show(new Student());//調(diào)用show方法的時(shí)候就明確了QQ是Student類型
//想傳什么樣的類型都可以 而且代碼非常的簡(jiǎn)單
}
}
public class Tool {
public void show(String s) {
System.out.println(s);
}
public void show(Integer i) {
System.out.println(i);
}
}
public class Tool1<QQ> {
public void show(QQ qq){
System.out.println(qq);
}
}
public class Tool2 {
public <QQ>void show(QQ s){
System.out.println(s);
}
}
泛型靜態(tài)方法: public static <泛型類型> 返回類型 方法名(泛型類型 變量名){}
public class Tools<Q> {
/*public static void show(Q q) { //編譯報(bào)錯(cuò)撞蚕,因?yàn)殪o態(tài)的 優(yōu)先于對(duì)象而存在
System.out.println(q);
}*/
public static<W> void print(W w) { //靜態(tài)方法必須聲明自己的泛型
System.out.println(w);
}
}
泛型接口:public interface 接口名<泛型類型>
子類在實(shí)現(xiàn)父接口的時(shí)候可以明確泛型,也可以直接沿用父類的泛型
代碼演示:
interface Inter<T> {
public void show(T t);
}
class Demo implements Inter<String> { //子類在實(shí)現(xiàn)父接口的時(shí)候 可以明確泛型 明確成了String類型
@Override
public void show(String t) {
System.out.println(t);
}
}
class Demo<T> implements Inter<T> { //也可以直接沿用父類的泛型 T
@Override
public void show(T t) {
System.out.println(t);
}
}
泛型-通配符:
A:泛型通配符<?>任意類型
List<?> list = new ArrayList<Integer>(); //當(dāng)右邊的泛型是不確定時(shí),左邊可以指定為?
B:<? extends E >明確泛型的時(shí)候明確成E或者E的兒子
代碼演示:
public static void main(String[] args) {
ArrayList<Person> list1 = new ArrayList<>();
list1.add(new Person("張三", 23));
list1.add(new Person("李四", 24));
list1.add(new Person("王五", 25));
ArrayList<Student> list2 = new ArrayList<>();
list2.add(new Student("趙六", 26));
list2.add(new Student("周七", 27));
//boolean addAll(Collection<? extends E> c)
list1.addAll(list2); //Student 是Person的兒子 所以 可以添加成功
System.out.println(list1);
}
C:<? super E >明確泛型的時(shí)候明確成 E或者E的父類
增強(qiáng)for循環(huán)
為了簡(jiǎn)化數(shù)組或者集合的遍歷而出現(xiàn)的(JDK1.5出現(xiàn)的)
for(集合或者數(shù)組里面元素的數(shù)據(jù)類型 變量名 : 數(shù)組或者集合){
直接使用變量名就ok过牙;
}
代碼演示:
public static void demo1() {
int[] arr = {11,22,33,44,55};
for (int i : arr) { //增強(qiáng)for循環(huán)可以遍歷數(shù)組
//增強(qiáng)for循環(huán)在遍歷數(shù)組或者集合的時(shí)候甥厦,優(yōu)點(diǎn):代碼的書寫確實(shí)簡(jiǎn)單了,但缺點(diǎn)是遍歷時(shí)候沒(méi)有索引寇钉,如果想用索引的時(shí)候刀疙,就請(qǐng)用普通for循環(huán)
System.out.println(i);
}
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (String string : list) { //增強(qiáng)for循環(huán)可以遍歷集合
System.out.println(string);
}
}
遍歷過(guò)程中能否刪除元素總結(jié):
1)普通for循環(huán)在遍歷的時(shí)候(只能遍歷List體系的集合),可以刪除扫倡,但是在刪除過(guò)程中索引會(huì)改變谦秧, size也會(huì)發(fā)生改變,所以容易出現(xiàn)漏刪的情況撵溃。
解決:索引--疚鲤,代碼片段如下:
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
for(int i = 0; i < list.size(); i++) {
if("b".equals(list.get(i))) {
list.remove(i--); //通過(guò)索引刪除元素
}
}
2)迭代器在遍歷集合的時(shí)候 Iterator(可以遍歷任何單列集合),不可以通過(guò)集合操作元素缘挑,否則會(huì)報(bào)并發(fā)修改異常集歇。只能通過(guò)迭代器自身來(lái)對(duì)元素進(jìn)行操作,如果是刪除:可以用Iterator 也可以用ListIterator 因?yàn)樗麄兝锩娑加衦emove()语淘;如果是添加:只能使用ListIterator诲宇,因?yàn)橹挥蠰istIterator里面有add()
代碼片段如下:
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
if("b".equals(it.next())) {
//list.remove("b"); //不能用集合的刪除方法,因?yàn)榈^(guò)程中如果集合修改會(huì)出現(xiàn)并發(fā)修改異常
it.remove(); //讓迭代器自己來(lái)刪除元素
}
}
3)增強(qiáng)for循環(huán)遍歷集合的時(shí)候(可以遍歷任何單列集合),由于底層就是調(diào)用的迭代器惶翻,所以不能刪除姑蓝,只能遍歷。代碼片段如下:
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
for (String string : list) {
if("b".equals(string)) {
list.remove("b"); //運(yùn)行報(bào)錯(cuò)维贺,并發(fā)修改異常它掂,增強(qiáng)for循環(huán)底層用的是迭代器 所以不能在迭代器過(guò)程中讓集合來(lái)刪除元素巴帮,如果用迭代器自己來(lái)刪除 溯泣,哪有迭代器來(lái)讓你使用呢?榕茧,在底層呢 你又看不到
}
}
System.out.println(list);
可變參數(shù):
格式:修飾符 返回值類型 方法名(數(shù)據(jù)類型 ... 變量名){}
注意:
- 可變參數(shù)是JDK1.5后出現(xiàn)的新特性
- 可變參數(shù)其實(shí)是一個(gè)數(shù)組垃沦,所以調(diào)用帶有可變參數(shù)的方法的時(shí)候,可以傳入一個(gè)相同類型的數(shù)組
- 有多個(gè)參數(shù)的時(shí)候用押,可變參數(shù)放到最后
代碼演示:
public class Demo3_ChangeableArgs {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
print(); //調(diào)用的時(shí)候 可以不傳入?yún)?shù)
print(arr); //調(diào)用的時(shí)候 可以傳入一個(gè)數(shù)組肢簿,因?yàn)榭勺儏?shù)的底層就是使用的數(shù)組
print(11,22,55); //調(diào)用的時(shí)候 可以傳入多個(gè)參數(shù)
}
public static void print(int ... arr) { //可變參數(shù)其實(shí)是一個(gè)數(shù)組
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void show(String s , int ... arr) { //有多個(gè)參數(shù)的時(shí)候,可變參數(shù)放到最后
}
/*
public static void method(int ... arr , String s) { //編譯報(bào)錯(cuò) 有多個(gè)參數(shù)的時(shí)候,可變參數(shù)放到最后
}*/
}
//可變參數(shù)的應(yīng)用
public class Demo4_ChangeableArgs {
public static void main(String[] args) {
//求兩個(gè)數(shù)的最大值,我需要定義一個(gè),含兩個(gè)參數(shù)的方法max(int a , int b)
int big = max(5,6);
//假如現(xiàn)在需求變了池充,我想求三個(gè)數(shù)的最大值,那么我需要定義一個(gè)含三個(gè)參數(shù)的方法 max(int a , int b , int c)
int big1 = max(5,6,10);
//假如現(xiàn)在需求又變了桩引,我想求四個(gè)數(shù)的最大值,難道我就再繼續(xù)定義一個(gè)含有四個(gè)參數(shù)的方法 max(int a , int b , int c , int d)嗎收夸? 這樣太麻煩了坑匠, 解決方案就是 用可變參數(shù)
int big2 = max(11,432,7,87,23);
}
//求兩個(gè)數(shù)的最大值
public static int max(int a , int b) {
return a>b?a:b;
}
//求三個(gè)數(shù)的最大值
public static int max(int a , int b , int c) {
return a>b ? (a>c?a:c) : (b>c?b:c);
}
//求任意個(gè)數(shù)的最大值
public static void max(int ... arr) { //可變參數(shù)其實(shí)是一個(gè)數(shù)組
int a = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]> a){
a = arr[i]
}
}
return a;
}
}
集合和數(shù)組之間的轉(zhuǎn)換
Arrays工具類的asList(T ... t):將數(shù)組轉(zhuǎn)成集合(該方法用的可變參數(shù))
注意:
1)返回一個(gè)長(zhǎng)度固定的集合,可以改和查,不能增和刪,也就是改變其長(zhǎng)度的操作都不可以做卧惜。
2)將數(shù)組轉(zhuǎn)換成集合,數(shù)組必須是引用數(shù)據(jù)類型厘灼。
Collection中toArray(T[] a)泛型版的集合轉(zhuǎn)數(shù)組:
T[] 明確成什么樣的數(shù)組 toArray(T[] a)方法就返回什么類型的數(shù)組
注意:當(dāng)集合轉(zhuǎn)換數(shù)組時(shí),數(shù)組長(zhǎng)度如果是小于等于集合的size時(shí),轉(zhuǎn)換后的數(shù)組長(zhǎng)度等于集合的size;如果數(shù)組的長(zhǎng)度大于了size,分配的數(shù)組長(zhǎng)度就和你指定的長(zhǎng)度一樣咽瓷。
好了今天就先說(shuō)到這了设凹,想了解更多學(xué)習(xí)知識(shí),請(qǐng)關(guān)注微信公眾號(hào)“阿Q說(shuō)”茅姜,獲取更多學(xué)習(xí)資料吧闪朱!你也可以后臺(tái)留言說(shuō)出你的疑惑,阿Q將會(huì)在后期的文章中為你解答匈睁。每天學(xué)習(xí)一點(diǎn)點(diǎn)监透,每天進(jìn)步一點(diǎn)點(diǎn)。