泛型

泛型

一、泛型概念

泛型:JDK1.5以后,使用容器时,必须明确容器中元素的类型。这种机制称之为 :泛型

泛型格式

<数据类型>,这种格式不是很难理解,<> 尖括号也是括号,往括号里面写东西其实就是在传递参数

泛型的好处

(1)安全

(2)将运行时期的异常转为编译时期的异常

(3)避免了强制类型转换的麻烦

二、泛型的使用

1.泛型类的使用

2.泛型方法的使用

// <T>声明有一个泛型 T t 真正使用泛型
class Utils<W>{
    // 泛型在方法上
    public<T> void print(T t,W w){
        // 向下转型成w
        W w1 = (W)new Object();
        System.out.println("print:" + t);
    }

    public static<Q> Q pr(Q q){
        return q;
    }

    // 静态方法使用泛型 -- 用不了类级别的泛型
//    public static<Q> Q pr(Q q,W w){
//        W w = (W)new Object();
//    }
}
public class Demo03 {
    public static void main(String[] args) {
        Utils<String> su = new Utils<String>();
        su.print(12,"Curley G");
        // boolean类型
        boolean pr = su.pr(false);
        System.out.println(pr);
    }
}

3.泛型接口的使用

//  接口
interface Inter<E>{
    void show(E e);
}
// 实现类1 -- 明确类型
class ImplInter1 implements Inter<String>{
    public void show(String s){
        System.out.println("字符串类型:" + s);
    }
}

// 实现类2 -- 不明确类型
class ImplInter2<E> implements Inter<E>{
    public void show(E e){
        System.out.println("不确定类型:" + e);
    }
}

// 测试类
public class Demo04 {
    public static void main(String[] args) {
        // 多态:父类引用指向子类对象
        Inter ir = new ImplInter1();
        ImplInter1 ir1 = new ImplInter1();
        // 多态时泛型限定会有问题
        Inter<String> ir3 = new ImplInter2<String>();
        ir3.show("Curley");
    }
}

4.自定义泛型

// 类 -- Tool
class Tool{
   // 年龄
    private int age;
    
    public int getAge(){
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

// 类 -- Tool1
class Tool1{
   // 年龄
    private int age;
    public int getAge(){
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

// 自定义泛型类 T 只是形式
class ToolPlus<T>{
    // 用泛型类作为类型
    private T t;

    // 泛型是不可以实例化的
    public T getT(){
        // new T();
        // T t = (T)new Object(); //将对象向下转型为泛型
        return t;
    }

    public void setT(T t){
        this.t = t;
    }
}

// 测试类
public class Demo02 {
    public static void main(String[] args) {
        ToolPlus<String> sp = new ToolPlus<>();
        sp.setT("123");
        ToolPlus<Integer> sp1 = new ToolPlus<>();
        sp1.setT(123);
        sp.getT();
        sp1.getT();
    }

}

三、泛型通配符

当使用泛型类或者接口时,传递的具体的类型不确定,可以通过通配符(?)表示。但是一旦使用泛型的通配符机制后,只能使用Object类中的共性方法,集合中元素自身方法无法使用

public class Demo05 {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<Student>();
        list.add(new Student("Curley",22));
        list.add(new Student("Idiot",20));
        list.add(new Student("Daisy",18));

        Set<Worker> set = new HashSet<>();
        set.add(new Worker("A",26));
        set.add(new Worker("B",28));
        set.add(new Worker("C",30));

        // LinkedHashSet 既去重又有序
        Set<String> sets = new LinkedHashSet<>();
        sets.add("a");
        sets.add("b");
        sets.add("c");

        printCollection(list);
        System.out.println();
        printCollection(set);
        System.out.println();
//        printCollection(sets);// 因为它没有继承Person类
    }

    public static void printCollection(Collection<? extends Person> coll){
        Iterator<?> it = coll.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}

四、泛型限定

泛型限定可以这样书写:

? extends Person : 接收Person类型或者Person的子类型。

public static void printCollection(Collection<? extends Person> list) {
	for (Iterator<? extends Person> it = list.iterator(); it.hasNext();) {
			System.out.println(it.next());
		}
	}

上述这种限定称为:限定泛型的上限:? extends E:接收E类型或者E的子类型。

当然有上限,肯定也有泛型的下限:? super E:接收E类型或者E的父类型。

在API中TreeSet集合的构造函数中允许我们传递一个其它集合作为TreeSet集合的构造时的初始化数据,并且对传递的这个集合做了相应的限定。TreeSet(Collection<? extends E> c)

我们知道TreeSet集合在定义时要求必须明确其中存放对象的类型,即TreeSet集合的定义格式如下:

class TreeSet<E>{
		TreeSet(Collection<? extends E> c){}
}

TreeSet集合构造函数要求传递数据类型必须是E的子类类型或者E本身TreeSet集合要保证排序,那么就必须要求在我们创建TreeSet对象是明确的类型本身必须具备比较功能(这个对象要实现Comparable接口),如果我们在创建TreeSet对象时明确数据类型,并且在创建TreeSet时给TreeSet中传递另外一个集合进行初始化,那么这个集合中的对象必须保证和TreeSet对象要求的数据类型保持一致,或者是其子类(只要是其子类,当然就具备比较功能)。所以在设计TreeSet构造函数如果传递集合进行初始化动作,就使用到了泛型的上限

class TreeSet<E>{
		TreeSet(Comparator<? super E> c){}
}

TreeSet集合在定义是要求其中存放的对象类型必须是E类型,当我们给集合传递比较器后,每当给集合中存放元素,都会取出集合中已经存放的元素,并用正要存放元素进行比较。可以用比较器用E本身接收,当然也可以用比较器用E的父类接收,即就形成了多态,这样的话就形成了限定的下限了。

代码体现:

// 类 -- A
public class A {
    private String str;
    // 构造方法
    public A(){

    }
    public A(String str){
        this.str = str;
    }
}

// 类 -- B 继承 A 
class B extends A{
    public B(){

    }
    public B(String str){
        super(str);
    }
    public int compareTo(Object o) {
        return 0;
    }
}

// 类 -- C 继承 B 
class C extends B{
    public C(){}
    public C(String str){
        super(str);
    }
}
// 测试类
public class Demo01 {
    public static void main(String[] args) {
        // 容器1
        List<A> list1 = new ArrayList<A>();
        list1.add(new A("a1"));
        list1.add(new A("a2"));
        list1.add(new A("a3"));
        list1.add(new A("a4"));

        // 容器2
        List<B> list2 = new ArrayList<B>();
        list2.add(new B("b1"));
        list2.add(new B("b2"));
        list2.add(new B("b3"));
        list2.add(new B("b4"));

        // 容器3
        List<C> list3 = new ArrayList<C>();
        list3.add(new C("c1"));
        list3.add(new C("c2"));
        list3.add(new C("c3"));
        list3.add(new C("c4"));

        // B对象始终可以使用
        printCollection1(list2);
        printCollection2(list2);

        // printCollection2(list1);  (<? extends B> B或者B的子类)
        printCollection2(list1);
        // printCollection1(list3);  (<? super B> B的父类或者B)
        printCollection1(list3);

        TreeSet<B> treeSet = new TreeSet<B>(new Comparator<A>(){
            public int compare(A o1, A o2) {
                B b = (B)o1;
                B b2 = (B)o2;
                return b.compareTo(b2);
            }
        });
    }

    // 上限限定 (继承)
    public static void printCollection1(Collection<? extends B> coll){
        Iterator it = coll.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }

    // 下线限定
    public static void printCollection2(Collection<? super B> coll){
        Iterator it = coll.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}

五、自定义线性表

// 接口类
public interface List<E> extends Iterable<E> {
    // 在表尾添加新元素
    public void add(E element);

    // 在指定位置添加新元素
    public void add(int index,E element);

    // 移除指定元素
    public void remove(E element);

    // 移除指定位置元素,并获取旧元素
    public E remove(int index);

    // 获取指定位置元素
    public E get(int index);

    // 替换指定位置元素,并获取旧元素
    public E set(int index,E element);

    // 获取线性表长度
    public int size();

    // 查找指定元素并获取位置
    public int indexOf(E element);

    // 判断是否包含指定元素
    public boolean contains(E element);

    // 判断是否为空
    public boolean isEmpty();

    // 清空线性表
    public void clear();

    // 根据比较器排序
    public void sort(Comparator<E> c);

    // 截取新线性表
    public List<E> subList(int startIndex,int endIndex);
}

public class ArrayList<E> implements List<E>{
    // ArrayList 默认容量大小为10
    private static final int DEFAULT_CAPACITY = 10;
    // 底层的容器
    private E[] value;
    // 有效长度
    private int size;
    // 构造区
    public ArrayList(){
        this(DEFAULT_CAPACITY);
    }
    // 指定容器大小
    public ArrayList(int capacity){
        if(capacity < 0){
            throw new IllegalArgumentException("容量数据错误,初始化失败!");
        }
        value = (E[])new Object[capacity];// 初始化E数组
        size = 0;// 有效长度为0

    }
    // 指定数组E[] -- O(n) n:arr.length
    public ArrayList(E[] arr){
        if(arr == null){
            throw new IllegalArgumentException("数组不能为null!");
        }
        // 创建一个大小arr数组
        value = (E[])new Object[arr.length];
        // 将原数组的值遍历到新数组中
        for(int i = 0; i < arr.length; i++){
            value[i] = arr[i];
        }
        size = arr.length;
    }

    // 在表尾添加新元素 -- O(n) n:size
    public void add(E element) {
        // 扩容
        if(size == value.length){
            resize(value.length + 10);
        }
        // 在有效位置size-1之后添加
        value[size] = element;
        size++;
    }

    // 在指定位置添加新元素 -- O(n) n:有效长度
    public void add(int index, E element) {
        // index的范围是:[0,size-1]
        if(index < 0 || index >= size){
            throw new IndexOutOfBoundsException("下标出错!");
        }
        // 如果容器已满(当有效长度和容器的长度相同时,则满) -- 扩容
        if(size == value.length){
            resize(value.length + 10);
        }
        // 从后面移动,腾出目标位置
        for(int i = size-1;i >= index;i--){
            value[i + 1] = value[i];
        }
        // 目标位置添加
        value[index] = element;
        size++;// 有效长度+1
    }

    // 扩/缩容 -- O(n) n:size
    private void resize(int newCapacity){
        // 创建新数组
        E[] newValue = (E[])(new Object[newCapacity]);
        // 将原数组的内容复制到新数组中
        for(int i = 0;i < size;i++){
            newValue[i] = value[i];
        }
        // 将新数组赋值给原数组
        value = newValue;
    }

    // 移除指定元素 -- O(n) n:size
    public void remove(E element) {
        // 先查询目标元素的位置
        int index = indexOf(element);
        // 下标不符合条件,抛出异常
        if(index < 0){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        // 调用remove() 指定位置删除
        remove(index);
    }

    // 在末尾移除一个元素 -- O(n) n:size
    public E remove(){
        return remove(size - 1);
    }

    // 移除指定位置元素,并获取旧元素 -- O(n) n:size
    public E remove(int index) {
        if(index < 0 || index >= size){
            throw new IndexOutOfBoundsException("下标越界" + index);
        }
        E ret = value[index];// 目标元素E
        for(int i = index+1;i < size;i++){
            value[i-1] = value[i];
        }
        size--;
        // 有效长度是实际容量的1/4,并且容量>默认值
        if(size == value.length/4 && value.length > DEFAULT_CAPACITY){
            // 缩容
            resize(value.length/2);
        }
        return null;
    }

    // 获取指定位置元素
    public E get(int index) {
        if(index < 0 || index > size-1){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        return value[index];
    }

    // 替换指定位置元素,并获取旧元素 -- O(1)
    public E set(int index, E element) {
        if(index < 0 || index >= size){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        // 存储原来的值
        E ret = value[index];
        // 用新值替换旧值
        value[index] = element;
        return ret;
    }

    // 获取线性表有效长度
    public int size() {
        return size;
    }

    // 数组独占:容量
    private int getCapacity(){
        return value.length;
    }

    // 查找元素并获取位置 -- O(n) n:size
    public int indexOf(E element) {
        int index = -1;// 找不到的时候默认返回-1
        for(int i = 0;i < size;i++){
            if(value[i].equals(element)){
                index = i;
            }
        }
        return index;
    }

    // 判断是否包含指定元素 -- O(n)
    public boolean contains(E element) {
        // 找不到返回-1,如果不是-1的话说明元素存在
        return indexOf(element) != -1;
    }

    // 判断是否为空 -- O(1)
    public boolean isEmpty() {
        // 有效长度为0即为空
        return size == 0;
    }

    // 清空线性表 -- O(1)
    public void clear() {
//        E[] newValue = (E[]) (new Object[DEFAULT_CAPACITY]);
//        value = newValue;
        value = (E[]) (new Object[DEFAULT_CAPACITY]);
        size = 0;
    }

    // 根据比较器排序 -- O(log2 n)
    public void sort(Comparator<E> c) {
        if(c == null){
            throw new IllegalArgumentException("参数异常!");
        }
        int j = 0;
        E e = null;
        // 插入排序
        for(int i = 0;i < size; i++){
            e = value[i];
            for(j = i;j > 0 && c.compare(value[j-1],e)>0;j--){
                value[j] = value[j-1];
            }
            value[j] = e;
        }
    }

    // 截取新线性表 -- O(n) n:size
    public List subList(int startIndex, int endIndex) {
        // 开始下标<0,抛出异常
        if(startIndex < 0){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        // 末尾下标大于等于有效长度,抛出异常,endIndex最大为size-1
        if(endIndex >= size){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        // 开始下标>末尾下标,抛出异常
        if(startIndex > endIndex){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        ArrayList<E> es = new ArrayList<>();
        for(int i = startIndex;i <= endIndex;i++){
            // 往新线性表中添加旧线性表的元素
            es.add(value[i]);
        }
        return es;
    }

    // 比较两个数组中的元素是否相等
    public boolean equals(Object o) {
        if(this == o){
            return true;
        }
        // 为空,也返回false
        if(o == null){
            return false;
        }
        if(!(o instanceof ArrayList)){
            return false;
        }
        // 比较
        ArrayList al = (ArrayList) o;
        if(size != al.size){
            return false;
        }
        // 用工具类比较值
        return Arrays.equals(value,al.value);
    }

    // ArrayList 有效个数/容器大小 [x,x,x,x,x]  -- O(n) n:size
    public String toString() {
        StringBuffer sb = new StringBuffer(String.format("ArrayList:%d/%d [",
                size,value.length));
        if(isEmpty()){
            sb.append("]");
        }else{
            for(int i = 0;i < size;i++){
                // 添加元素
                sb.append(value[i]);
                // 如果不是最后一个元素
                if(i != (size-1)){
                    sb.append(",");
                }
                // 是最后一个元素
                else{
                    sb.append("]");
                }
            }
        }
        // 将sb转化为String 并返回
        return sb.toString();
    }

    /**
     * 获取迭代器,创建ArrayListIterator对象
     * @return
     */
    public Iterator iterator() {
        return new ArrayListIterator();
    }
    // 自定义迭代器
    class ArrayListIterator implements Iterator<E> {
        private int cur = 0;// 游标

        // 是否有下一个元素
        public boolean hasNext() {
            return cur < size;
        }
        // 获取下一个元素
        public E next() {
            return value[cur++];
        }
    }
}

// 测试类
public class ArrayListTest {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(10);
        
        // 在表尾添加元素
        list.add("Curley");
        list.add("Idiot");
        list.add("Daisy");
        list.add("Sally");
        list.add("a");
        System.out.println("表尾添加元素:" + list);
       
       // 指定位置添加元素
        list.add(1,"str");
        System.out.println("指定位置添加元素:" + list);
        
        // 移除指定元素
        list.remove("str");
        System.out.println("移除指定元素:" + list);
       
       // 在末尾移除一个元素
        list.remove();
        System.out.println("末尾移除一个元素:" + list);
       
       // 移除指定位置元素
        list.remove(3);
        System.out.println("移除指定位置元素:" + list);
       
       // 获取指定位置元素
        String str = list.get(1);
        System.out.println("获取指定位置元素:" + str);
      
        // 替换指定位置元素
        list.set(1,"ly");
        System.out.println("替换指定位置元素:" + list);
        
        // 获取线性表有效长度
        int length = list.size();
        System.out.println("线性表有效长度:" + length);
       
       // 查找元素并获取位置
        int i = list.indexOf("Curley");
        System.out.println("查找指定元素并获取位置:" + i);
       
       // 判断是否包含指定元素
        boolean flag = list.contains("Idiot");
        System.out.println("是否包含元素:" + flag);
       
       // 根据比较器排序
        list.sort(new Comparator<String>() {
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        System.out.println("排序后:" + list);
        // toString()
        System.out.println("toString():" + list.toString());
        
        // 迭代
        Iterator it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        list.subList(0,2);
        System.out.println(list);

        // 清空
        list.clear();
        System.out.println("清空:" + list);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值