.net java 泛型_Java—泛型详解和使用

1 泛型介绍

1.1 泛型的出现

泛型的出现还得从集合说起,没有泛型的时候,我们将一个对象存入集合时,集合不care这个对象的数据类型是什么,当我们再次从这个对象取出来的时候,对象的编译类型会变成Object类型,这时候我们就需要强制类型转换,但是这种行为每次都要去指定类型进行强制转换,并且有可能强制转换不了,比如我存的是Integer类型,误转换为String类型,那就可能会引发ClassCastException异常。

当Java 5引入了一个叫做“参数化类型”的概念后,我们可以在创建集合时去指定集合,这样我们再从集合取出数据时,这个数据就是我们当初指定的类型,不会出现需要强制类型转换的情况了。这种参数化类型就是泛型。

1.2 泛型在集合中的使用示例

在集合接口或者类后面增加尖括号<>,里面注明数据类型,创建这个集合后,这个集合就只能存储这个特定的数据类型对象。

从Java 7开始,在使用带泛型的接口、类定义变量,我们调用构造器创建对象时构造器后面不需要带完整的泛型信息,只需要带一对尖括号<>就行。如List strList = new ArrayList<>();只需要前面声明泛型,后面只需要<>即可。

示例:

public class DemoApplication {

public static void main(String[] args) {

List stringList = new ArrayList<>();

stringList.add("t1");

stringList.add("t11");

Map> map = new HashMap<>();

map.put("t", stringList);

stringList.forEach(str -> System.out.println(str.length()));

map.forEach((key, value) -> System.out.println(key + "---->" + value));

}

}

结果:

2

3

t---->[t1, t11]

2 泛型的进阶

泛型就是允许在定义接口、类和方法时使用类型形参,通过传入实际的类型参数(类型实参),该类型形参会在声明变量、创建对象、调用方法的时候动态指定。类型形参可以在整个接口、类内当作类型使用。这种方式可以动态生成无限个逻辑上的子类(实际物理中没有)。

无论泛型的类型形参传入的是什么类型实参,系统最后都是当作一个类来处理,内存中也只是占用一块内存空间。如List intList = new ArrayList<>();和List strList = new ArrayList<>();通过intList.getClass()和strList.getClass()得到的是相等的结果,这就表明两个类是相同的。

另: 在静态变量和静态方法声明中不可以使用类型形参。

2.1 泛型接口举例

public interface List {

void create(T e);

void delete(T e);

void update(T e);

void find(T e);

}

其中,List为例,若形参T传入的是String类型的实参,则会产生一个List,逻辑上是List的子接口,只不过这个接口内的E类型都为String类型。

2.2 泛型类举例

定义泛型类Person:

//创建带泛型声明的自定义类

public class Person{

//使用T类型形参来定义实例变量

private T info;

public Person(){}

//使用T类型形参定义构造器,注意:构造器不用增加泛型声明,直接使用原类名即可;

public Person(T info) {

this.info = info;

}

public T getInfo() {

return info;

}

public void setInfo(T info) {

this.info = info;

}

@Override

public String toString() {

return info.toString();

}

}

泛型形参传入实参测试:

public class DemoApplication {

public static void main(String[] args) {

//实参传入String类型给T形参,则构造器构造对象时传参为String类型;

Person personStr = new Person<>("小明");

System.out.println("姓名: " + personStr.getInfo());

//实参传入Integer类型给T形参,则构造器构造对象时传参为Integer类型;

Person personInt = new Person<>(28);

System.out.println("年龄: " + personInt.getInfo());

}

}

结果:

姓名: 小明

年龄: 28

从上面的实验中,我们可以看出:通过泛型类Person传入实参后,可以生成诸如Person,Person,Person等多个逻辑子类。

2.3 泛型类无参子类

创建ChinesePerson类继承无参泛型类。

public class ChinesePerson extends Person {

@Override

public String getInfo() {

return super.getInfo().toString();

}

}

测试:

public class DemoApplication {

public static void main(String[] args) {

Person chinesePerson = new ChinesePerson();

chinesePerson.setInfo("中国人");

System.out.println("Chinese person: " + chinesePerson.getInfo());

}

}

结果:

Chinese person: 中国人

2.5 泛型类带参子类

创建JiangsuPerson类继承带参泛型类。

public class JiangsuPerson extends Person {

//重写父类方法,返回值类型需保持一致

public String getInfo() {

return "城市信息: " + super.getInfo();

}

}

测试:

public class DemoApplication {

public static void main(String[] args) {

Person jiangsuPerson = new JiangsuPerson();

jiangsuPerson.setInfo("南京");

System.out.println(jiangsuPerson.getInfo());

}

}

结果:

城市信息: 南京

3 泛型的类型通配符

3.1 类型通配符>

通配符?在类型形参中使用后,可以表示各种泛型的父类,如List>,即List的类型未知,可以传入任何类型的实参。

这种List>不能直接添加元素,因为无法确定集合内的类型是什么,所以无法添加对象。(除了null,因为null是所有引用类型的实例)

List>通过get()方法返回的一定是Object,所以可以将其赋值给Object类型变量。

3.2 类型通配符上限 extends xx>

通过 extends xx>表示所有xx泛型的父类,如List extends Person>表示所有Person泛型List的父类。?代表的是一个未知类型,但这个未知类型又受到extends限制,只能是Person的自身及子类。

3.3 类型形参的上限

类型形参的上限主要是限制实参只能是形参类型本身或子类。

示例:

public class Person {

T info;

public static void main(String[] args) {

Person person = new Person<>();

Person person2 = new Person<>();

}

}

若上述代码中增加Person person3 = new Person<>();,则编译报错,因为String类型不是Number或子类;通过限制住形参的上限。

4 泛型方法

4.1 泛型方法定义

泛型方法就是在声明方法时定义一个或多个类型形参;相比较于普通方法,泛型方法多了类型形参声明,多了<>,若有多个类型形参,使用逗号","隔开,并且在方法修饰符和方法返回值类型中间要有类型形参。

4.2 语法

修饰符 返回值类型 方法名(形参列表){

//方法体

}

4.3 举例

泛型方法:

public class GenericMethodExample {

//定义泛型方法,传递T类型形参

public static void copyArrayToCollection(T[] array, Collection collection) {

for (T obj : array) {

collection.add(obj);

}

}

//定义泛型方法,通过类型通配符设置T类型上限

public static void copyCollectionToCollection(Collection extends T> fromCollection,

Collection toCollection) {

for (T obj : fromCollection) {

toCollection.add(obj);

}

}

}

入口类:

public class DemoApplication {

public static void main(String[] args) {

//泛型方法

Object[] objects = new Object[]{"10", 12, new Person("hello, i'm from jiangsu")};

Collection collections = new ArrayList<>();

GenericMethodExample.copyArrayToCollection(objects, collections);

collections.forEach(obj -> System.out.println(obj.toString()));

//泛型方法通过类型通配符设置上限类型形参

List fromCollection = new ArrayList<>();

fromCollection.add(1);

fromCollection.add(2);

fromCollection.add(3);

Collections.reverse(fromCollection);

List toCollection = new ArrayList<>();

GenericMethodExample.copyCollectionToCollection(fromCollection, toCollection);

System.out.println("泛型方法上限测试:" + toCollection);

}

}

运行结果:

10

12

hello, i'm from jiangsu

泛型方法上限测试:[3, 2, 1]

从上述测试中,我们可以看到

5 泛型构造器

5.1 泛型构造器定义

在构造器签名中声明类型形参就是泛型构造器。

5.2 语法

public 类名(形参列表){

//方法体

}

5.3 示例

给GenericMethodExample类定义泛型构造方法

public class GenericMethodExample {

public GenericMethodExample(T t) {

System.out.println(t);

}

}

主类入口:

public class DemoApplication {

public static void main(String[] args) {

new GenericMethodExample("泛型构造器01");

new GenericMethodExample(100);

new GenericMethodExample("显示指定泛型构造器形参T为String类型");

new GenericMethodExample(50);

}

}

运行结果:

泛型构造器01

100

显示指定泛型构造器形参T为String类型

50

参考《疯狂Java》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值