Java基础——泛型(一)

本文深入解析Java泛型的概念,包括其解决的问题、好处、擦除与补偿机制,以及在类、方法和接口中的应用。同时,文章提供了泛型通配符的使用技巧,并探讨了泛型限定的上限和下限。最后,通过集合类的选择策略,帮助读者理解不同容器的适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

1.泛型用来解决什么问题?

使用集合类不加<>也可以,但是使用的时候需要注意类型问题,运行时可能出错;而且其后还要进行各种上下转型
           因此,当操作的引用数据类型不确定的时候。那就使用<>。将要操作的引用数据类型传入即可。其实<>就是一个用于接收类型的参数范围。

总的来说,在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用类型。

问题:什么是引用数据类型?

2.好处

  • 1,将运行时期的问题ClassCastException转到了编译时期。
  • 2,避免了强制转换的麻烦。

3.擦除和补偿(感觉怪怪的,不知道1.8是不是更新了)

3.1.擦除

  • 泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。
  • 运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除

为什么擦除呢?

据说->因为为了兼容运行时的类的加载器

3.2.补偿

在运行时,通过获取元素的类型进行转换动作。不用使用者在强制转换了。

二、泛型类

可不可以定义一个工具类,来操作所有对象?这就引入了我们的泛型最重要的应用——泛型类。

在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。

泛型类。什么时候用?当类中的操作的引用数据类型不确定的时候,就使用泛型来表示

使用:

public class Main {

    public static void main(String[] args){
        GenericDemo<Main> mm = new GenericDemo<>();
        mm.set(new Main());
        System.out.println(mm.get());
    }
}

class GenericDemo<T> {
    private T tt;

    public T get(){
        return tt;
    }
    public void set(T obj){
        tt = obj;
    }
}

三、泛型方法

//将泛型定义在方法上,返回值的前面修饰符的后边
public T void show(T tt){
    sout(tt.toString());
}

当方法静态时,不能使用类上定义的泛型。如果静态方法使用泛型,只能像上面这样将泛型定义在方法上。 

发现了缺点:能实现的方法知识Object类的方法

四、泛型接口

interface inter<T>{
    public void show(T tt);
}

class InterDemo implements Inter<String>{
    public void show(String str){
        sout(str);//sout是简写
    }
}

学会了IDEA重构函数快捷键(选中代码块,按下ctrl+alt+M) 


~~~~~~~~~~~~~~~~~~~~补充要点:泛型通配符:?~~~~~~~~~~~~~~~~~~~~~~

public static void printCollection(Collection<?> a){//通配符的使用
    Iterator<?> it = a.iterator();
    
    while(it.hasNext()){
        sout(it.next());
    }
}

和下面这个有啥区别呢? 

    public static <E>void printCollection(Collection<E> a){
        Iterator<E> it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }

 T可以直接拿来当做类来调用方法,?不可以。还有什么区别????可以接着往下看:

通配符的高级用法:

看个例子:

class GenericDemo<T> {
    private T tt;

    public T get(){
        return tt;
    }
    public void set(T obj){
        tt = obj;
    }
//其中A是一个类
    public static void printCollection(Collection<? extends A> a){//注意这里
        Iterator<? extends A> it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}

 

~~~~~~~~~~~~~~~~~~~~~~~~~这就引出了泛型限定~~~~~~~~~~~~~~~~~~~~~~~~~~~


五、泛型限定

1.上限

限定其继承自哪里。就是我们上面刚用到的例子。格式就是下面这样,这里就不再举例。

? extends E;//接收E类型或其子类型。因此叫做上限

什么时候用?

Collection里面的addAll方法: bool addAll(Collection<? extends E> c)表示可以用E类型或其子类。

一般存储元素时使用上限。因为这样取出都是按照上线类型来运算的。不会出现类型安全隐患。

2.下限

? super E;//接收E类型或其父类型。这种叫做下限。

下限什么时候用?

TreeSet中的构造函数:TreeSet(Compator<? super E> compactor)表示根据指定比较器进行排序。

对集合中的元素做取出操作时可以使用下限。用的不多但是不好理解!!!

六、集合查阅技巧

在选择前思考一下:

需要唯一吗?
需要:Set
    需要制定顺序: 
            需要: TreeSet
            不需要:HashSet
            但是想要一个和存储一致的顺序(有序):LinkedHashSet
不需要:List
    需要频繁增删吗?
        需要:LinkedList
        不需要:ArrayList
        
如何记录每一个容器的结构所属体系呢?

看名字!

后缀名就是该集合所属的体系

List
    |--ArrayList
    |--LinkedList

Set
    |--HashSet
    |--TreeSet

前缀名就是该集合的数据结构

  • 看到array:就要想到数组,就要想到查询快,有角标。
  • 看到link:就要想到链表,就要想到增删快,就要想要 add get remove+frist last的方法。
  • 看到hash:就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashcode方法和equals方法。 
  • 看到tree:就要想到二叉树,就要想要排序,就要想到两个接口Comparable,Comparator。

而且通常这些常用的集合容器都是不同步的。 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值