JAVA泛型详解

Java泛型详解

目录:

1.问题现象,如何处理,新的问题

2.泛型介绍,以及注意点

3.定义泛型类

4.定义泛型方法

5.类型擦除

6.限制使用类型

 

 

 

 

1.问题现象,如何处理,新的问题

问题现象:

我们都知道在使用一个变量之前我们都需要先定义好变量的数据类型,然后再使用变量,但是如果我们需要使用一个变量它的数据类型既可以是int又可以是String...那么怎么做到呢?

我们都知道两点

1.自动装箱:基本数据类型可以自动装箱,被转换成对应的包装类;

2.向上转型Object 是所有类的祖先类,任何一个类的实例都可以向上转型为 Object 类型,例如:

·int --> Integer --> Object

·double -->Double --> Object

·String --> Object

那么问题得到解决:

我们将数据的类型定义为object,如下代码:

1. class Point{

2.     Object x = 0;

3.     Object y = 0;

4. 

5.     public Object getX() {

6.         return x;

7.     }

8.     public void setX(Object x) {

9.         this.x = x;

10.     }

11.     public Object getY() {

12.         return y;

13.     }

14.     public void setY(Object y) {

15.         this.y = y;

16.     }

这里的代码将XY的类型都定义为object,这样在传入数据的时候就可以实现我们之前说的问题,可以实现在变量类型未知的请况下的赋值。

 

但是问题来了:如何实现数据的提取与使用?

向下转型存在着风险,而且编译期间不容易发现,只有在运行期间才会抛出异常,所以要尽量避免使用向下转型。运行上面的代码,第12行会抛出 java.lang.ClassCastException 异常。

 

 

 

 

2.泛型介绍,以及注意点

定义泛型类

怎么处理?

可以使用泛型类(Java Class),它可以接受任意类型的数据。所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。

1. public class Demo {

2.     public static void main(String[] args){

3.         // 实例化泛型类

4.         Point p1 = new Point<</span>Integer, Integer>();

5.         p1.setX(10);

6.         p1.setY(20);

7.         int x = p1.getX();

8.         int y = p1.getY();

9.         System.out.println("This point is" + x + ", " + y);

10.        

11.         Point p2 = new Point<</span>Double, String>();

12.         p2.setX(25.4);

13.         p2.setY("东京180");

14.         double m = p2.getX();

15.         String n = p2.getY();

16.         System.out.println("This point is" + m + ", " + n);

17.     }

18. }

19. 

20. // 定义泛型类

21. class Point<</span>T1, T2>{

22.     T1 x;

23.     T2 y;

24.     public T1 getX() {

25.         return x;

26.     }

27.     public void setX(T1 x) {

28.         this.x = x;

29.     }

30.     public T2 getY() {

31.         return y;

32.     }

33.     public void setY(T2 y) {

34.         this.y = y;

35.     }

36. }

首先解释一下上面的代码:

1.class Point<</span>T1, T2>这里的<</span>T1, T2>是自定义的标识符,用来表示类型参数,T1T2是类 型参数的占位符,在实际运行的时候会被真正的类型替代。

2.传值参数(我们通常所说的参数)由小括号包围,如 (int x, double y)

类型参数(泛型参数)由尖括号包围,多个参数由逗号分隔,如  

3.类型参数在类后给出,在类中就可以进行使用了,类型参数标识符要使用合法的标识符,一般来说,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型(这个只是方便规范)。

4.泛型类在实例化的时候必须要进行给定具体的类型,也就是相当于函数中参数必须要传,格式为:

    className variable = new className();

也可以省略等号右边的数据类型,但是会产生警告,即:

className variable = new className();

5.因为在使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险

6.·类型参数只能用来表示引用类型,不能用来表示基本类型,如  intdoublechar 等。但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。

 

定义泛型方法:

 Public void add(V1 a,V2 b){

V1 m =x;

V2 n =y;

System.out.println(“xy”+x+y);

}

需要注意到的是泛型的方法和泛型类没有什么关系

同时泛型方法的使用不用像泛型类一样要事先定义好,编译器会自动根据传入参数的类型查找出相应类型

总而言之,泛型方法除了定义上与其他方法有些不同,其他都是一样的。

 

 

类型擦除

如果在使用泛型时没有指明数据类型,那么就会擦除泛型类型

1. public class Demo {

2.     public static void main(String[] args){

3.         Point p = new Point();  // 类型擦除

4.         p.setX(10);

5.         p.setY(20.8);

6.         int x = (Integer)p.getX();  // 向下转型

7.         double y = (Double)p.getY();

8.         System.out.println("This point is" + x + ", " + y);

9.     }

10. }

11. 

12. class Point<</span>T1, T2>{

13.     T1 x;

14.     T2 y;

15.     public T1 getX() {

16.         return x;

17.     }

18.     public void setX(T1 x) {

19.         this.x = x;

20.     }

21.     public T2 getY() {

22.         return y;

23.     }

24.     public void setY(T2 y) {

25.         this.y = y;

26.     }

27. }

如上代码在没有传入相应的类型之后再使用之后就又需要向下转型,这样的话就和我们之前最开始的代码没有区别了

 

 

 

限制泛型的可用类型

在上面的代码中,类型参数可以接受任意的数据类型,只要它是被定义过的。但是,很多时候我们只需要一部分数据类型就够了,用户传递其他数据类型可能会引起错误。例如,编写一个泛型函数用于返回不同类型数组(Integer 数组、Double 数组、Character 数组等)中的最大值:

1. public <</span>T> T getMax(T array[]){

2.     T max = null;

3.     for(T element : array){

4.         max = element.doubleValue() > max.doubleValue() ? element : max;

5.     }

6.     return max;

7. }

上面的代码会报错,doubleValue() 是 Number 类的方法,不是所有的类都有该方法,所以我们要限制类型参数 T,让它只能接受 Number 及其子类(Integer、Double、Character 等)。

通过 extends 关键字可以限制泛型的类型,改进上面的代码:

1. public <</span>T extends Number> T getMax(T array[]){

2.     T max = null;

3.     for(T element : array){

4.         max = element.doubleValue() > max.doubleValue() ? element : max;

5.     }

6.     return max;

7. }

表示 T 只接受 Number 及其子类,传入其他类型的数据会报错。这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的 extends 已经不是继承的含义了,应该理解为 T 是继承自 Number 类的类型,或者 T 是实现了 XX 接口的类型。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值