泛型与通配符

泛型

-----------先写一个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>();
泛型的意义
  1. 可以对类型进行自动检查(并不是替换)在编译期间进行检查
  2. 自动对类型进行转换

泛型是怎么编译的呢???
是用了类型的擦除机制,通过向上擦除===》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));
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值