在解釋泛型的時候先說下java中的可變參數的定義和應用。
定義:參數的類型... 參數名稱
示例:
public class Demo{
public static void main(String args[]){
System.out.println(count(1,2,2,3,4));
}
public static int count(int... temp){//使用可變參數的形式完成需求
int sum=0;
for(int i=0;i<temp.length;i++){
sum+=temp[i];
}
return sum;
}
```
泛型:java的一個新特性,相當于是一個標簽。在集合中大量使用。
在定義一個類的時候如果無法確定某些參數的類型的時候,可以先不去確定參數的類型,先使用一個占位符<T>的形式表示參數類型。等創建對象的時候再具體確定參數的形式。泛型的出現是為了讓運行時的錯誤在編譯時體現出來。讓開發跟快捷。
為什么要用泛型:
package com.zhaoqiang.paradigm;
import java.util.ArrayList;
/*
- 泛型:
- 需求:把一個集合中元素全部轉成大寫
- */
public class Demo1 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("aa");
list.add("bb");
list.add("cc");
list.add(123);
for (int i = 0; i < list.size(); i++) {
String str = (String)list.get(i);
System.out.println("大寫"+str.toUpperCase());
}
}
}
上面的代碼出現了一個異常“ClassCastExcepton”,出現這個異常的根本原因就是int 類型的數據不能轉換成String類型的數據。所有我們需要避免這種錯誤發生在運行時(如果你不聲明泛型,項目內開發的時候,其他人很難知道你這個集合存放的是什么數據類型)
示例:
package com.zhaoqiang.paradigm;
import java.util.ArrayList;
/*
- 泛型:
- 需求:把一個集合中元素全部轉成大寫
- */
public class Demo1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add(123);
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println("大寫"+str.toUpperCase());
}
}
}
上面的代碼在編輯的時候就會出現錯誤(安全警告),因為這個時候集合中只能存放String類型的數據。也避免了無謂的強制類型轉換。
下面介紹一下方法上定義泛型:
修飾符 <聲明自定義的泛型> 返回值類型 函數名(使用自定義泛型){}
示例:
package com.zhaoqiang.paradigm;
/*
- 需求:定義一個方法可以接受任意類型的參數,而且返回值類型必須要與實際參數一致。
- 自定義泛型:
自定義泛型就是一個數據類型的占位符或者是一個數據類型的變量
- 在方法上自定義泛型:
修飾符 <聲明自定義的泛型> 返回值類型 函數名(使用自定義泛型){
}
- 注意:在泛型中不能使用基本數據類型,如果需要使用基本數據類型,那么久使用基本數據類型對于的包裝類型。
- byte --- Byte
- short -- Short
- int ---- Integer
- long --- Long
- double - Double
- float -- Float
- char --- Character
- boolean - Boolean
- 方法泛型注意事項:
1,在方法上自定義泛型,這個自定義泛型的具體數據類型是在調用該方法的時候傳入實參是確定。
2,自定義泛型只要符合標識符的命名規則即可。但是一般習慣自定義泛型的時候使用一個大寫字母表示(T(Type),E(Element))
- */
class Person<T>{
public T say(T t){
return t;
}
}
public class Demo2 {
public static void main(String[] args) {
String str = getData("abc");
System.out.println(str.toUpperCase());
}
public static <T>T getData(T t){
return t;
}
public static <T>Person getInfo(Person<T> p){
return p;
}
public static void getInfo(Person<Integer> p){
System.out.println(p);
}
public static String getInfo(Person<String> p){
return p.say("hah");
}
}
上面的泛型類型是在使用的時候(調用的時候確定泛型的數據類型).
如果一個類里面很多個方法都要用到泛型。我們可以定義一個泛型類:
class 類名<泛型>{}
示例:
class MyArrays<T>{
// 元素翻轉
public void reverse(T[] arr){
for (int startIndex=0, endIndex=arr.length-1; startIndex<endIndex; startIndex++,endIndex--){
T temp = arr[startIndex];
arr[startIndex] = arr[endIndex];
arr[endIndex] = temp;
}
}
public String toString(T[] arr){
StringBuffer sb = new StringBuffer();
for (int i = 0; i < arr.length; i++) {
if (i==0) {
sb.append("["+arr[i]+",");
}else if(i==arr.length-1){
sb.append(arr[i]+"]");
}else{
sb.append(arr[i]+",");
}
}
return sb.toString();
}
// 如果使用靜態修飾了方法,必須要用這種格式。
// 原因:自定義在類上的泛型是不會作用在靜態方法上的
public static <T> void print(T[] t){
}
}
public class Demo3 {
public static void main(String[] args) {
Integer[] arr = {10,15,48,456,742};
MyArrays<Integer> marr = new MyArrays<Integer>();
marr.reverse(arr);
System.out.println(marr.toString(arr));
}
}
通過上面的代碼可以證明開始說的那句話,在類上定義泛型的具體數據類型是在使用該類創建對象的時候確定的。【注】泛型沒有重載。
泛型的上限和下限:
上限:<? extends T>
一旦在方法中指定了泛型的上限,那么該方法只能接收上限所對應的類的子類類型的泛型或者上限對應的本類類型。
下限:<? super T>
一旦設置了下限,那么方法所接受的類型必須是下限所對應的父類及本類類型。
示例:
public class Demo5 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList<Number> list2 = new ArrayList<Number>();
print(list);
print(list);
HashSet<String> set = new HashSet<String>();
ArrayList<String> set1 = new ArrayList<String>();
printl(set1);
printl(set);
}
// 泛型的下限
public static void print(Collection<? super Integer> c){
}
// 泛型的下限
public static void printl(Collection<? extends String> c){
}
}
泛型接口:
interface IAction<T>{//定義一個泛型接口
public T count(T t);
}
class Action<T> implements IAction<T>{
public T count(T t){
return t;
}
}
public class Demo {
public static void main(String[] args) {
System.out.println( new Action<Double>().count(12.0));
}
}