由浅入深,没时间解释了,快上车,fuck car!!!
Java中的泛型,相信很多人在开发中都用到,像下面的
public class Test <T> {
private T t;
private <T> T getData() {
};
private interface ITest <T> {
T getData();
T getDatas(T a);
}
}
是不是很熟悉,很好,觉得熟悉就对了,那下面这个呢,涉及到了泛型的限制,通配符之类的,是不是很眼熟呢~。
//通配符(还有super)
public void method4(Person<? extends Fruit> p) {
}
public class Test <T exstends Serializable> {}
//正确
public class Test <T exstends ArrayList&Serializable> {}
//下个却是错的,如果有多个,类要放在第一(ArrayList),接口放在后面(Serializable),语法限制。。。
public class Test <T exstends Serializable&ArrayList> {}
上面的错误的原因,请看下图:
......
唠嗑了下曾经碰到过的,那么,开始吧,提出问题。
1. 什么是泛型
2. 为什么要用泛型
3. 泛型的使用
4. 限定类型变量
5. 泛型使用中的局限性
6. 泛型中的通配符类型
7. 虚拟机是如何实现泛型的
问题提出来了,喝瓶阔落压压惊。
- 什么是泛型
可以这么理解:参数化类型或者类型参数化。什么意思呢?用过方法吧,方法里面传的参数,举个例子:
//方法1
public int getData(int a) {
}
//方法2
public <T> T getData(T a) {
}
方法1把类型参数化,变成方法2,就不再局限于该方法的参数类型只能是int,你可以是String,double等之类的。
- 为什么要用泛型
1.多种数据类型使用相同的代码。
2.使用泛型,在编码过程中指定数据类型,不需要强制转换。
3.泛型的使用
泛型主要用在类,接口,方法。
泛型类
public class Fruit{
}
public class Apple extends Fruit {
}
public class Person <T> {
}
//派生类
public class Demo <T> extends Person <T> {
private List<T> list;
}
泛型类是可以继承或者扩展其他泛型类的,正确的写法是:
Person<Apple> p1 = new Demo<Apple>(); //里面的类型Apple不能换 成Fruit
注意:
Person<Fruit> p1 = new Person<>();
Person<Apple> p2 = new Person<>();
p1跟p2没有继承关系,如何证明呢,看下面:
Person<Apple> p1 = new Person<Fruit>();
上面代码会报错了~
泛型接口
public interface CallBack <T> {
void callBack(T a);
}
//接口实现
public class ImpCallBack <T> implements CallBack <T> {
...
}
或者具体某个
public class ImpCallBack implements CallBack <String> {
...
}
泛型方法
//泛型方法
public <T> T methodTest(T t) {
...
}
//注意:下面的method1并不是泛型方法,他只是引用了Demo中的泛型
public class Demo <T> extends Person <T> {
public void method1(Demo<T> demo) {
...
}
}
4.限定类型变量
泛型的限定类型变量,就是限定可以传递的类型。
举个例子(这里就拿 泛型方法做例子, because,泛型类,泛型接口与泛型方法类似。)
public class Person{
}
public class Boy extends Person{
}
public class Aa{
}
此时,我这里有个方法
public <T extends Person> void method2( T t) {
...
}
如果需要调用这个方法,只能传递Person或者Person的子类:
method2(new Boy());
method2(new Person());
method2(new Aa()); //错误,这个不行
如果传递的是别的对象,sorry,不行
5.泛型使用中的局限性
不能实例化类型变量
public class Person <T>{
private T t = new T();
}
上面这情况是不阔以的,语法不允许(报错:type parameter "T" cannot be instantiated directly)
静态域或者静态方法是不能引用类型变量
public class Person <T>{
private static void method3(T t){
...
}
private static <T> void method4(T t){
...
}
}
//注意
上面的method3写法是不可以,原因:静态方法的执行比对象的创建
要早, 然而new Person<String>()的时候,才知道T的类型。
当然了,静态方法本身是泛型方法就可以。看method4()方法。
泛型里面不能是基本数据类型
public class Person <T>{
}
使用: new Person<int>() ,是错误的,int需要装箱后放进去。
也就是说,只能是对象,不能是基本数据类型
泛型是不能用instanceof关键字的
举个例子
public class Person <T>{
}
public static void main(String[] args) {
Person <T> person;
if(person instanceof Person <T>) {
}
//是不允许的,不支持
}
泛型类不能继承Exception
//下面这样写,直接就给你飘红了
public class Person<T> extends Exception {
}
看图
泛型其他有趣的限制
Person<Long>[] person; //定义可以,没问题,but
person = new Person<Long>[5]; //初始化,对不起,不行~
不要问为什么。。。语法限制
6.泛型中的通配符类型
我们来看个例子
//普通类
public class Food {
}
public class Fruit extends Food{
}
public class Apple extends Fruit {
}
//泛型类
public class Person <T> {
}
....
public void method3(Person<Fruit> p) {
}
//使用了通配符的
public void method4(Person<? extends Fruit> p) {
}
public void method5(Person<? super Fruit> p) {
}
public static void main(String[] arg) {
Person<Food> p0 = new Person<>();
Person<Fruit> p1 = new Person<>();
Person<Apple> p2 = new Person<>();
//方法调用
method3(p1); //这个毫无疑问,是可以的
method3(p2); // 不可以!!!
//这个时候就要使用通配符了
method4(p1); .// you can
method4(p2); // 哎,这个也可以了
method4(p0); //这个不行,看下面说明
//说明:通配符 extends 限制了上界,比如上面的,上届就是Fruit,
//只要是派生自Friut或者本身,都可以,Food就不行了(也就是说,只要是 Friut的子类都可以)
//还没完事呢,通配符除了extends ,还有 super,
//用法刚好跟extends相反,看method5,只要是 Fruit的超(父)类或者其本身,都可以。
}
7.虚拟机是如何实现泛型的
实不相瞒,进行了泛型擦除。什么意思呢,我举个例子
public class Person<T> {
private T t;
}
上面的类泛型擦除后,会是下面这个:
public class Person<T> {
private Object t;
}
继续看
public class Person<T extends ArrayList&Comparable> {
private T t;
public void test(){
// t.compareTo()
}
}
擦除后这样的:
public class Person<T extends ArrayList&Comparable> {
private ArrayList t;
public void test(){
// (Comparable)t.compareTo()
}
}
开头就提出来了,如果有继承的,必须放在第一(ArrayList放在Comparable前面),
类只能有一个(因为在java里面,是单继承的),接口可以多个。对于后面的Comparable,什么时候体现呢?
当你在某个方法用到了Comparable接口的时候,编译器会插入一个强制转型的代码,看test()方法。
感兴趣的可以看编译后的.class文件。
over,记录下。