泛型
概念
- 泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类、泛型接口、泛型方法
- 语法:<T,…>T称为类型占位符,表示一种引用类型
优点
- 提高代码的可复用性
- 防止类型转换异常,提高代码的安全性
- 将运行时期异常提前到了编译时期
- 解决了黄色警告线问题
- 避免了强制类型转换
常见的泛型变量名
- E:元素(Element),多用于java集合框架
- K:关键字(Key)
- N:数字(Number)
- T:类型(Type)
- V:值(Value)
泛型方法
规则
- 所有的泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回值之前
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开.一个泛型参数,也被称为一个类型变量,用于指定一个泛型类型名称的标识符
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符
- 泛型方法的声明和其他方法一样.注意类型参数只能代表引用类型,不能是基本类型.
示例:
public class Test {
public static void main(String[] args) {
//定义三个不同类型的变量
int text1 = 10;
String text2 = "hello";
double text3 = 1.2;
print(text1);
print(text2);
print(text3);
}
//泛型方法
public static <E>void print (E text){
System.out.println(text);
}
}
执行结果
泛型类
规则
- 泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分
- 和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数用逗号隔开
- 一个泛型参数,也被称之为一个类型变量是用于指定一个泛型类型名称的标识符,因为他们接受一个或多个参数.
示例
//泛型类
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
//测试类
public class Test {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());
System.out.printf("字符串为 :%s\n", stringBox.get());
}
}
执行结果
泛型接口
泛型接口的定义
public interface TestInterface<T> {
public void print() ;
}
泛型接口的实现
//实现1
public class Testimplementation1 implements TestInterface<String>{
@Override
public void print() {
System.out.println("Hello Testimplementation1");
}
}
//实现2
public class Testimplementation2<T> implements TestInterface<T>{
@Override
public void print() {
System.out.println("Hello Testimplementation2");
}
}
//测试
public class Test {
public static void main(String[] args) {
Testimplementation1 test1 = new Testimplementation1();
Testimplementation2<String> test2 = new Testimplementation2<String>();
test1.print();
test2.print();
}
}
执行结果
泛型的上下限
public class TestGeneric {
//制订了泛型的上界,为Person
//参数是Person和Person的子类(间接的也可以)
public void printCollection1(Collection<? extends Person> c) {
}
//制订了泛型的下界,为Person
//参数是Person和Person的父类(间接的也可以)
public void printCollection2(Collection<? super Person> c) {
}
}
可变参数
- 在Java5中提供了可变参数,允许在调用方法时传入不定长度的参数.
为什么会出现可变参数
举个栗子:
- 以爱好为例,有的人没有爱好,有的人有一个爱好,有的人有两个爱好…有的人有100个爱好
- 我现在要定义一个方法,打印这些爱好,我怎么办呢?写一百个重载的方法吗?
- 这也太傻了,有了可变参数后,一个方法搞定
public void printHobby(String ... hobbys) {
//判断参数是否为空
if(hobbys == null || hobbys.length == 0) {
System.out.println("I have no hobby ....");
}else {
//创建可变字符串
StringBuilder sb = new StringBuilder("I like ");
//遍历,将参数追加到可变字符串里
for (String h : hobbys) {
sb.append(h + ", ");
}
//删除最后的那个","
sb.deleteCharAt(sb.length() - 2);
//打印
System.out.println(sb);
}
}
//测试
public static void main(String[] args) {
Hobby h = new Hobby();
h.printHobby();
h.printHobby("eatting");
h.printHobby("eatting", "fishing");
h.printHobby("eatting", "fishing", "sleeping");
h.printHobby("eatting", "fishing", "sleeping", "dadoudou");
}
执行结果
注意事项
- 在定义方法时,在最后一个形参后加上三点 …,就表示该形参可以接受多个参数值,多个参数值被当成数组传入。
- 可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数
- 由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数
- Java的可变参数,会被编译器转型为一个数组
- 变长参数在编译为字节码后,在方法签名中就是以数组形态出现的。这两个方法的签名是一致的,不能作为方法的重载。如果同时出现,是不能编译通过的。可变参数可以兼容数组,反之则不成立
- 可变参数常用于集合,在JKD提供的工具类源码中经常见