黑馬程式設計師—泛型
-------android培訓、java培訓、期待與您交流!
----------
泛型的概述:
泛型是一種特殊的型別,它把指定型別的工作推遲到客戶端程式碼宣告並例項化類或方法的使用進行。也被稱為引數化型別,可以把型別當做引數一樣傳遞過來,在傳遞過來之前我不明確,但是在使用的時候就就明確了。
泛型出現的原因:
早期的Object型別可以接收任意的物件型別,但是在實際的使用中,會有型別轉換的 問題。也就存在這隱患,所以Java提供了泛型來解決這個安全問題。是jdk1.5的新特性。
泛型的好處:
1.提高了程式的安全性
2.將執行期遇到的問題轉移到了編譯期
3.省去了型別強轉的麻煩
泛型的常見應用:
1.泛型類
2.泛型方法
3.泛型介面
Java泛型的工作原理以及型別擦除概述:
Java的泛型是偽泛型。在編譯期間,所有的泛型資訊都會被擦除掉。正確理解泛型概念的首要前提是理解型別擦除。
Java中的泛型基本上都是在編譯器這個層次來實現的。在生產的Java位元組碼中是不包含泛型中的型別資訊的。使用泛型的時候加上的型別引數,會在編譯器在編譯的時候去掉。這個過程就稱為型別擦除。
如在程式碼中定義的List<Object>和List<String>型別,在編譯後都會變成List。JVM看到的只是List,而由泛型附加的型別資訊對JVM來說是不可見的。Java編譯器會在編譯時儘可能的發現可能出錯的地方,但是仍然無法避免在執行時刻出現型別轉換異常的情況。
型別擦除後保留的原始型別
原始型別就是擦除去了泛型資訊,最後在位元組碼中的型別變數的真正型別。無論何時定義一個泛型型別,相應的原始型別都會被自動地提供。型別變數被擦除,並使用其限定型別(無限定的變數用Object)替代。
泛型的格式:
< 泛型型別 >
注意: 這裡的泛型型別可以任意的內容,基本的資料型別,比如 String Person QQ、T、E、K
泛型案例:
public class GenericDemo {
public static void main(String[] args) {
ArrayList<String> list2 = new ArrayList<String>();
list2.add("A1");
list2.add("B1");
list2.add("C1");
// list2.add(123);
for (int i = 0; i < list2.size(); i++) {
String s = list2.get(i);
System.out.println(s);
}
}
}
自定義泛型案例:
案例:使用ArrayList集合,儲存自定義物件,並遍歷 (泛型版本);
public class GenericDemo {
public static void main(String[] args) {
//建立集合物件 加泛型
ArrayList<Person> list = new ArrayList<Person>();
//建立元素物件
Person p1 = new Person("張三");
Person p2 = new Person("李四");
Person p3 = new Person("王五");
//新增元素到集合
list.add(p1);
list.add(p2);
list.add(p3);
//遍歷
Iterator<Person> it = list.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.println(p.getName());
}
}
}
//自定義類 作為泛型使用
public class Person {
private String name;
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
泛型類:
把泛型定義在類上。
格式:public class 類名<泛型型別1,…>
注意:泛型型別必須是引用型別
<QQ> 定義一個泛型
QQ 使用當前這個泛型,這個QQ在程式執行的時候,會對應著一個具體的資料型別
public class Test<QQ> {
private QQ name;
public void setName(QQ name){
this.name = name;
}
public QQ getName(){
return name;
}
}
package cn.itcast_08_Generic_Class;
泛型類測試:
public class QQTest {
public static void main(String[] args) {
//Test t = new Test();
Test<String> t = new Test<String>();
t.setName("呵呵");
System.out.println( t.getName() );
Test<Integer> t2 = new Test<Integer>();
t2.setName(123);
System.out.println( t2.getName() );
}
}
package cn.itcast_09_Generic_Method;
泛型方法:
把泛型定義在方法上
格式:public <泛型型別> 返回型別 方法名(泛型型別 .)
K 的型別是在建立物件的時候 確定的
TT 型別是在呼叫方法的時候 確定的
這裡的K,TT 理解為 是一種資料型別的變數名
注意:建立多個泛型類物件的時候,可以賦值不同的泛型型別,不會產生衝突
public class GenericMethod<K> {
//普通方法
public String method(String str){
return str + "哈哈";
}
//泛型方法
public K function(K str){
return str;
}
//泛型方法
public <TT> TT show(TT str) {
return str;
}
}
package cn.itcast_09_Generic_Method;
泛型方法的測試類:
public class GenericMethodTest {
public static void main(String[] args) {
GenericMethod<String> gm = new GenericMethod<String>();
System.out.println(gm.method("haha"));
String str = gm.function("呵呵");
System.out.println(str);
Integer in = gm.show(123);
System.out.println(in);
}
}
package cn.itcast_10_Generic_Interface;
泛型介面
把泛型定義在介面上
格式:public interface 介面名<泛型型別1…>
public interface Inter<TT> {
public abstract TT show(TT str);
}
package cn.itcast_10_Generic_Interface;
實現泛型介面的類
方式1 : 在編寫類的時候實現泛型介面
定義類的時候就確定了泛型的資料型別
public class InterImpl implements Inter<String> {
@Override
public String show(String str) {
return str;
}
}
方式2 :
建立物件的時候,確定泛型的資料型別
InterImpl<QQ> 宣告泛型QQ
implements Inter<QQ> 使用QQ 所代表的資料型別
public class InterImpl<QQ> implements Inter<QQ>{
@Override
public QQ show(QQ str) {
return str;
}
}
泛型介面測試類
public class Test {
public static void main(String[] args) {
//方式2
InterImpl<String> impl = new InterImpl<String>();
String str = impl.show("hehe");
System.out.println(str);
//方式1
InterImpl impl = new InterImpl();
String str = impl.show("haha");
System.out.println(str);
}
}
package cn.itcast_11_Generic;
import java.util.ArrayList;
import java.util.Collection;
泛型萬用字元<?>
任意型別,如果沒有明確,那麼就是Object以及任意的Java類了
? extends E
向上限定,E及其子類
?代表了 可以是E所對應的資料型別,或者是E的子類型別
例如:
? extends Animal
? 代表了 Animal型別,或者Animal子類型別
? super E
向下限定,E及其父類
?代表了 可以使 E所對應的資料型別,或者是E的父類型別
例如:
? super Dog
? 代表的是 Dog型別,或者是Dog的父類型別
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
public class CollectionDemo {
public static void main(String[] args) {
//泛型的資料型別 要求左右一致
//Collection<Object> coll = new ArrayList<Animal>();
//Collection<Animal> coll = new ArrayList<Dog>();
Collection<?> c1 = new ArrayList<Animal>();
Collection<?> c2 = new ArrayList<Dog>();
Collection<?> c3 = new ArrayList<Cat>();
Collection<?> c4 = new ArrayList<Object>();
Collection<?> c10 = new ArrayList<String>();
Collection<?> c11 = new ArrayList<Integer>();
Collection<? extends Animal> c5 = new ArrayList<Animal>();
Collection<? extends Animal> c6 = new ArrayList<Dog>();
Collection<? extends Animal> c7 = new ArrayList<Cat>();
// Collection<? extends Animal> c8 = new ArrayList<Object>(); 因為 Object型別,不是Animal型別或Animal的子型別
Collection<? super Animal> c9 = new ArrayList<Animal>();
// Collection<? super Animal> c10 = new ArrayList<Dog>();// 因為Dog 不是 Animal型別 或者 Animal的父型別
// Collection<? super Animal> c11 = new ArrayList<Cat>();// 因為Cat 不是 Animal型別 或者 Animal的父型別
Collection<? super Animal> c12 = new ArrayList<Object>();
}
}