泛型 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 泛型的理解和好處 看一個需求 請編寫程式,在ArrayList中,添加3個Dog對象 Dog對象含有name和age,並輸出name和age(要求使用getXxx()) 先使用傳 ...
泛型
筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html)
泛型的理解和好處
看一個需求
-
請編寫程式,在ArrayList中,添加3個Dog對象
-
Dog對象含有name和age,並輸出name和age(要求使用getXxx())
先使用傳統的方法來解決->引出泛型
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(new Dog("旺財", 10));
arrayList.add(new Dog("發財", 1));
arrayList.add(new Dog("小黃",5));
//假如我們的程員,不小心,添加了一隻貓
arrayList.add(new Cat("招財貓",8));
//遍歷
for (Object o : arrayList) {
//向下轉型0bject ->Dog
Dog dog = (Dog)o;
System.out.println(dog.getName() + "-" + dog.getAge());
}
}
使用傳統方法的問題分析
- 不能對加入到集合ArrayList中的數據類型進行約束(不安全)
- 遍歷的時候,需要進行類型轉換,如果集合中的數據量較大,對效率有影響
泛型快速體驗險-用泛型來解決前面的問題
看演示
ArrayList<Dog> arrayList = new ArrayList<Dog>();
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
//使用傳統的方法來解決===>使用泛型
// 解讀
//1.當我們ArrayList<Dog>表示存放到 ArrayList集合中的元素是Dog類型〔細節後面說...)
// 2。如果編譯器發現添加的類型,不滿足要求,就會報錯
//3。在遍歷的時候,可以直接取出 g類型而不是 Object
ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺財", 10));
arrayList.add(new Dog("發財", 1));
arrayList.add(new Dog("小黃", 5));
//假如我們的程式員,不小心,添加了一隻貓
// arrayList.add(new Cat("招財貓",8));//加入Dog類型外的對象會報錯,編譯不通過
System.out.println("===使用泛科===");
for (Dog dog : arrayList) {
System.out.println(dog.getName() + "-" + dog.getAge());
}
}
}
class Dog {
public String name;
public int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Dog [name=" + name + ". age=" + age + "]";
}
}
泛型的好處
-
編譯時,檢查添加元素的類型,提高了安全性
-
減少了類型轉換的次數,提高效率[說明]
√不使用泛型
Dog-加入->Object -取出->Dog //放入到ArrayList 會先轉成Object,在取出時,還需要轉換成Dog√使用泛型
Dog -> Dog -> Dog //放入時,和取出時,不需要類型轉換,提高效率
-
不再提示編譯警告
泛型介紹
int a = 10;
老韓理解:泛(廣泛)型(類型)=> Integer, String,Dog
-
泛型又稱參數化類型,是Jdk5.0出現的新特性,解決數據類型的安全性問題
-
在類聲明或實例化時只要指定女好需要的具體的類型即可。
-
Java泛型可以保證如果程式在編譯時沒有發出警告,運行時就不會產生ClassCastException異常。同時,代碼更加簡潔、健壯
-
泛型的作用是:可以在類聲明時通過一個標識表示類中某個屬性的類型,或者是某個方法的返回值的類型,或者是參數類型。[有點難,舉例]
public class Test {
public static void main(String[] args) {
Person<String> person = new Person<String>("韓順平教育");
}
}
class Person<E> {
E s;//E表示s的數據類型,該數據類型在定義Person對象的時候指定,即在編譯期間,就確定E是什麼類型
public Person(E s) {//E也可以是參數類型
this.s = s;
}
public E f() {//返回類型使用E
return s;
}
}
泛型語法
泛型的聲明
interface 介面<T>{}和class 類<K,V>{}
//比如: List , ArrayList
說明:
- 其中,T,K,V不代表值,而是表示類型。
- 任意字母都可以。常用T表示,是Type的縮寫
泛型的實例化:
要在類名後面指定類型參數的值(類型)。如:
- List<String> strList = new ArrayList<>();[舉例說明]
- Iterator<Customer> iterator = customers.iterator():
泛型使用的註意事項和細節
- interface List<T>{} , public class HashSet<E>{}..等等
說明:T,E只能是引用類型
看看下麵語句是否正確?:
List<Integer> list = new ArrayList<Integer>();//OK
List<int> list2 = new ArrayList<int>();//錯誤
-
在指定泛型具體類型後,可以傳入該類型或者其子類類型
-
泛型使用形式
List<lnteger> list1 =new ArrayList<lnteger>();List<lnteger> list2 = new ArrayList<>(); (簡寫,推薦使用)
-
如果我們這樣寫List list3 = new ArrayList(); 預設給它的泛型是[<E>E就是Object]
即:List<Object> list3 = new ArrayList<>();
自定義泛型
泛型類(難點)
基本語法
class 類名<T,R...>{//...表示可以有多個泛型成員
}
註意細節
- 普通成員可以使用泛型(屬性、方法)
- 使用泛型的數組,不能初始化
- 靜態方法中不能使用類的泛型
- 泛型類的類型,是在創建對象時確定的(因為創建對象時,需要指定確定類型)
- 如果在創建對象時,沒有指定類型,預設為Object
//解讀
//1. Tiger後面泛型,所以我們把 Tiger就稱為自定義泛型類
//2. T,R,M泛型的標識符,一般是單個大寫字母
//3.泛型標識符可以有多個.
//4.普通成員可以使用泛型(屬性、方法)
//5. 使用泛型的數組,不能初始化
//6. 靜態方法中不能使用類的泛型
class Tiger<T, R, M> {
String name;
R r;//屬性使用到泛型
M m;
T t;
//因為new T[8]在編譯時就需要獲得T類型,而數組在new不能確定T的類型,就無法在記憶體開空間
T[] ts=new T[8];//編譯不通過
public Tiger(String name, R r, M m, T t) {
this.name = name;
this.r = r;
this.m = m;
this.t = t;
}
//因為靜態是和類相關的,在類增載時,對象還沒有創建
//所以,如果靜態方法和靜態屬性使用了泛型,JVM就無法完成初始化
static R r2;
public static void m1(M m) {
}
public M getM() {
return m;
}
public T getT() {
return t;
}
}
泛型介面
自定義泛型介面
基本語法
interface 介面名<T,R..>{
}
註意細節
- 介面中,靜態成員也不能使用泛型(這個和泛型類規定一樣)
- 泛型介面的類型,在繼承介面或者實現介面時確定
- 沒有指定類型,預設為Object
//演示
//在繼承介面指定泛型介面的類型
interface IA extends IUsb<String,Double>{
}
//當我們去實現IA介面時,因為IA在繼承IUsu介面時,指定了U為String R為Double
//,在實現IUsu介面的方法時,使用String替換U,是Double替換R
class AA implements IA{
@Override
public Double get(String s) {
return null;
}
@Override
public void hi(Double aDouble) {
}
@Override
public void run(Double r1, Double r2, String u1, String u2) {
}
}
interface IUsb<U, R> {
int n = 10;
//U name;不能這樣使用
//普通方法中,可以使用介面泛型
R get(U u);
void hi(R r);
void run(R r1, R r2, U u1, U u2);
//在jdk8中,可以在介面中,使用預設方法,也是可以使用泛型
default R method(U u) {
return null;
}
}
泛型方法
自定義泛型方法
基本語法
修飾符<T,R..> 返回類型 方法名(參數列表){
}
註意細節
-
泛型方法,可以定義在普通類中,也可以定義在泛型類
-
當泛型方法被調用時,類型會確定
-
public void eat(E e){},修飾符後沒有<T,R..> eat
方法不是泛型方法,而是使用了泛型
public class Test {
public static void main(String[] args) {
Car car = new Car();
car.fly("寶馬", 100);//當調用方法時,傳入參數,編譯器,就會確定類型
car.fly(300, 100.1);//當調用方法時,傳入參數,編譯器,就會確定類型
}
}
//泛型方法,可以定義在普通類中,也可以定義在泛型類中
class Car {//普通類
public void run() {//普通方法
}
//說明泛型方法
//1.<T,R>就是泛型
// 2.是提供給 fly使用的
public <T, R> void fly(T t, R r) {//泛型方法
System.out.println(t.getClass());//String
System.out.println(r.getClass());//Integer
}
}
class Fish<T, R> {//泛型類
public void run() {//普通方法
}
public <U, M> void eat(U u, M m) {//泛型方法
}
//說明
//1. 下麵hi方法不是泛型方法
//2.是hi方法使用了類聲明的泛型
public void hi(T t) {
}
//泛型方法,可以使用類聲明的泛型,也可以使用自己聲明泛型
public <K> void hello(R r, K k) {
}
}
泛型繼承和通配符
泛型的繼承和通配符說明
- 泛型不具備繼承性
List<Object> list = new ArrayList<String>();//錯誤 - :支持任意泛型類型
- :支持A類以及A類的子類,規定了泛型的上限
- :支持A類以及A類的父類,不限於直接父類,規定了泛型的下限
//舉例
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Object> objects = new ArrayList<>();
printCollection2(objects);//因為Object不是AA的子類,所以 報錯
List<BB> bb = new ArrayList<>();
printCollection2(bb);//因為BB是AA的子類,所以 正常
}
// ? extends AA 表示上限,可以接受AA或者AA子類
public static void printCollection2(List<? extends AA> c) {
for (Object object : c){
System.out.println(object);
}
}
}
class AA{
}
class BB extends AA{
}
JUnit
為什麼需要JUnit
- 一個類有很多功能代碼需要測試,為了測試,就需要寫入到main方法中
- 如果有多個功能代碼測試,就需要來回註銷,切換很麻煩
- 如果可以直接運行一個方法,就方便很多,並且可以給出相關信息,就好了-> JUnit
基本介紹
-
JUnit是一個Java語言的單元測試框架
-
多數Java的開發環境都已經集成了JUnit作為單元測試的工具
使用步驟
註意:使用之前程式中不能含有自定義的Test類。否則會出現衝突
第一次添加(在需要運行的方法上方添加@Test,後續步驟如下圖所示)
後續使用只需要 import該Test