java详解泛型_Java泛型详解

泛型

泛型由来

泛型字面意思不知道是什么类型,但又好像什么类型都是。看前面用到的集合都有泛型的影子。

public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable {

...

}

以ArrayList为例,它为什么要写成ArrayList这样.我也不知道他为什么要写成这样,但是我知道如果它不用泛型,那代码就乱了,那也别写代码了。

ArrayList运用泛型可以这么写

ArrayList strings = new ArrayList<>();//可以存String

ArrayList integers = new ArrayList<>();//可以存Integer类型

ArrayList objects = new ArrayList<>();//可以存对象

ArrayList没用泛型之后:

如果要存放各种各样的样类型,是不是意味着写各种各样对象的链表,那开发者可以不用活了...咦,或者你可以可不用死了,你发现所有类都继承自Object类,那只要这么写一个

step1.png?raw=true

在取出元素的时候强转成对应的类型就可以了,是的,这样就可以不会被写代码累死了。但为什么源码没有这么写,因为它没泛型强大!让我们看下面代码了解泛型的由来。

假如我要写一个类存放一个int类型的模型,那简单

public class IntegerFun {

private int data;

public int getData() {

return data;

}

public void setData(int data) {

this.data = data;

}

}

满足你的需求,但需求变了,我还要一个存放String类型的,那你也忍了,再来一个

public class StringFun {

private String data;

public String getData() {

return data;

}

public void setData(String data) {

this.data = data;

}

}

需求又添加了一个,存放Long、Student、Math.....于是撕逼开始...结束之后,这次你聪明了,写了一个万能的,管它存放什么都行的类:

public class ObjectFun {

private Object data;

public Object getData() {

return data;

}

public void setData(Object data) {

this.data = data;

}

}

这样总算解决了问题,看用法:

step2.png?raw=true

你总觉得你写的前无故人,后无来者了,可是经理还是过来找你了,因为你的程序跑不起来了,你认真的看了一下,发现代码第十五行,存放的是Integer 结果你转成了Float出错了,那你可能会抱怨编译器

没有立即告诉你这里存在问题,接下来我们来看看运用泛型会怎么样。

public class Fun {

private T data;

public T getData() {

return data;

}

public void setData(T data) {

this.data = data;

}

}

用法:

step3.png?raw=true

这就是使用泛型的原因.

多泛型

上面写的还不够全,因为Fun只能存放一种类型的元素,假如我要存放多种呢,我希望你已经会了,再来一个泛型。

/**

* 泛型类

*

* @param 泛型T

* @param 泛型V

*/

public class Fun {

private T data;

private V data2;

//泛型方法

public T getData() {

return data;

}

public void setData(T data) {

this.data = data;

}

public V getData2() {

return data2;

}

public void setData2(V data2) {

this.data2 = data2;

}

}

要存放无数个呢.....

Fun{

}

泛型规范

T1,T2,T3,.......泛型可以随便写吗,可以随便写,但我们追求规范。

E — Element,常用在java Collection里,如:List,Iterator,Set

K,V — Key,Value,代表Map的键值对

N — Number,数字

T — Type,类型,如String,Integer等等

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

泛型接口

/**

* 格式:接口名后面跟

*

* @param

*/

public interface IManager {

void add(T data);

T remove(int index);

void sop();

}

泛型类(之前的都是)

泛型类实现泛型接口(关于怎么更好的构建泛型类,就靠诸君在日后的生涯中寻找答案了)

/**

* @param

*/

public class Manager implements IManager {

private List datas;

public Manager() {

datas = new ArrayList<>();

}

@Override

public void add(T data) {

datas.add(data);

}

@Override

public T get(int index) {

return datas.get(index);

}

@Override

public void sop() {

for (T t : datas) {

System.out.println(t);

}

}

}

泛型方法(前面的好多)

@Override

public T get(int index) {

return datas.get(index);

}

//泛型方法

public T getData() {

return data;

}

案例运行

public class Demo {

public static void main(String[] args) {

Manager manager = new Manager();

manager.add(new Student("小鱼", 20));

manager.add(new Student("小黑", 30));

manager.add(new Student("SF", 21));

System.out.println("get--->" + manager.get(1));

manager.sop();

}

}

泛型能代表的太多了,是否能给它一些限制呢,答案也是肯定的。下面来看泛型的上下限。

确定上限

什么叫确定上限,字面意思就是你的上限我已经给你定好了,你不可能再超出这个范围,那就有用到一个关键字 extends,我们让 T(泛型)extends 某一个类,那是不是这个泛型的上限就被你决定了。

下面我们看代码。

定义基类

/**

* 基类

*/

public class Person {

int age;

String name;

public Person(String name, int age) {

this.name = name;

this.age = age;

}

}

定义子类

public class Child extends Person {

public Child(String name, int age) {

super(name, age);

}

}

还有一个不相关的类

public class Dog {

private String name;

private int age;

public Dog(String name, int age) {

this.name = name;

this.age = age;

}

}

定义泛型类

public class Fun1 {//确定上限,(泛型类的建模很重要)

private T datas;

public T getDatas() {

return datas;

}

public void setDatas(T datas) {

this.datas = datas;

}

}

运行(接收的引用类型要么是Person类,要么是Person的子类: 确定上限)

step4.png?raw=true

确定下限

感觉用的不多,关键字 super

案例

public class Demo {

public static void main(String[] args) {

Collection cs = new ArrayList();

cs.add(new Student("李xx", 20));

cs.add(new Student("xxx", 19));

cs.add(new Student("hhahah", 20));

sop2(cs);

}

//接收的引用类型要么是Student类,要么是Student的父类: 确定下限

static void sop2(Collection super Student> cs) {

Iterator> iterator = cs.iterator();

while (iterator.hasNext()) {

System.out.println(iterator.next());

}

}

}

让我们带着泛型的目光回顾 TreeSet中涉及Collections、Comparator、Comparable

我们说过TreeSet存储的元素是要支持可排序的,那他有两种方式,一是实现Comparable接口,二是在构造TreeSet实例的时候传一个Comparator实例。

我们先看源码:

Comparable

package java.lang;

public interface Comparable {//一个泛型接口

int compareTo(T var1);

}

这就是Comparable所有的代码,简单吧.

Comparator代码巨多,我们也就只看一行

public interface Comparator {

int compare(T var1, T var2);

......

}

和Comparable很像;

Collections集合工具类,代码巨多,我们也就只看几行

public static > void sort(List var0) {

var0.sort((Comparator)null);

}

public static void sort(List var0, Comparator super T> var1) {

var0.sort(var1);

}

当初也许你会很好奇,这个类凭什么帮你排序,现在你知道了吧,你所传的实例都被泛型限定好了,这里出现了一个以前没说过的"?"号,我们先忽略它。

两个sort方法,要么实现Comparable,要么是Comparator,但有一点他们是统一的,就是都是用确定下限的泛型方式。加深印象!

案例 Comparator泛型的确定下限

Animal(基类)

public class Animal {

int age;

String name;

public Animal(int age, String name) {

this.age = age;

this.name = name;

}

@Override

public String toString() {

return "[" + this.name + "\t" + this.age + "]";

}

}

Cat(子类)

public class Cat extends Animal {

public Cat(int age, String name) {

super(age, name);

}

@Override

public String toString() {

return super.age + "";

}

}

运行

step5.png?raw=true

还有一个?号等着去解决...

? 通配符

我们在Collections 的源码中看到了好多Comparable super T>,那这个?和T有什么关系呢。

? 和T没有什么必然的联系。我们要使用T,则必须在定义类的时候申明T,像 class Fun,然后在类里可以使用T这一类型,

而?则表示通配(填充),表示通配,表示通配,而不是定义,因此我们使用之前不用定义它,表示通配!就如 Class> cls = Person.class.getClass();

Class在实例化的时候,T要替换成具体类

Class>它是个通配泛型,?可以代表任何类型

extends T>受限统配,表示T的一个未知子类。

super T>下限统配,表示T的一个未知父类。

参考

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值