泛型的介绍和使用

1 什么是泛型?通俗的讲就是可以代替其它类型,

为什么要使用泛型?

类似于抽象归类,每个类型都可以使用同一个方法或者类或者接口来调用。

//设置Integer类型的点坐标
class IntegerPoint{
    private Integer x ;       // 表示X坐标
    private Integer y ;       // 表示Y坐标
    public void setX(Integer x){
        this.x = x ;
    }
    public void setY(Integer y){
        this.y = y ;
    }
    public Integer getX(){
        return this.x ;
    }
    public Integer getY(){
        return this.y ;
    }
}
//设置Float类型的点坐标
class FloatPoint{
    private Float x ;       // 表示X坐标
    private Float y ;       // 表示Y坐标
    public void setX(Float x){
        this.x = x ;
    }
    public void setY(Float y){
        this.y = y ;
    }
    public Float getX(){
        return this.x ;
    }
    public Float getY(){
        return this.y ;
    }
}

每个类都是单独的具体的类型,分别只能传入Interger或这Float 型,两个类型的代码基本一样,那么进一步归类

class Object{
    private Object x ;       // 表示X坐标
    private Object y ;       // 表示Y坐标
    public void setX(Object x){
        this.x = x ;
    }
    public void setY(Object y){
        this.y = y ;
    }
    public Object getX(){
        return this.x ;
    }
    public Object getY(){
        return this.y ;
    }

由于Interger和Float都派生自Object,这样可以传入不同的类型,取出时在强制类型转换。

ObjectPoint integerPoint = new ObjectPoint();
integerPoint.setX(new Integer(100));
Integer integerX=(Integer)integerPoint.getX();

但是如果由于不知道传入什么类型,取出的时候强制类型转为其它类型会怎么样?编译时不会报错,但是运行时会报类型转换错误。

那有没有一种办法在编译阶段,即能合并成同一个,又能在编译时检查出来传进去类型不对呢?当然,这就是泛型。

//定义
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());  

可以看到在构造泛型类的实例的时候,先传入相应的类型,取得时候就不会出错了。

总结两点优势:

(1) 使用泛型不用再强制类型转换

(2) 生成实例时传入什么类型,p.setX(new Integer(100))如果传入其它类型会报错。

2 多泛型变量定义及字母规范

(1)多泛型变量定义

如果要传多个泛型变量怎么办?

class MorePoint<T,U,A,B,C>{
}

如上所示,字母大写,并用逗号隔开,并不一定非要用T才可以当作泛型,其它大写字母也可以。

class MorePoint<T,U> {
    private T x;
    private T y;       
 
    private U name;
 
    public void setX(T x) {
        this.x = x;
    }
    public T getX() {
        return this.x;
    }
	…………
    public void setName(U name){
        this.name = name;
    }
 
    public U getName() {
        return this.name;
    }
}
//使用
MorePoint<Integer,String> morePoint = new MorePoint<Integer, String>();
morePoint.setName("harvic");
Log.d(TAG, "morPont.getName:" + morePoint.getName());

使用的时候就可以传多种类型的变量了。

(2)字母规范

  •  E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
  •  K,V — Key,Value,代表Map的键值对
  •  N — Number,数字
  •  T — Type,类型,如String,Integer等等

字母没有特别的定义,只是为了提高可读性。

3 泛型接口定义

上面讲的是泛型类的定义,下面主要介绍泛型接口定义。

interface Info<T>{        // 在接口上定义泛型  
    public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型  
    public void setVar(T x);
}  

定义时也是在接口名后加尖括号。

有两种使用方法,第一种是非泛型类实现该接口,第二种是泛型类实现该接口

class InfoImpl implements Info<String>{	// 定义泛型接口的子类
    private String var ;				// 定义属性
    public InfoImpl(String var){		// 通过构造方法设置属性内容
        this.setVar(var) ;
    }
    @Override
    public void setVar(String var){
        this.var = var ;
    }
    @Override
    public String getVar(){
        return this.var ;
    }
}
 
public class GenericsDemo24{
    public  void main(String arsg[]){
        InfoImpl i = new InfoImpl("harvic");
        System.out.println(i.getVar()) ;
    }
};

非泛型类只能在实现泛型接口时就填充类型,如果要在使用时才填充类型就需要使用泛型类了。

class InfoImpl<T> implements Info<T>{	// 定义泛型接口的子类
    private T var ;				// 定义属性
    public InfoImpl(T var){		// 通过构造方法设置属性内容
        this.setVar(var) ;
    }
    @Override
    public void setVar(T var){
        this.var = var ;
    }
    @Override
    public T getVar(){
        return this.var ;
    }
}
 
public class GenericsDemo24{
    public  void main(String arsg[]){
        InfoImpl<String> i = new InfoImpl<String>("harvic");
        System.out.println(i.getVar()) ;
    }
};

泛型类实现泛型接口,只需要在生成实例的时候传入类型,通过构造函数将类型传给接口。

4 泛型函数的使用

如果我们想单独在一个方法中使用泛型,可以有两种定义方法:

public class StaticFans {
	//静态函数
    public static  <T> void StaticMethod(T a){
        Log.d("harvic","StaticMethod: "+a.toString());
    }
	//普通函数
    public  <T> void OtherMethod(T a){
        Log.d("harvic","OtherMethod: "+a.toString());
    }
}

分别是静态函数和普通函数,使用静态方法,与以往方法的唯一不同点就是在返回值前加上<T>来表示泛型变量。其它没什么区别。

调用方法:

StaticFans.StaticMethod("adfdsa");//使用方法一
StaticFans.<String>StaticMethod("adfdsa");//使用方法二

第一种是隐式调用,直接省去传值类型,不建议使用,不利于维护;第二种是在函数前加上要填充的类型,建议使用;

上面是无返回值的情况,如果有返回值,那么该怎么写?

public class StaticFans {
	//静态函数
    public static <T> T StaticMethod(T a){
        Log.d("harvic","StaticMethod: "+a.toString());
        return a;
    }
	//普通函数
    public  <T> T OtherMethod(T a){
        Log.d("harvic","OtherMethod: "+a.toString());
        return a;
    }
}

直接用T来代替void就可以啦。

如果是返回数组呢?

//定义
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) ;
}  

和返回String[]类型的数组一样,返回泛型数组,就在函数前加上T[ ] 即可。

总结一下,一是什么是泛型?为什么要使用泛型?泛型的使用可以预先填充类型,防止运行时由于类型不匹配导致程序崩溃。

二是泛型类的使用,泛型类后加尖括号<T>,如果多泛型参数,就用逗号隔开<T,U,P>并大写;

三是泛型接口的使用,使用方法也是在接口加尖括号<T>,如果要调用接口,可能有非泛型和泛型类实现接口,泛型类通过构造函数,将泛型填充到接口,非泛型只能在实现接口时填充。

四是泛型函数的使用,在返回类型前加尖括号<T>,声明要填充的类型,也可以省略但不建议这么用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值