JAVA自学笔记,泛型

在JDK1.5版本中提供了泛型概念,泛型实质上就是使程序员定义安全的类型。在没有出现泛型之前,Java也提供了对Object的引用“任意化”操作,这种任意化操作就是对Object引用进行“向下转型”及“向上转型”操作,但某些强制类型转换的错误也许不会被编译器捕捉,而在运行后出现异常,可见强制类型转换存在安全隐患,所以提供了泛型机制。

回顾

在介绍泛型之前我们先回顾一下“向上转型”和“向下转型”上例子。
在这里插入图片描述
在这里插入图片描述
在本例中,Test类中定义了私有的成员变量b,它的类型为Object类型,同时为其定义了相应的setXXX()与getXXX()方法。在类主方法中,将new Boolean(true)对象作为setB()方法的参数,由于setB()方法的参数类型为Object,这样就实现了“向上转型”操作,同时在调用getB()方法时,将getB()方法返回的Object对象以相应的类型返回,这个就是“向下转型”操作,问题通常就会出现在这里。因为“向上转型”是安全的,而如果进行“向下转型”操作时用错了类型,或者并没有执行该操作,就会出现异常。例如如下代码。
在这里插入图片描述
在这里插入图片描述
上面代码并不存在语法错误,也可以被编译器接受,但是在执行的时候会出现ClassCastException异常,这样看来,“向下转型”操作通常会出现问题,而泛型机制有效的解决了这一问题。

定义泛型类

Object类为最上层的父类,很多程序员为了使程序更为通用,设计程序时通常使传入的值与返回的值都以Object类型为主,当需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则在运行时将会发生ClassCastException异常。
而在JDK1.5版本以后,提出了泛型机制,其语法如下。

类名<T>

其中,T代表一个类型的名称。
小例子。
在这里插入图片描述
在这里插入图片描述
运行上述代码,结果与之前的例子完全一致,上面代码中定义类时,在类名后面添加了一个<T>语句,这里便使用了泛型机制,可以将OverClass类称为泛型类,同时返回和接受的参数使用T这个类型。最后在主方法中可以使用Over<Boolean>形式返回一个Boolean型的对象,使用OverClass<Float>形式返回一个Float型的对象,使这两个对象分别调用setOver()方法不需要进行显示“向上转型”操作,setOver()方法直接接受相应类型的参数,而调用getOver()方法时,不需要进行“向下转型”操作,直接将getOver()方法返回的值赋予相应的类型变量即可。
从上面代码可以看出,使用泛型定义的类在声明该类对象时可以根据不同的需求指定<T>真正的类型,而在使用类中的方法传递或返回数据类型时将不再进行类型转换操作,而是使用在声明泛型类对象时“<>”符号中设置的数据类型。
使用泛型这种形式将不会发生ClassCastException异常,因为在编译器中就可以检查类型匹配是否正确。
例如:
在这里插入图片描述
在上面的代码中,由于over2对象在实例化时已经制定类型为Float,而最后一条语句却将该对象获取出的Float类型赋值赋予Integer类型,所以编译器会报错。而如果使用“向下转型”操作就会在运行上述代码时发生异常。
在定义泛型类时,一般类型名称使用T来表达,而容器的元素使用E来表达。具体可以参看JDK5.0以上版本的API。

泛型的常规用法

定义泛型类时声明多个类型

在定义泛型类时,可以声明多个类型。

MutiOverClass<T1,T2>
MutiOverClass:泛型类名称

其中,T1和T2为可能被定义的类型。这样在实例化指定类型的对象时就可以指定多个类型。

MutiOverClass<Boolean,Float>=new MutiOverClass<Boolean,Float>();
定义泛型类时声明数组类型

定义泛型类时也可以声明数组类型,看例子。
在这里插入图片描述
在这里插入图片描述
本例在定义泛型类时声明了一个成员数组,数组的类型为泛型,然后在泛型类中相应设置setXXX()与getXXX()方法。
由此可见,可以在使用泛型机制时声明一个数组,但是不可以使用泛型来建立数组的实例,例如下面的代码就是错误的。

public class ArrayClass<T>{
private T[] array = new T[10];//不能使用泛型来建立数组的实例
}

JDK1.7版本中添加了一个新特性,自动推断实例化类型的泛型。所以这种语法

ArrayClass<String> a = new ArrayClass<>();

会自动转换成:

ArrayClass<String> a = new ArrayClass<String>();

集合类声明容器的元素

在实际应用中,通过在集合类中应用泛型可以使集合类中的元素类型保证唯一性,这样在运行时就不会产生ClassCastException异常,提高了代码的安全性和可维护性。可以使用K和V两个字符代表容器中的键值与键值相对应的具体值。
在这里插入图片描述
在这里插入图片描述
其实在本例中定义的泛型类MutiOverClass纯属多余,因为在Java中这些集合框架已经都被泛型化了,可以再主方法中直接使用public Map<K,V> m = new HashMap<K,V>();语句创建实例,然后相应调用Map接口中的put()与get()方法完成填充容器或根据键名获取集合中具体值的功能。集合中除了HashMap这种集合类型之外,还包括很多倍泛型化的集合类,下面给大家列举出一些常用的。
在这里插入图片描述
下面演示一下这些集合的使用方式。
在这里插入图片描述
在这里插入图片描述

泛型的高级用法

泛型的高级用法主要包括通过类型参数T的继承和通过类型通配符的继承来限制泛型类型,另外,开发人员还可以继承泛型类或者实现泛型接口。

通过类型参数T的继承限制泛型类型

默认可以使用任何类型来实例化一个泛型对象,但Java中也对泛型类实例的类型做了限制,这主要通过对类型参数T实现继承来体现。

class 类名称 <T extends anyclass>

其中,anyClass指某个接口或类。
使用泛型限制后,泛型类的类型必须实现或继承了anyClass这个接口或类。无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字。
在这里插入图片描述
上面例子中,将泛型做了限制,设置泛型类型必须实现List接口。ArrayList和LinkedList都实现了List接口,而HashMap没有实现List接口,所以在这里不能实例化HashMap类型的泛型对象。
当没有使用extends关键字限制泛型类型时,默认Object类下的所有子类都可以实例化泛型类对象。

通过类型通配符的继承限制泛型类型

在泛型机制中,提供了类型通配符,其主要作用是在创建一个泛型类对象时,限制这个泛型类的类型,或者限制这个泛型类型必须继承某个接口或某个类(或其子类)。要声明这样一个对象可以使用“?”通配符,同时使用extends关键字来对泛型加以限制。
通过对类型参数T实现继承限制泛型类型时,在声明时就进行了限制,而通过对类型通配符实现继承限制泛型类型时,则在实例化时才进行限制。

泛型类名称<? extends List> a = null;

其中,<? extends List>表示类型未知,当需要使用该泛型对象时,可以单独实例化。例如:

A<? extends List> a = null;
a = new A<ArrayList>();
a = new A<LinkedList>();

如果实例化没有实现List接口的泛型对象,编译器将会报错。上面的例子中如果我们声明一个HashMap对象时,编译器将会报错,因为HashMap没有实现List接口。
除了可以实例化一个限制泛型类型的实例之外,还可以将该实例放置在方法的参数中。例如:

public void doSomething(A<? extends List>a){
}

上面例子中,定义方式有效地限制了传入doSomething()方法的参数类型。
如果使用A<?>这种形式实例化泛型类对象,则默认表示可以将A指定为实例化Object及以下的子类类型。大家可能对这种编码类型有疑惑。我们来看个例子。
在这里插入图片描述
在这里插入图片描述
上面代码中,由于对象l1时没有使用A<?>这种形式初始化出来的对象,所以它可以调用set()方法改变集合中的值,但l2与l3则是通过使用通配符的方式创建出来的,所以不能改变集合中的值,所以无法调用set()方法。另外,List<?>类型的对象可以接受String类型的ArrayList集合,也可以接受Integer类型的LinkedList集合。那么List<?>l2=l1语句与List l2 = l1存在何种本质区别?使用通配符声明的名称实例化的对象不能对其加入新的信息,只能获取或删除。
泛型类型限制除了可以向下限制之外,还可以向上限制,只要在定义时使用super关键字即可,例如A<? superList> a = null;这样定义后,对象a只接受List接口或上层父类类型,如a = new A<Object>();

继承泛型类与实现泛型接口

定义为泛型的类和接口欧也可以被继承与实现。
例如,在项目中创建一个类文件,在该类中继承泛型类。

class SubClass<T1,T2,T3> extends ExtendClass<T1>{//泛型可以比父类多,但是不可以比父类少

}

如果在SubClass类继承ExtendClass类时保留父类的泛型类型,需要在继承时指明,如果没有指明,直接使用extends ExtendsClass语句进行继承操作,则SubClass类中的T1,T2和T3都会自动变为Object,所以在一般情况下都将父类的泛型类型保留。
定义的泛型接口也可以被实现。

泛型总结

使用泛型需要遵循以下原则。
1,泛型的类型参数只能是类类型,不可以是简单类型,如A<int>这种泛型定义就是错误的。
2,泛型的类型个数可以使多个。
3,可以使用extends关键字限制泛型的类型。
4,可以使用通配符限制泛型的类型。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值