泛型與萬用字元
阿新 • • 發佈:2019-02-11
泛型
-----------先寫一個ObjectStack類實現棧的操作-----------
class ObjectStack{
private Object[] elem;
private int top;
public ObjectStack(){
this(10);
}
public ObjectStack(int size){
this.elem = new Object[size];
this.top = 0;
}
public void push(Object value){
this .elem[this.top++] = value;
}
public void pop(){
--this.top;
}
public Object getTop(){
return this.elem[this.top-1] ;
}
}
public class ObjectStackDemo {
public static void main(String[] args) {
ObjectStack objectStack = new ObjectStack();
objectStack. push(10);
objectStack.push(66.6);
objectStack.push("showLo");
//String str = (String) objectStack.getTop();
//這裡必須強轉,否則會報錯
//對多資料來說很麻煩
//System.out.println(str);
}
}
雖然ObjectStack對元素資料型別沒有限制, 放任何型別的資料進去都會編譯通過,但是都預設為Object型別,所以當我們得到棧頂元素時,返回的是Object類,獲取該元素時需要進行強制轉換。。。。就很麻煩la。。。。。
所以…我們有了泛型~~
emmmmmm…什麼是泛型呢???
就是----------適用於許多許多的型別。
所以上面的例子用泛型來寫就很nice了!!!
class GenericStack<T> {
private T[] elem;
private int top;
public GenericStack() {
this(10);
}
public GenericStack(int size) {
//this.elem = new T[size]; error
this.elem = (T[]) new Object[size];
this.top = 0;
}
public void push(T value){
this.elem[this.top++] = value;
}
public void pop(){
this.elem[this.top-1] = null;
--this.top;
}
public T getTop(){
return this.elem[this.top-1];
}
}
測試
public class GenericStackDemo {
public static void main(String[] args) {
//想用哪種型別就在建立的時候指定該型別
GenericStack<Integer> genericStack = new GenericStack<Integer>();
genericStack.push(10);
//用指定型別以外的型別則會出現錯誤
//genericStack.push("ss"); error
//genericStack.push(10.3); error
int data = genericStack.getTop();
GenericStack<Double> genericStack1 = new GenericStack<Double>();
genericStack1.push(40.3);
//GenericStack<Integer>[] genericStack3 = new GenericStack<Integer>(); error
// 不能new泛型型別的物件陣列
}
}
泛型概述
- 通過泛型可以定義型別安全的資料結構,而無需使用實際的資料型別
- 泛型類和泛型方法具有可重用性、型別安全性和高效性
- 在泛型型別定義中,必須通過指定尖括號中的型別引數來宣告型別。引數型別不是特定的型別,而是型別佔位符
class GenericStack<T>
T只是一個型別的佔位符,表示GenericStack是一個泛型類
- 在建立泛型型別的例項物件時,必須指定尖括號的型別,可以是編譯器識別的任何型別(!!!不能為簡單型別)
GenericStack<Integer> genericStack = new GenericStack<Integer>();
GenericStack<Animal> genericStack2 = new GenericStack<Animal>();
泛型的意義
- 可以對型別進行自動檢查(並不是替換)在編譯期間進行檢查
- 自動對型別進行轉換
泛型是怎麼編譯的呢???
是用了型別的擦除機制,通過向上擦除===》Object類
(在編譯器的編譯期間,把泛型全部擦除為Object型別)
public static void main(String[] args) {
GenericStack<Integer> genericStack = new GenericStack<Integer>();
GenericStack<String> genericStack1 = new GenericStack<String>();
System.out.println(genericStack);
System.out.println(genericStack1);
System.out.println(int.class);
System.out.println(String.class);
System.out.println(GenericStack.class);
}
寫一個通用的演算法,找到陣列當中的最大值
class GenericAlg<T extends Comparable<T>>{
public T findMaxVal(T[] array) {
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
}
測試程式碼
public class Test2 {
public static void main(String[] args) {
Integer[] array ={1,2,3,4,5};
GenericAlg<Integer> genericAlg = new GenericAlg<Integer>();
System.out.println(genericAlg.findMaxVal(array));
Double[] array1 = {3.6,4.8,5.9,6.6,0.9};
GenericAlg<Double> genericAlg1 = new GenericAlg<Double>();
System.out.println(genericAlg1.findMaxVal(array1));
}
}
//5
//6.6
泛型方法
//泛型的上界-----》T extends Comparable<T>
//泛型沒有下界
class GenericAlg2{
public static<T extends Comparable<T>> T findMaxValu(T[] array){
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
}
public class Test2 {
public static void main(String[] args) {
Integer[] array ={1,2,3,4,5};
Double[] array1 = {3.6,4.8,5.9,6.6,0.9};
//T會通過實參的型別推演出泛型型別
System.out.println(GenericAlg2.findMaxValu(array));
System.out.println(GenericAlg2.findMaxValu(array1));
System.out.println(GenericAlg2.<Integer>findMaxValu(array)); //也可在前面指明其型別
}
//5
//6.6
記憶體洩漏
// An highlighted block
var foo = 'bar';
泛型的坑
- 不能new泛型型別的陣列
- eg: new T[];
- 不能new泛型型別的物件
- eg: T obj = new T();
- 不能new 泛型型別的物件陣列
- eg: Object[] obj = new GenericStack[10];
- 不能用簡單型別作為泛型型別的引數
- 一定記得加<泛型型別的引數>,否則就是Object
- 不能 GenericStack genericStack3 = new GenericStack();
- 應該 GenericStack genericStack = new GenericStack();
- 在靜態方法中不能使用泛型型別的引數,因為靜態方法不依賴物件,如果不依賴物件,就不知道這個T是什麼型別,編譯時就不能進行型別檢查
萬用字元(?)
通過擦除機制 ------》 Object
寫一個通用的演算法:列印集合ArrayList內的所有元素
class GenericAlg1{
public static <T> void printList(ArrayList<T> list){
for (T obj : list){
System.out.println(obj + " ");
}
System.out.println();
}
}
public class GenericDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
GenericAlg1.printList(arrayList);
}
}
Integer 繼承 Number , Number 繼承 Object
但是 ArrayList ArrayList ArrayList 三者間不能構成繼承關係
class GenericAlg1{
public static void printList(ArrayList<?> list) {
for (Object obj : list) {
System.out.println(obj + " ");
}
System.out.println();
}
}
public class GenericDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
GenericAlg1.printList(arrayList);
// ArrayList<Object> arrayList1 = new ArrayList<Integer>(); error,不構成繼承關係
}
}
萬用字元的應用
寫一個演算法找集合當中的最大值
比較時報錯,應該怎麼辦呢???
解決辦法如下
class GenericAlg2{
public static <T extends Comparable<T>> T findMaxVal(ArrayList<T> list){
T max = list.get(0);
for (int i = 0; i < list.size(); i++) {
if (max.compareTo(list.get(i)) < 0){
max = list.get(i);
}
}
return max;
}
}
萬用字元的上下界
可以使用 extends 為萬用字元限定上界或使用 super 為萬用字元限定下界
<? extends 基類> //? 限定為指定類或其派生類
<? super 派生類> //? 限定為指定類或其基類
- 萬用字元的上界主要用來寫入
- 萬用字元的下界主要用來讀取
class GenericAlg2{
//萬用字元的下界:找到是不是有T的基類實現了Comparable介面
public static <T extends Comparable<? super T>> T findMaxVal1(ArrayList<T> list){
T max = list.get(0);
for (int i = 0; i < list.size(); i++) {
if (max.compareTo(list.get(i)) < 0){
max = list.get(i);
}
}
return max;
}
//萬用字元的上界 ArrayList<? extends T>
public static <T extends Comparable<T>> T findMaxVal(ArrayList<? extends T> list){
T max = list.get(0);
for (int i = 0; i < list.size(); i++) {
if (max.compareTo(list.get(i)) < 0){
max = list.get(i);
}
}
return max;
}
}
class Person implements Comparable<Person>{//不實現介面main函式呼叫方法時會報錯
private String name;
public Person(String name){
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Person o) {
return name.compareTo(o.name);
}
}
class Student extends Person{
private int age;
public Student(String name,int age){
super(name);
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
public class GenericDemo {
public static void main(String[] args) {
ArrayList<Person> arrayList = new ArrayList<Person>();
arrayList.add(new Person("ss"));
arrayList.add(new Person("qq"));
System.out.println(GenericAlg2.findMaxVal(arrayList));
ArrayList<Student> arrayList1 = new ArrayList<Student>();
arrayList1.add(new Student("ss",8));
arrayList1.add(new Student("qq",18));
System.out.println(GenericAlg2.findMaxVal(arrayList1));
System.out.println(GenericAlg2.findMaxVal1(arrayList1));
}
}