JAVA学习总结之泛型
来源:互联网 发布:淘宝客网站开发 编辑:程序博客网 时间:2024/06/05 19:25
泛型(Gereric):
允许在定义类,接口,方法时使用类型形参,这个类型形参将在变量声明,创建对象,调用方法时动态的指定(即传入实际的类型实参),
类型实参在整个接口,类体内可当成类型使用。
注意: 1.包含泛型说明的类型可以在定义变量,创建对象时传入一个类型实参,从而可以动态的生成无数个逻辑上的子类,但是这种子类在物理上并不存在。
2.当创建带泛型声明的自定义类,为该类定义构造器时,构造器还是原来的类名,不要增加泛型说明。
一、从泛型派生出子类:
当创建了带泛型的接口,父类之后,可以为该接口创建实现类,或从父类派生子类,但是当使用这些接口或者父类的时候不能再包含类型实参.
如,下面的代码就是错误的:
//定义类A继承Apple类,Apple类不能跟类实参
public class extends Apple<T>{ }
定义和使用方法与定义和使用类,接口的异同:
1.方法中的形参代表变量,常量,表达式等数据,定义方法时可以声明数据类型,调用方法时必须为这些数据类型传入实际的数据;与此类似的是,定义类,接口,方法时可以声明类型形参,使用类,接口,方法时应该为类型形参传入实际的类型.
如:
//使用Apple类时为T形参传入实际的类型参数
public class A extends Apple<String>{ }
2.调用方法时必须为所有的数据形参传入参数值,与调用方法不同的是,使用类,接口时也可以不为类型形参传入实际的类型参数,如:
//使用Apple类时,没有为T形参传入实际的类型参数
public class A extends Apple{ }
二、并不存在泛型类:
1.不管泛型的实际类型参数是什么,它们在运行时总有同样的类,在内存中也只占用同一块内存空间,因此在静态方法,静态初始化或者静态变量的声明和初始化中不允许使用类型形参。
2.由于系统中并不会真正生成泛型类,所以instanceof运算符后不能使用泛型类。
(补充:
1. instanceof用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。
2. instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类)。
3. 在进行强制类型转换之前,先用instanceof运行符判断是否可以成功转换,从而避免出现ClassCastException异常,这样可以保证程序更加健壮。
4. 在使用instanceof运算符需要注意:instanceof运算符前面操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系,否则会引起编译错误。
)
注意:
如果Foo是Bar的一个子类型(子类或子接口),而G是具有泛型说明的类或接口,G<Foo>并不是G<Bar>的子类!这一点非常重要。
但是数组和泛型有所不同,假设Foo是Bar的一个子类型(子类或子接口),那么Foo[]依然是Bar[]的子类型;但G<Foo>不是G<Bar>的子类型。
三、类型通配符
1.为了表示各种泛型List的父类,可以使用类型通配符,类型通配符是一个问号(?),讲一个问号作为类型实参传给List集合,写作List<?>(意思是元素类型未知的List),这种写法可以适应于任何支持泛型的接口和类。
这个问号(?)被称为通配符,它的元素类型可以匹配任何类型,但是这种带通配符的List仅表示它是各种泛型LIst的父类,并不能把元素加入到其中,如下,代码将会引起编译出错:
List<?> c = new ArrayList<String>();
//下面引起编译出错(因为无法确定集合中元素的类型)
c.add(new Object);
2.类型通配符的上限
一般的时候,有些方法只能处理一部分数据类型,这时候就可以使用上限和下限来确定这个范围,格式如下:
泛型上限:
<? extends 类名>
public static void function(Student<? extends Number> s){
System.out.println("姓名是:"+s.getName());
}
表示只能接收Number这个类以及这个类的子类的数据类型。(extends表继承,就是这个类下面的东西)
泛型下限:
<? super 类>
表示只能接收Number这个类以及这个类的父类的数据类型。(super表父类,超过这个类的东西)
四、泛型方法:
在声明方法时定义一个或多个类型形参(类型形参声明以尖括号括起来,多个形参之间以逗号隔开,所有的类型形参声明放在方法修饰符和方法返回值之间)
1.与接口、类声明中定义的类型不同的是,方法声明中定义的形参只能在该方法里使用,而接口、类中的类型形参则可以在整个接口、类中使用。
2.与接口、类中使用泛型参数不同的是,方法中的泛型参数无需显示传入实际类型参数。(即即使带参数的方法可以直接使用 方法名())
五、擦除:
当把一个具有泛型信息的对象赋值给另一个没有泛型信息的变量时,所有尖括号之间的类型信息都将被扔掉.
如:Java允许直接把List对象赋给一个List<Type>(Type可以是任何类型)类型的变量,但是当把List<Type>对象直接赋给一个List类型的list之后,编译器会丢失前者的泛型信息,
即丢失List<Type>集合里元素的类型信息,这就是典型的擦除。
六、泛型与数组
1.Java泛型有一个很重要的设计原则--如果一段代码在编译时没有提出“[unchecked]为经检查的转换”警告,则程序在运行时不会引发ClassCasrException异常。
因此,数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符。但可以声明元素类型包含类型变量或类型形参的数组。
也就是说,只能声明List<String>[]类型的数组,但不能创建ArrayList<String>[10]这样的数组对象。
2.Java允许创建无上限的通配符泛型数组,类如 new ArrayList<?>[10].(程序得进行强制转换)
允许在定义类,接口,方法时使用类型形参,这个类型形参将在变量声明,创建对象,调用方法时动态的指定(即传入实际的类型实参),
类型实参在整个接口,类体内可当成类型使用。
注意: 1.包含泛型说明的类型可以在定义变量,创建对象时传入一个类型实参,从而可以动态的生成无数个逻辑上的子类,但是这种子类在物理上并不存在。
2.当创建带泛型声明的自定义类,为该类定义构造器时,构造器还是原来的类名,不要增加泛型说明。
一、从泛型派生出子类:
当创建了带泛型的接口,父类之后,可以为该接口创建实现类,或从父类派生子类,但是当使用这些接口或者父类的时候不能再包含类型实参.
如,下面的代码就是错误的:
//定义类A继承Apple类,Apple类不能跟类实参
public class extends Apple<T>{ }
定义和使用方法与定义和使用类,接口的异同:
1.方法中的形参代表变量,常量,表达式等数据,定义方法时可以声明数据类型,调用方法时必须为这些数据类型传入实际的数据;与此类似的是,定义类,接口,方法时可以声明类型形参,使用类,接口,方法时应该为类型形参传入实际的类型.
如:
//使用Apple类时为T形参传入实际的类型参数
public class A extends Apple<String>{ }
2.调用方法时必须为所有的数据形参传入参数值,与调用方法不同的是,使用类,接口时也可以不为类型形参传入实际的类型参数,如:
//使用Apple类时,没有为T形参传入实际的类型参数
public class A extends Apple{ }
二、并不存在泛型类:
1.不管泛型的实际类型参数是什么,它们在运行时总有同样的类,在内存中也只占用同一块内存空间,因此在静态方法,静态初始化或者静态变量的声明和初始化中不允许使用类型形参。
2.由于系统中并不会真正生成泛型类,所以instanceof运算符后不能使用泛型类。
(补充:
1. instanceof用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。
2. instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类)。
3. 在进行强制类型转换之前,先用instanceof运行符判断是否可以成功转换,从而避免出现ClassCastException异常,这样可以保证程序更加健壮。
4. 在使用instanceof运算符需要注意:instanceof运算符前面操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系,否则会引起编译错误。
)
注意:
如果Foo是Bar的一个子类型(子类或子接口),而G是具有泛型说明的类或接口,G<Foo>并不是G<Bar>的子类!这一点非常重要。
但是数组和泛型有所不同,假设Foo是Bar的一个子类型(子类或子接口),那么Foo[]依然是Bar[]的子类型;但G<Foo>不是G<Bar>的子类型。
三、类型通配符
1.为了表示各种泛型List的父类,可以使用类型通配符,类型通配符是一个问号(?),讲一个问号作为类型实参传给List集合,写作List<?>(意思是元素类型未知的List),这种写法可以适应于任何支持泛型的接口和类。
这个问号(?)被称为通配符,它的元素类型可以匹配任何类型,但是这种带通配符的List仅表示它是各种泛型LIst的父类,并不能把元素加入到其中,如下,代码将会引起编译出错:
List<?> c = new ArrayList<String>();
//下面引起编译出错(因为无法确定集合中元素的类型)
c.add(new Object);
2.类型通配符的上限
一般的时候,有些方法只能处理一部分数据类型,这时候就可以使用上限和下限来确定这个范围,格式如下:
泛型上限:
<? extends 类名>
public static void function(Student<? extends Number> s){
System.out.println("姓名是:"+s.getName());
}
表示只能接收Number这个类以及这个类的子类的数据类型。(extends表继承,就是这个类下面的东西)
泛型下限:
<? super 类>
表示只能接收Number这个类以及这个类的父类的数据类型。(super表父类,超过这个类的东西)
四、泛型方法:
在声明方法时定义一个或多个类型形参(类型形参声明以尖括号括起来,多个形参之间以逗号隔开,所有的类型形参声明放在方法修饰符和方法返回值之间)
1.与接口、类声明中定义的类型不同的是,方法声明中定义的形参只能在该方法里使用,而接口、类中的类型形参则可以在整个接口、类中使用。
2.与接口、类中使用泛型参数不同的是,方法中的泛型参数无需显示传入实际类型参数。(即即使带参数的方法可以直接使用 方法名())
五、擦除:
当把一个具有泛型信息的对象赋值给另一个没有泛型信息的变量时,所有尖括号之间的类型信息都将被扔掉.
如:Java允许直接把List对象赋给一个List<Type>(Type可以是任何类型)类型的变量,但是当把List<Type>对象直接赋给一个List类型的list之后,编译器会丢失前者的泛型信息,
即丢失List<Type>集合里元素的类型信息,这就是典型的擦除。
六、泛型与数组
1.Java泛型有一个很重要的设计原则--如果一段代码在编译时没有提出“[unchecked]为经检查的转换”警告,则程序在运行时不会引发ClassCasrException异常。
因此,数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符。但可以声明元素类型包含类型变量或类型形参的数组。
也就是说,只能声明List<String>[]类型的数组,但不能创建ArrayList<String>[10]这样的数组对象。
2.Java允许创建无上限的通配符泛型数组,类如 new ArrayList<?>[10].(程序得进行强制转换)
阅读全文
0 0
- 泛型之Java学习总结
- JAVA学习总结之泛型
- Java高级特性之泛型学习总结
- java学习之--多线程总结
- Java学习总结之IO
- Java学习总结之Debug
- Java学习总结之线程
- Java学习总结之反射
- Java学习之IO总结
- Java学习之线程总结
- java学习总结之IO
- java学习之路---总结
- JAVA学习总结之Socket
- 【java学习之容器总结】
- JAVA学习之集合总结
- JAVA学习之IO总结
- Java学习总结之数组
- java学习总结之继承
- leetcode675. Cut Off Trees for Golf Event(Hard)
- 现代滤波器
- 程序与进程的区别
- Python排列组合之itertools
- 如何在VirtualBox虚拟机中安装Android x86
- JAVA学习总结之泛型
- SED
- poj3468
- malloc & 内存碎片 & 细节
- 2017 ACM-ICPC 亚洲区(北京赛区)网络赛C.Matrix (DP)
- 机器学习中的正则化技术L0,L1与L2范数
- scrapy抓取的中文结果乱码解决办法
- 下载软件 ==》BitComet(比特彗星)
- SPOJ