不忘初心 砥砺前行, Tomorrow Is Another Day !
相关文章
- 一. 重识Java之夯实泛型
- 二. 重识Java之夯实注解
- 三. 重识Java之夯实反射
引言
本文概要:
- 泛型的基本使用
- 泛型类
- 泛型接口
- 泛型函数
- 泛型的进阶使用
- 类型绑定
- 通配符
泛型的基本使用
本节概要:
- 泛型类,接口,函数的定义
泛型的优点:
- 不用强制转换
- 如果传入类型不对,编译时会报错
一. 泛型类的定义
1.1 单泛型变量类的定义
public class Location<T>{//标识符号可以随意写
private T x ;
private T y ;
public void setX(T x){//作为参数
this.x = x ;
}
public void setY(T y){
this.y = y ;
}
public T getX(){//作为返回值
return this.x ;
}
public T getY(){
return this.y ;
}
}
复制代码
1.2 多泛型变量类的定义
以 , 进行分隔
public class MoreLocation<T,U> {//标识符号可以随意写
private T x;
private U y;
public void setX(T x) {//作为参数
this.x = x;
}
public void setY(U y) {
this.y = y;
}
public T getX() {//作为返回值
return this.x;
}
public U getY() {
return this.y;
}
}
复制代码
1.3 标识符号的字母规范.
虽然标识符号可以随意取,但为了提高可读性,一般遵循以下规则.
- E — Element,常用在java Collection里,如:List,Iterator,Set
- K,V — Key,Value,代表Map的键值对
- N — Number,数字
- T — Type,类型,如String,Integer等等
二. 泛型接口的定义
在接口上定义泛型与在类中定义泛型是一样的
interface ILocation<T>{ // 在接口上定义泛型
T getZ() ;
void setZ(T z);
}
复制代码
2.1 非泛型类实现泛型接口
public class LocationImpl implements ILocation<String>{
private String z ;
public LocationImpl(String z){
this.setZ(z) ;
}
@Override
public void setZ(String z){
this.z = z ;
}
@Override
public String getZ(){
return this.z ;
}
}
复制代码
2.2 泛型类实现泛型接口
publick class LocationImpl<T,K,U> implements ILocation<U>{ //把第三个泛型变量U用来填充接口
private U z ;
private T x;
private K y;
public LocationImpl(U z){
this.setZ(z) ;
}
@Override
public void setZ(U z){
this.z = z ;
}
@Override
public U getZ(){
return this.z ;
}
}
复制代码
三. 泛型函数的定义
在方法的返回值前加上来表示泛型变量.
public class MethodLocation {
public static <T> void staticMethod(T text) {
System.out.println("staticMethod:" + text);
}
//返回值与形参中存在泛型
public <T> T normalMethod(T text) {
System.out.println("normalMethod:" + text);
return text;
}
//定义泛型数组, T[]相当于String[].
public static <T> T[] funArray(T...arg){ // 接收可变参数
return arg ; // 返回泛型数组
}
public static void main(String[] args) {
MethodLocation methodLocation = new MethodLocation();
String text1 = methodLocation.normalMethod("hello");//方法1
String text2 = methodLocation.<String>normalMethod("genericity");//方法2
System.out.println("from main method:"+text1);
System.out.println("--------------------------");
Integer[] intArray = MethodLocation.funArray(1, 2, 3, 4, 5, 6);
System.out.println(Arrays.toString(intArray));
}
}
//输出结果
normalMethod:hello
normalMethod:genericity
from main method:hello
--------------------------
[1, 2, 3, 4, 5, 6]
复制代码
注意:虽然方法2是推荐方式,但实际在IDEA中会提示使用方法1,这是因为它会实时检测传入类型是否一致,不一致直接提醒编译不通过.
泛型的进阶使用
本节概要:
- 类型绑定
- 通配符
一. 类型绑定
在前一节中,T只能是Object的子类,所以在编译时只能调用Object类的相关方法.假如现在有个dog类,我们想在编译时就调用他父类Animal的方法.这时就需要用到类型绑定.
定义:
< T extends BoundingType >
T和BoundingType可以是类,也可以是接口.
此处的==extends==仅仅表示子类型,不等同于继承.
优点:
- 对泛型加以限定
- 泛型变量T,可以使用BoundingType内部的函数.
//省略....创建dog,Animal,IAction相关代码.
public class TypeBind {
public static void main(String[] args) {
Dog dog = new Dog("旺财");
String nameClass = getAnimalNameClass(dog);
System.out.println(nameClass);
System.out.println("---------------");
String actionInterface = getAnimalActionInterface(dog);
System.out.println(actionInterface);
System.out.println("---------------");
String nameAction = getAnimalNameAndAction(dog, dog);
System.out.println(nameAction);
}
//绑定类
private static <T extends Animal> String getAnimalNameClass(T sub) {
//这样编译时,就能调用Animal中的方法.
return sub.getName();
}
//绑定接口
private static <T extends IAction> String getAnimalActionInterface(T sub) {
return sub.howl();
}
//多个泛型绑定多个类型,通过&符号指定多个类型
private static <T extends Animal & Serializable, U extends IAction & Serializable> String
getAnimalNameAndAction(T sub1, U sub2) {
return sub1.getName() + sub2.howl();
}
}
复制代码
二. 通配符
通配符的意义就是它是一个未知的符号,可以是代表==任意的类==,通常用?号表示.
作用:用于填充泛型变量T,表示代表任意类型!仅仅是填充方式的一种.
//使用位置有且只有,只能用来在生成泛型实例时使用.
Location<?> location;
location = new Location<Integer>();
复制代码
2.1 通配符?的extends绑定
- 指填充为派生于XXX的任意子类的话.
- 所以实例能取不能存.
Location<? extends Number> location;
location = new Location<Integer>(2,3);
//取
Number number = location.getX();//编译通过
//存
location.setX(new Integer(123);//编译报错
复制代码
location的类型由<? extends Number>决定,并不会因为location = new Location(2,3)而改变类型.所以不能确定通配符类型.
2.2 通配符?的super绑定
- 则表示填充为任意XXX的父类.
- 实例能存不能取.
/**
* 准备三个类Animal(动物),Mammal(哺乳动物),Mouse(老鼠).
* Mouse 继承 Mammal, Mammal 继承 Animal.
* .....省略相关类代码
*/
List<? super Mammal> list;
list = new ArrayList<Animal>;
//取
Animal animal = list.get(0);//编译报错
Object object = list.get(0);
//存
list.add(new Animal());//编译报错
list.add(new Mammal());
list.add(new Mouse());
复制代码
取的时候报错,编译器不能确定<? super Mammal>的父类就是Animal.
至于存的时候报错,同样因为是未知类型,编译器只能确定通配符类型为Mammal及其子类.
对于编译器,只要能确定通配符类型,就会编译通过.否则会报错.
最后的话:
本文只是对参考链接的内容总结,如需详细了解,请参考启舰大佬的博客链接.
由于本人技术有限,如有错误的地方,麻烦大家给我提出来,本人不胜感激,大家一起学习进步.
参考链接:
- blog.csdn.net/harvic88092…
- blog.csdn.net/harvic88092…