【java基础】java泛型[一]——使用泛型的三种方式

24 篇文章 0 订阅
4 篇文章 0 订阅

一、为啥要使用泛型?

以前没有泛型的时候,泛型的设计时通过继承来实现的。ArrayList只维护一个Object引用的数组,存在了两个问题:

  • 获取一个值时,必须进行强制类型转换
  • 可以向其中添加任何类型的值

而现在,泛型提供了更好的解决方法,使用 {类型参数}:

var files = new ArrayList<String>();
//或
ArrayList<String> files = new ArrayList<>();

二、Java泛型的应用场景

Java泛型分别可以应用在接口、类和方法中,下面将逐个说明:

2.1 泛型类

泛型类相当于普通类的工厂,我们定义一个可以保存一对变量类型为T的泛型类:

package JavaGeneric.GenClass;

/**
 * T is the type that we will deal with
 * 
 * @author Aran
 * @param <T>
 */
public class Pair<T>{
    public T first;
    public T second;

    public Pair() {
    }

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return first;
    }

    public void setFirst(T first) {
        this.first = first;
    }

    public T getSecond() {
        return second;
    }

    public void setSecond(T second) {
        this.second = second;
    }

        
    
}

此时,就可以进行泛型类的调用了:

package JavaGeneric.GenClass;

/**
 * @author Aran
 */
public class Main {
    public static void main(String[] args){
        Pair<String> pairStr = new Pair<>();
        pairStr.setFirst("first");
        pairStr.setSecond("second");

        Pair<Integer> pairInt = new Pair<>();
        pairInt.setFirst(1);
        pairInt.setSecond(2);

        System.out.println(pairStr.getFirst());
        System.out.println(pairInt.getSecond());
    }
   
   
}

上例中,我们调用类两次,分别传入了{String} 和 {Integer} 两个具体类型,并对pairStr的第一个元素和pairInt的第二个元素进行输出,运行以上示例,得到输出:

first
2

2.2 泛型方法

我们先通过一个例子,直观的感受下:

package JavaGeneric.GenMethod;

import JavaGeneric.GenClass.Pair;

public class ArrayAlg {
    
    //调用Pair<T>,计算一个字符串数组中的最大最小值

    public static Pair<String> minAndMax(String[] a){
        //如果数组为空或null,则无法比较
        if(a == null || a.length == 0){
            return null;
        }else{
            //初始化最大、最小值为字符串数组的第一个元素
            String min = a[0];
            String max = a[0];

            for(String s : a){
                if(min.compareTo(s) > 0){
                    //min比s大,交换
                    min = s;
                }
                if(max.compareTo(s) < 0){
                    //max比s 小,交换
                    max = s;
                }
            }
            return new Pair<>(min,max);
        }

    }

    //泛型方法
    public static <T> T getMiddle(T...a){
        return a[a.length / 2 ];
    }

}

ArrayAlg 类中,getMiddle是一个 泛型方法,泛型方法的基本介绍如下:

  • public 与 返回值之间的 非常重要,可以理解为,这样做之后,它才是个泛型方法
  • 泛型类中使用了泛型的成员方法并不是泛型方法
  • 表示该方法将使用泛型类型T,此时可以在方法中使用泛型类型T
  • 与泛型的定义一样,此处T可以随便写为任意标识,常见的T、E、K、V等形式的参数常用于表示泛型。

而对于 minAndMax ,它只是一个返回了一个泛型类的方法,并不是泛型方法。

我们写一个Main进行调用:

package JavaGeneric.GenMethod;

import JavaGeneric.GenClass.Pair;

/**
 * @author Aran
 */
public class Main {
    public static void main(String[] args){
        //定义一个字符串数组
        String[] words = {"Rita","Aran","Lucy","Marray","John"};
        Pair<String> minAndMax = ArrayAlg.minAndMax(words);
        //输出最大最小值
        System.out.println("min = " + minAndMax.getFirst());
        System.out.println("max = " + minAndMax.getSecond());

        //调用非静态泛型方法
        ArrayAlg aa = new ArrayAlg();
        aa.printTheFirst(3);
        aa.printTheFirst("Aran");
        //调用静态泛型方法
        String middle = ArrayAlg.<String>getMiddle("John","Wendy","Amy","Bob");
        System.out.println("middle = " +  middle);
    }
}
 

注意:

 //调用静态泛型方法
        String middle = ArrayAlg.<String>getMiddle("John","Wendy","Amy","Bob");

在这种情况下(实际上也是大多数情况下),方法调用中可以省略类型参数,因为编译器有足够的信息推断出你想要的方法。它将参数的类型与泛型类型T进行匹配,推断出T一定是String,即可以将调用方式改为:

//调用静态泛型方法
        String middle = ArrayAlg.getMiddle("John","Wendy","Amy","Bob");

2.3 泛型接口

对于一个如下的泛型接口:

package JavaGeneric.GenInterface;

public interface Generator<T> {
    T next();
}

对于实现该泛型接口,有两种情况:

未传入泛型实参时:

未传入实参,也就是说,虽然我实现了你,但其实我也是个泛型

package JavaGeneric.GenInterface;

public class MoneyGenerator<T>  implements Generator<T>{

    private T mynext;

    @Override
    public T next() {
        // TODO Auto-generated method stub
        return mynext;
    }
    
}

虽然MoneyGenerator实现了Generator,但它本身也是带T的,如果你不带T,编译器会告诉你“Unknown class”,就是说“没见过你这样连T都不带的”。

传入泛型实参时:

package JavaGeneric.GenInterface;

import java.util.Random;

public class GoldGenerator implements Generator<String> {

    private String[] myGold = new String[]{"one","two","three"};

    @Override
    public String next() {
        // TODO Auto-generated method stub
        Random rand = new Random();
        return myGold[rand.nextInt(3)];
        // return null;
    }
    
}

调用上面的next方法:

package JavaGeneric.GenInterface;

public class Main {
    public static void main(String[] args){
        GoldGenerator gold = new GoldGenerator();
        System.out.println(gold.next());
    }
}

得到结果:

three

总结:

  • 泛型的使用方式有三种:类、方法、接口
  • 泛型类的局限是每次只能操作一种实参类型
  • 泛型方法可以在非泛型类中
  • 泛型接口实现时,如果是T,则实现也必须是T

关于这三种方式的使用,以后学习到更深层次的我会及时更新博客,下面篇文章,我们一起学习下,关于java泛型一些小而美的知识(类型变量的限定、泛型中的限制与局限性、通配符等)。


你喜欢什么不重要,重要的是,你是否有能力去喜欢,是否有尽力去触碰,是否有定力去坚守,是否有魄力去取舍,是否有权力去选择。

—— 大冰《额弥陀福么么么哒》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值