泛型的基本使用

转载:
https://blog.csdn.net/harvic880925/article/details/49872903
https://www.bilibili.com/video/BV1eF411h7A5?p=3&share_medium=android&share_plat=android&share_session_id=0933dced-f38b-4439-8e49-f7e4c236828a&share_source=WEIXIN&share_tag=s_i&timestamp=1641741952&unique_k=jJ7NQeb

java中ArrayList就是一个泛型。泛型使用的引用类型,所以在定义泛型类型的时候不能为基本类型,如List 等,只能为List ,编译器在编译的时候会进行类型擦除
泛型类型定义的字母,任意一个大写字母都可以。他们的意义是完全相同的,但为了提高可读性,大家还是用有意义的字母比较好,一般来讲,在不同的情境下使用的字母意义如下:
E — Element,常用在java Collection里,如:List,Iterator,Set
K,V — Key,Value,代表Map的键值对
N — Number,数字
T — Type,类型,如String,Integer等等
如果这些还不够用,那就自己随便取吧,反正26个英文字母呢。
再重复一遍,使用哪个字母是没有特定意义的!只是为了提高可读性!!!!

使用泛型的好处

上一节只是讲解了泛型的引入,那么泛型带来了哪些好处呢?

  • 将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
  • 避免了类型强转的麻烦。

一.泛型类和泛型方法

泛型,用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。

定义和使用泛型的类

定义格式:

修饰符 class 类名<代表泛型的变量> {  }

例如,API中的ArrayList集合:

class ArrayList<E>{ 
    public boolean add(E e){ }

    public E get(int index){ }
   	....
}

使用泛型类
使用的时候必须要声明使用的泛型的具体类型,如下
List list = ……,Integer str = ……,String str=……;

List<String> list = new ArrayList<>();
list.add("qqq");
String str =list.get(0);



List<Integer> list = new ArrayList<>();
list.add(0);
Integer str  = list.get(0)

使用泛型: 即什么时候确定泛型。
在创建对象的时候确定泛型

例如,ArrayList<String> list = new ArrayList<String>();
ArrayList 表示定义的是个ArrayList 类型的具体类型为String,add(E e) ,类型E 和ArrayList 类型一致,表示是String类型;在定义类变量类型的时候就已经定义好了

示例二 定义泛型类
public class GenericsClassDto<T> {
    private T t;
    public void setParam(T t){
        System.out.println("GenericsClassDto.getParam:"+t);
    }

    public T getParam(T t){
        System.out.println("GenericsClassDto.getParam:"+t);
        return t;

    }
}

使用泛型类
在这里插入图片描述

泛型的方法

泛型方法可以优化泛型类在使用到时候声明的啰嗦的问题;省略先定义泛型类变量的问题;
定义格式:

修饰符 <代表泛型的变量> 返回值类型 方法名(参数){  }
public class MyGenericMethod {	
  
    public <MVP> void show(MVP mvp) {
    	System.out.println(mvp.getClass());
	
    }
    
    public <MVP> MVP show2(MVP mvp) {	
    	return mvp;
    }
}

表示 修饰符泛型的变量类型 ,有了代表泛型的变量 ,就不要在类名后面进行声明变量了,这也是和泛型类的区别之一

使用格式:调用方法时,确定泛型的类型

public class GenericMethodDemo {
    public static void main(String[] args) {
        // 创建对象,
        MyGenericMethod mm = new MyGenericMethod();
        // 演示看方法提示
        mm.show("aaa");
        mm.show(123);
        mm.show(12.45);
        //编译器会自动推断出类型为double类型
var tt= mm.show(12.45); 
    }
}
示例二

定义泛型方法

public class GenericsMethodDto {

    public<T,M> T setParam(T t, M m){
        System.out.println("GenericsClassDto.getParam t:"+t);
        System.out.println("GenericsClassDto.getParam k:"+m);
        return t;
    }

    public<T,V,K> List getParam(T t, V v){
        List list = new ArrayList();
        System.out.println("GenericsClassDto.getParam t:"+t);
        System.out.println("GenericsClassDto.getParam v:"+v);
        if(t instanceof String){
            list.add(t);
        }
        if(t instanceof Integer){
            list.add(v);
        }
        return list;
    }
}

使用泛型方法

在这里插入图片描述

泛型类和泛型方法的区别

定义上的区别

泛型类,在定义的时候需要在类上声明方法中含有的 泛型类变量
如: 修饰符 class 类名<代表泛型的变量>

class ArrayList<E>{ 
    public boolean add(E e){ }

    public E get(int index){ }
   	....
}

泛型方法

修饰符 <代表泛型的变量> 返回值类型 方法名(参数){  }

<代表泛型的变量> 有了这块的泛型类型声明就不需要在类名后再此声明泛型变量

https://www.bilibili.com/video/BV1eF411h7A5?p=3&share_medium=android&share_plat=android&share_session_id=0933dced-f38b-4439-8e49-f7e4c236828a&share_source=WEIXIN&share_tag=s_i&timestamp=1641741952&unique_k=jJ7NQeb

泛型类和泛型方法在使用上的区别

泛型类必须要在使用时候定义好泛型类
使用的时候必须要声明使用的泛型的具体类型,如下
List list = ……,Integer str = ……,String str=……;

泛型方法
可以不需要在类型定义时定义这些

泛型的接口

修饰符 interface接口名<代表泛型的变量> { }

定义格式:

修饰符 interface接口名<代表泛型的变量> {  }

例如,

public interface MyGenericInterface<E>{
	public abstract void add(E e);
	
	public abstract E getE();  
}

使用格式:

1、定义类时确定泛型的类型

例如

public class MyImp1 implements MyGenericInterface<String> {
	@Override
    public void add(String e) {
        // 省略...
    }

	@Override
	public String getE() {
		return null;
	}
}

此时,泛型E的值就是String类型。

泛型类,泛型方法,泛型接口总结

<T> 加在哪个位置就是哪种类型,加载泛型接口上就是泛型接口,加载方法返回值前就是泛型方法,加载类名后就是泛型类

示例二

定义泛型接口

/**
 * <T>加在哪里就是哪种类型
 * 加载泛型接口类上就是泛型接口类
 * 加载方法返回值前就是泛型方法
 * @param <T>
 */

public interface GenericsInterface<T> {

    public void setParam(T t);


    /**
     * 泛型方法
     * @param m
     * @param <M>
     * @return
     */
    public<M> M getParam(M m);
    
}

泛型接口的实现类
在这里插入图片描述
调用泛型接口
在这里插入图片描述
在实现的时候也需要在泛型接口类后面指定具体的类型;

2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型

例如

public class MyImp2<E> implements MyGenericInterface<E> {
	@Override
	public void add(E e) {
       	 // 省略...
	}

	@Override
	public E getE() {
		return null;
	}
}

确定泛型:

/*
 * 使用
 */
public class GenericInterface {
    public static void main(String[] args) {
        MyImp2<String>  my = new MyImp2<String>();  
        my.add("aa");
    }
}

泛型的使用一

1、泛型类定义及使用

//定义  
class Point<T>{// 此处可以随便写标识符号  
   //定义泛型属性 
    private T x ;        
    private T y ; 
    
   //定义泛型方法       
    public void setX(T x){//作为参数  
        this.x = x ;  
    }  
    public void setY(T y){  
        this.y = y ;  
    }  
    public T getX(){//作为返回值  
        return this.x ;  
    }  
    public T getY(){  
        return this.y ;  
    }  
};  

泛型类的确定
泛型的类型的确定在创建类的时候确定,无论是泛型方法还是泛型属性,在泛型类的时候都需要在泛型类的类名后添加

//IntegerPoint使用  
Point<Integer> p = new Point<Integer>() ;   
p.setX(new Integer(100)) ;   
System.out.println(p.getX());    
  
//FloatPoint使用  
//创建泛型类
Point<Float> p = new Point<Float>() ;
//调用泛型类的方法   
p.setX(new Float(100.12f)) ;  
 
System.out.println(p.getX());
泛型的使用案例2
@Data
public class Persion<T, E, Y,M> {

    private T message;

    private Y area;

    public void save(E filter) {
        System.out.println(message);
        System.out.println(area);
        System.out.println(filter);

    }
    public M query(E filter) {

       return (M) filter;

    }
}

泛型的使用

public class GenericTest {

    public static void main(String[] args) {

        Persion<String,Integer,String,String>  persion = new Persion<>();

        persion.setArea("陕西");
        persion.setMessage("商务办公");
        persion.save(1);
        //创建了泛型类,泛型的入参已经确定了
        //persion.save("aa");//报错

        String   stringResult =persion.query(2);
        //在创建类型的时候,泛型类的泛型参数,泛型返回值都已经去确定,因此报错
       // Integer    intergetResult =persion.query(2);  //报错

        Persion<String,String,String,Integer>  man = new Persion<>();
        man.save("aa");//报错

        Integer  intergetResult =man.query("2");  //报错
        System.out.println( persion.query(2));

    }
}

泛型方法的使用三

有时候泛型类和泛型方法中含有泛型的参数和返回值,类,也可以不定义为泛型

public class GenericTest {
    //有返回值
    public  <T,M>   M StaticMethod(T a){
        System.out.println("harvic StaticMethod: "+a.toString());
        return (M) a;
    }
    //无返回值
    public <T>  void OtherMethod(T a){
        System.out.println("harvicOtherMethod: "+a.toString());
    }
    public static void main(String[] args) {
        GenericTest genericTest = new GenericTest();
        genericTest.OtherMethod("123");
        }
   }

在方法修饰符后定义泛型的参数和返回类型public <T,M>,这个样就不用在类名后跟泛型标识<T,M>

二.泛型接口和泛型方法

方式一
1.定义 泛型接口

public interface CorPorration<T,R> {

    public R queryCorPorrationNum(T  filter);
}

2.定义泛型接口的实现类

public class CorPorrationImpl implements CorPorration<String,Integer>{
    @Override
    public Integer queryCorPorrationNum(String filter) {
        return 5;
    }
}```

3.调用定义好的泛型接口

```java
 CorPorration<String,Integer> corPorration = new CorPorrationImpl();
   Integer  num= corPorration.queryCorPorrationNum("1233");

泛型的类型确定在,实现类中已经定义好了

方式二

1.定义泛型接口

public interface CorPorration<T,R> {
    public R queryCorPorrationNum(T  filter);
}

2、定义泛型的实现类

public class CorPorrationTwoImpl<T,R> implements CorPorration<T,R>{
    @Override
    public R queryCorPorrationNum(T filter) {
        return (R) filter;
    }
}

泛型类型的实现如果还是泛型,则要在类名称后跟上<T,R>

三、泛型类的创建

CorPorration<String,Integer> corPorrationTwo = new CorPorrationTwoImpl();
Integer  numTwo= corPorrationTwo.queryCorPorrationNum("1233");

泛型类型的确定在创建类的时候

泛型类型返回值

上面我们的函数中,返回值都是void,但现实中不可能都是void,有时,我们需要将泛型变量返回,比如下面这个函数:

静态方法中也可以含有泛型如下,静态类型中含有的泛型da

public class GenericTest {

    public static <T> List<T> parseArray(String response,Class<T> object){
        List<T> modelList = JSON.parseArray(response, object);
        return modelList;
    }

函数返回值是List类型。至于传入参数Class object的意义,我们下面会讲。这里也就是想通过这个例子来告诉大家,泛型变量其实跟String,Integer,Double等等的类的使用上没有任何区别,T只是一个符号,可以代表String,Integer,Double……这些类的符号,在泛型函数使用时,直接把T看到String,Integer,Double……中的任一个来写代码就可以了。唯一不同的是,要在函数定义的中在返回值前加上标识泛型;

静态方法中的类型和参数可以是泛型,在定义类的时候不需要是在类名称后跟上泛型参数;

其它用法:Class类传递及泛型数组

有时候需要传递Class类的泛型,示例如下
首先,我们应该把SuccessModel单独抽出来做为泛型变量,但parseArray()中用到的SuccessModel.class要怎么弄呢?
先来看代码


public static List<SuccessModel> parseArray(String response){
    List<SuccessModel> modelList = JSON.parseArray(response, SuccessModel.class);
    return modelList;

使用泛型后如下,传递Class 类型的 class 泛型如下


public static <T> List<T> parseArray(String response,Class<T> object){
    List<T> modelList = JSON.parseArray(response, object);
    return modelList;
}

泛型类、泛型接口整合类
模仿List 泛型接口实现

泛型接口定义

在这里插入图片描述

泛型接口的实现

在这里插入图片描述
接口调用
在这里插入图片描述

泛型数组

在写程序时,大家可能会遇到类似String[] list = new String[8];的需求,这里可以定义String数组,当然我们也可以定义泛型数组,泛型数组的定义方法为 T[],与String[]是一致的,下面看看用法:

//定义
public static <T> T[] fun1(T...arg){  // 接收可变参数  
       return arg ;            // 返回泛型数组  
}  
//使用
public static void main(String args[]){  
       Integer i[] = fun1(1,2,3,4,5,6) ;
       Integer[] result = fun1(i) ;
}  

我们先看看 定义时的代码:

public static <T> T[] fun1(T...arg){  // 接收可变参数  
       return arg ;            // 返回泛型数组  
}  

首先,定义了一个静态函数,然后定义返回值为T[],参数为接收的T类型的可变长参数。如果有同学对T…arg的用法不了解,可以去找下JAVA 可变长参数方面的知识。
由于可变长参数在输入后,会保存在arg这个数组中,所以,我们直接把数组返回即可。

三.泛型的通配符

当使用类或者泛型接口的时候,传递的参数中,泛型的类型不确定可以通过通配符<?>表示。但是一旦使用通配符后,只能使用Objecct类的共性方法,集合中元素自身的方法无法使用;

在这里插入图片描述
?代表任意待待确定的类型,只能使用Object的方法,同时List<?> 定义变量只能遍历,不能添加和修改;许多源码中也这样使用,告诉读者集合不存在方法内修改和添加;

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/cef6c504a7404942a52ae7ac2fba3f75.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oeS6bif5LiA5p6a,size_20,color_FFFFFF,t_70,g_se,x_16

通配符的基本使用

泛型的通配符不知道用什么类型来接受的时候,此时可以使用?表示未知通配符;此时只能接受数据不能往该集合中存储数据。

ist<?> , ?通配符定义的变量只能遍历不能修改

在这里插入图片描述

泛型擦除机制

所谓的泛型擦除机制是指

将 一个List 集合赋值给一个没有使用到泛型集合,直接使用泛型擦除机制

泛型是在编译阶段限制类型传递的,在运行阶段都是擦除底层class 文件在运行里面是没有泛型

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值