泛型(java)


泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型
泛型也可以看出是一个变量,用来接收数据类型
E e:Element 元素
T t:Type类型
ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型
创建对象的时候,就会确定泛型的数据类型

使用泛型的好处

创建集合对象;不适用泛型
好处:
    集合不使用泛型,默认的数据类型就是Object类型,可以存储任意类型的数据
弊端:
    不安全,会引发异常

创建集合对象,使用泛型
好处:
    1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
    2.把运行期异常(代码运行之后会抛出异常)提升到了编译器(写代码的时候会报错)
弊端:
    泛型是什么类型,只能存储什么类型的数据。

定义和使用含有泛型的类

模拟ArrayList集合
泛型是一个未知的数据类型,当我们不确定使用什么数据类型的时候,可以使用泛型,泛型可以接收任意的数据类型,可以使用Integer,String,Student…
创建对象的时候确定泛型的数据类型

public class DemoGenericClass<E> {//创建一个含有泛型的类
    private E name;
    public E getName(){
        return name;
    }
    public void setName(E name){
        this.name=name;
    }
}
public class MakeGenericClass {//主代码运用泛型,泛型可以随便指定类型
    public static void main(String[] args) {
        DemoGenericClass gc=new DemoGenericClass();
        gc.setName("不写泛型默认为Object类型");
        Object obj=gc.getName();

        //创建DemoGenericClass对象,泛型使用Integer类型
        DemoGenericClass<Integer>gc2=new DemoGenericClass<>();//这就是使用泛型的好处
        gc2.setName(1);
        Integer name=gc2.getName();
        System.out.println(name);

        //创建DemoGenericClass对象,泛型使用String类型
        DemoGenericClass<String>gc3=new DemoGenericClass<>();
        gc3.setName("小明");
        String name1=gc3.getName();
        System.out.println(name1);
    }
}

定义和使用含有泛型的方法

泛型定义在方法的修饰符和返回值类型之间
格式:

修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){
	方法体
}

注意:含有泛型的方法,在调用方法的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型

public class GenericMethod {
    //定义一个含有泛型的方法
    public <M>void method01(M m){//这个泛型的定义随便一个字母都可以,这里是M
        System.out.println(m);
    }
    //定义一个含有泛型的静态方法
    public static<S>void method02(S s){
        System.out.println(s);
    }
}
public class UsegenericMethod {//测试含有泛型的方法
    public static void main(String[] args) {
        //创建GenericMethod对象
        GenericMethod gm=new GenericMethod();
        /*
        调用含有泛型的方法method01
        传递什么类型,泛型就是什么类型
         */
        gm.method01(10);
        gm.method01("abc");
        gm.method01(1.1);
        gm.method01(true);
        gm.method02("静态方法不建议创建对象使用");
        //静态方法,可以直接通过类名.方法名(参数)
        GenericMethod.method02("静态方法");
        GenericMethod.method02(1);
    }
}

输出:
10
abc
1.1
true
静态方法不建议创建对象使用
静态方法
1

定义和使用含有泛型的接口

先定义一个接口

public interface GenericInterface<I> {
    public abstract void method(I i);
}

1.含有泛型的接口,第一种使用方式:定义接口的实现类,实现接口,指定接口的泛型
现有的eg:(可以不管)

public interface Iterator<E>{
	E next();
}

Scanner类实现了Iterator接口,并指定接口的泛型为String,所以重写的next方法泛型默认就是String

public final class Scanner implements Iterator<String>{
	public String next(){}
}

重要
下面是第一种接口实现类的代码演示:(在实现类的方法中就将泛型确定)

public class GenericInterfaceImpl1 implements GenericInterface<String>{
    @Override
    public void method(String s) {
        System.out.println(s);
    }
}

含有泛型的接口第二种使用方式:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走
就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型
现有的eg:(可以不看)

public interface List<E>{
	boolean add(E e);
	E get(int index);
}
public class ArrayList<E> implements List<E>{
	public boolean add(E e){}
	public E get(int index){}
}

重要
下面为定义第二种实现类的创建(实现类还是不把泛型确定,而是在主方法中定义对象的时候在确定泛型)

public class GenericInterfaceImpl2<I> implements GenericInterface<I> {
    @Override
    public void method(I i) {
        System.out.println(i);
    }
}

下面为主方法使用者两种实现类

//测试含有泛型的接口
public class UsegenericInterface {
    public static void main(String[] args) {
        //创建一个GenericInterfaceImpl1对象
        GenericInterfaceImpl1 gi1=new GenericInterfaceImpl1();
        gi1.method("字符串");
        //创建GenericInterfaceImpl2对象
        GenericInterfaceImpl2<Integer> gi2=new GenericInterfaceImpl2<>();
        gi2.method(10);
    }
}

输出:
字符串
10

泛型的通配符

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
通配符的基本使用
不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符
此时只能接收数据,不能往集合中存储数据。
就是说:
泛型的通配符:
    ?:表示任意的数据类型
使用方式:
    不能创建对象使用
    只能作为方法的参数使用
代码细讲

public class 通配符 {
    public static void main(String[] args) {
        ArrayList<Integer>list01=new ArrayList<>();//定义的时候不能直接使用泛型
        list01.add(1);
        list01.add(2);
        ArrayList<String>list02=new ArrayList<>();
        list02.add("a");
        list02.add("b");

        printArray(list01);
        printArray(list02);
    }
    //定义一个方法,能遍历所有类型的ArrayList集合
    //这时候我们不直到ArrayList集合使用什么数据类型,可以使用泛型的通配符?来接收数据类型
    //下面<>内不能写Object,泛型是没有继承概念的,要想01和02类型都不报错就直接?
    public static void printArray(ArrayList<?> list){
        //使用迭代器遍历
        Iterator<?> it=list.iterator();//集合是什么类型,迭代器的泛型就是什么类型
        while(it.hasNext()){
            //it.next()方法,取出的元素是Object,可以接收任意的数据类型
            Object o = it.next();
            System.out.println();
        }
    }
}

通配符的高级使用—受限泛型

这个东西工作中用的不多,只要能看懂就行了
泛型的上限:
格式:类型名称<? extends 类> 对象名称代表使用的泛型只能是E类型的子类/本身
意义:只能接收该类型及其子类
泛型的下限:
格式:类型名称<? super 类>对象名称代表使用的泛型只能是E类型的父类/本身
意义:只能接收该类型的父类

public class LimitGeneric {
    public static void main(String[] args) {
        Collection<Integer> list1=new ArrayList<Integer>();
        Collection<String> list2=new ArrayList<String>();
        Collection<Number> list3=new ArrayList<Number>();
        Collection<Object> list4=new ArrayList<Object>();
        getElement1(list1);
        getElement1(list2);//报错
        getElement1(list3);
        getElement1(list4);//报错

        getElement2(list1);//报错
        getElement2(list2);//报错
        getElement2(list3);
        getElement2(list4);
        //类与类之间的继承关系
        //Integer extends Number extends Object
        //String extends Object
    }
    //泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
    public static void getElement1(Collection<? extends Number> coll){}
    //泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
    public static void getElement2(Collection<? super Number> coll){}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值