文章目录
- 泛型
- 问题引出
- 泛型定义
- 泛型的规则
- 泛型通配符
- 泛型的上限
- 泛型的下限
- 泛型接口
- 泛型方法
泛型
JDK1.5 之后追加的新特性。其主要解决 ClassCastException 的问题,在进行对象的向下转型时存在的安全隐患。
问题引出
在设计一个成员属性接受多种类型的类时,在早期 Java 版本中,我们通过 Object 类来定义这样的属性。但是,渐渐地问题就出现了,比如在设计一个接收 int 类型的和 String 类型的属性,做一些操作时,编译器检查不出错误,执行时就会抛出错误。( 向下转型是不安全的 )
为了在程序编译的过程中指出程序的错误,可以大大提高开发效率。
泛型定义
在 JDK1.5 之后提供泛型技术,泛型的本质在于,类中的属性类型或方法的参数类型和返回值类型可以由对象实例化时动态决定。
使用泛型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Test<T>{ private T value; public void setValue(T value){ this.value = value; } public T getValue(){ return this.value; } } public class Main{ public static void main(String[] args){ Test<Integer> test = new Test<Integer>(); } }
泛型的规则
- 泛型只允许使用引用数据类型,使用基本数据类型必须使用包装类,如 int 必须用 Integer。
- 从JDK1.7开始,泛型对象实例化可以简写成:复制代码1
2Test<Integer> test = new Test<>();
泛型通配符
泛型通配符解决了泛型的引用传递问题。
在上面的代码中我们修改以下主类,希望输出不同泛型的Test对象内容,观察
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30public class Main{ public static void main(String[] args){ Test<String> testA = new Test<String>(); Test<Integer> testB = new Test<Integer>(); testA.setValue("字符串"); testB.setValue(12); fun(testA); fun(testB); } /* 1、重载函数 public static void fun(Test<String> test){ System.out.println(test.getValue()); } public static void fun(Test<Integer> test){ System.out.println(test.getValue()); } */ /* 2、这种方式不会检查泛型,不安全 public static void fun(Test test){ test.setValue(10.1); System.out.println(test.getValue()); } */ // 3、安全的泛型引用传递 public static void fun(Test<?> test){ //test.setValue(10.1); System.out.println(test.getValue()); } }
1、只执行 1 处的代码,编译发现:
1
2错误: 名称冲突: fun(Test<Integer>)和fun(Test<String>)具有相同疑符
也就是说这样的重载是错误的,无法通过编译
2、只执行2处的代码,先注释掉test.setValue(10.1);
,编译执行发现:
1
2
3字符串 12
成功了,那么加上test.setValue(10.1);
,编译再执行发现:
1
2
3
4
5
6注: Main.java使用了未经检查或不安全的操作。 注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。 10.1 10.1
编译发出了不安全警告,执行发现我们对象的内容都被改成了double类型。
3、只执行3处的代码,编译发现:
1
2
3
4
5
6
7Main.java:26: 错误: 不兼容的类型: double无法转换为CAP#1 test.setValue(10.1); ^ 其中, CAP#1是新类型变量: CAP#1从?的捕获扩展Object 注: 某些消息已经过简化; 请使用 -Xdiags:verbose 重新编译以获得完整输出
发生了错误,告诉我们这里不能使用 double 类型,因为我们的对象属性是 String 类型的。
注释掉test.setValue(10.1);
,编译执行发现:
1
2
3字符串 12
实现功能,这里观察到使用泛型通配符 ?进行引用传递更加安全。
泛型的上限
- 泛型的上限是指泛型只能是某个类或这个类的子类
T extends Myclass
复制代码1
2
3
4class Test<T extends Myclass>{ ... }
? extends Myclass
复制代码1
2
3
4public static void fun(Test<? extends Myclass> test){ ... }
泛型的下限
- 泛型的下限是指泛型只能是某个类或这个类的父类
T super Myclass
复制代码1
2
3
4class Test<T super Myclass>{ ... }
? super Myclass
复制代码1
2
3
4public static void fun( Test<? super Myclass> test ){ ... }
泛型接口
1
2
3
4interface ITest<T> { public String put(T t); }
两种实现方式:
1、在子类中继续设置泛型定义
1
2
3
4
5
6class MTest<S> implements ITest<S>{ public String put(S s){ return "PUT:" + s; } }
2、在子类实现父接口的时候直接指定泛型类型
1
2
3
4
5
6class MTest implements ITest<String>{ public String put(String s){ return "PUT:" + s; } }
泛型方法
即使不在一个泛型类中也可以使用泛型方法。
1
2
3
4
5
6
7
8
9
10
11
12public class Main{ public static void main(String[] args){ Integer[] nums = fun(1,2,3,4,5); for(int n:nums){ System.out.print(n + " "); } } public static <T> T[] fun(T ... args){ return args; } }
编译执行
1
2
3
4
5注: Main.java使用了未经检查或不安全的操作。 注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。 1 2 3 4 5
最后
以上就是靓丽大象最近收集整理的关于Java 泛型的全部内容,更多相关Java内容请搜索靠谱客的其他文章。
发表评论 取消回复