600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 泛型(泛型类 泛型方法 泛型接口 通配符)详解

泛型(泛型类 泛型方法 泛型接口 通配符)详解

时间:2021-12-15 20:40:36

相关推荐

泛型(泛型类 泛型方法 泛型接口 通配符)详解

泛型的定义:

在定义类的时候并不会设置类的属性和方法的参数的具体类型,而是在类实际用的时候再定义。它存在的意义是帮我们在编译期间检查我们的类型是否正确。

//定义一个Point类class Point{private Object x;private Object y;public Object getX() {return x;}public void setX(Object x) {this.x = x;}public Object getY() {return y;}public void setY(Object y) {this.y = y;}}public class Generic {public static void main(String[] args) {//创建Point类对象Point point = new Point();//定义X和Ypoint.setX("东经80度");point.setY("北纬20度");//转成字符串类型String x = (String) point.getX();String y = (String) point.getY();//打印System.out.println("x = "+x);System.out.println("y = "+y);}}

我们先定义一个Point类,其中的X和Y属性我们都用定义为Object类,在使用的时候转成字符串,再进行打印。

但是当我们setY的时候给了它一个整数,但是后面转换成字符串的时候,编译器并没有个我们提示类型错误,只有到运行的时候在产生报错。

告诉我们34行产生类型转化错误,所以就产生类泛型,目的是可以帮助我们在编译器期间就可以告诉我们类型错误,及时修改!

泛型类:

基本语法:

class exampleClass<T>{

}

这里的尖括号中的T表示类型参数,可以指代任何类型。

这里的T可以用任意符号代替,但是java中会给出了一些标准。

T:代表一般的类

E:代表Element元素和Exception异常

K:代表key

V:代表Value,通常会配合K一起使用(只能出现一个K,K有它对应的Value,键值对)

S:代表Subtype子类型

我们利用泛型类将上面的代码再写一遍

//定义一个泛型Point类class Point<T>{private T x;private T y;public T getX() {return x;}public void setX(T x) {this.x = x;}public T getY() {return y;}public void setY(T y) {this.y = y;}}public class Generic {public static void main(String[] args) {//创建Point类对象Point<String> point = new Point<String>();//定义X和Ypoint.setX("东经80度");point.setY("北纬30度");//转成字符串类型String x = (String) point.getX();String y = (String) point.getY();//打印System.out.println("x = "+x);System.out.println("y = "+y);}}

和之前的代码没有太多的差距,但是我们再将Y定义成一个int类型的数据看一下效果。

编译器提醒我们在32行出现了错误需要我们进行修改!这就是泛型存在的意义。

泛型方法:

基本语句:

class exampleClass<T>{

public <E> E exampleMethod(E e){

System.out.println(e);

return e;

}

}

第一个<E>表示这个方法是一个泛型方法;

第二个E表示方法的返回值类型是E;

括号中的E表示传入的参数的类型是E,这个E被称为是参数化类型。

泛型类和泛型方法是可以共存的,在泛型类中有泛型方法,他们俩尖括号中的内容不是一定要相同的,泛型方法的参数类型是单独的,与泛型类无关!

泛型接口:

基本语法:

interface IMessage<T>{

public void print(T t);

}

子类实现这个接口:

(1)子类仍然是泛型类:

//定义一个泛型接口interface IMessage<T>{//抽象方法public void print(T t);}//定义一个类实现泛型接口class MessageImpl1<T> implements IMessage<T>{//覆写泛型接口的方法@Overridepublic void print(T t) {System.out.println(t);}}

(2)子类给出具体类型(子类就不是泛型类了):

//给出具体类型的类就不是泛型类了class MessageImpl2 implements IMessage<Integer>{//覆写接口方法@Overridepublic void print(Integer integer) {}}

通配符:

问号通配符:<?>

当我们定义了一个泛型类,在写一个方法的时候,要将这个泛型类当做参数传入,但是我们这是不能确定这个泛型类的具体类型,所以就有了问号通配符,帮我们接受这个泛型类包含的所有数据类型。

//泛型类class exampleClass2<T>{T t;//定义fun方法//利用问号通配符,接收泛型类所包含的所有数据类型public static void fun(exampleClass2<?> exampleClass){System.out.println(exampleClass);}}

但是用问号通配符的方法不可以修改泛型类对象的值,因为我们在这是不知道该属性的类型,所有不能进行修改。我们只能获取它的值,不能修改

这里77行我们试图修改,编译器就会提醒有错误。

上限通配符:<? extends A>

//泛型类class exampleClass3<T>{T t;//上限通配符public static void fun(exampleClass3<? extends Number> exampleClass3){System.out.println(exampleClass3);}}

上限通配符与问号通配符的不同就是让问号继承了一个父类,这个这个方法只会接受这个父类及其子类的类型。

这里也是不清楚该方法具体传入的参数的类型,所以也是只能获取不能修改

95行修改时报错。

下限通配符:<? super B>

//泛型类class exampleClass4<T>{T t;//下限通配符public static void fun(exampleClass4<? super Number> exampleClass4){System.out.println(exampleClass4);}}

下限通配符表示方法只能接收该类及其所有的父类的类型。

这里我们清楚所有的传入数据不是当下这个就是它的父类,所以可以通过向上转型进行修改,这里是一个天然的向上转型。

这里我们在修改的时候就不会报错。

三种通配符的使用特点:

1、三种通配符都可以用在方法上

2、只有上限通配符还可以用在泛型类和泛型接口的声明上

3、问号通配符和上限通配符只能获取数据不能修改

4、只有下限通配符可以对元素进行修改

类型擦除:

泛型只存在于编译阶段,当进入JVM中所有的泛型内容都会被擦除。普通泛型擦除为Object;有泛型上限的擦除为相应的泛型上限;有泛型下限的,擦除为相应的反省下限。反省的存在就只是为了在编译阶段帮助程序员检查类型错误的,所以在运行是它的意义就失去了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。