JDK5泛型和可变参数
泛型和可变参数在我们学习类,集合时是必不可缺的,我们可以通过泛型和可变参数简化编译代码以便于更好地达到目的
泛型概述
泛型:
- JDK5引入的特性,提供了编译时类型安全检测机制,该机制允许在变成时检测到非法的类型;
- 它的本质是参数化类型,操作数的数据类型被指定为一个参数
- 将类型由原本的具体的类型参数化,然后在使用和调用时传入具体的 类型
泛型定义格式:
- <类型>:指定一种类型的格式;这里的类型可以看成形参
- <类型1,类型2...>:指定多种类型的格式,多种类型之间用逗号隔开
- 将来具体调用的时候给的类型可以看作实参,并且实参的类型只能是引用数据类型
泛型的好处:
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换
下面给出代码实例:
代码语言:javascript复制import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class Demo1 {
public static void main(String[] args) {
//泛型就是集合后面的<>,你可以在里面提前标记集合的类型,防止编译后报错,可以将报错信息提前至编译时
//这里没有使用泛型,在后续add中,你可以添加int,double类型但编译器不提示,直到你运行时产生报错
Collection c = new HashSet();
//这里使用泛型,在后续add中,你无法可以添加除String以外的类型,若添加后编译器报错
Collection<String> cc =new HashSet<>();
//包括迭代器Iterator也有泛型
//这里没有使用泛型,在后续的赋值中,你需要采用强制转换(int)it.next()才能赋值或使用;
Iterator<String> it = c.iterator();
//这里使用泛型,在后续的赋值中,你不需要采用强制转换(int)it.next()赋值就可以直接使用
Iterator<String> itt = cc.iterator();
}
}
泛型类
泛型类的定义格式:
代码语言:javascript复制//模板:
修饰符 class 类名<类型>{
}
下面给出泛型类和应用泛型类的实例:
代码语言:javascript复制public class Demo2 {
public static void main(String[] args) {
//这里首先用String作为T
testClass1<String> tc = new testClass1<String >();
tc.setT("Jorry");
tc.printT();
//这里使用int作为T
testClass1<Integer> tcc = new testClass1<Integer>();
tcc.setT(10);
tcc.printT();
}
}
代码语言:javascript复制//在这里设置T作为泛型,整个类变成泛型类
public class testClass1<T> {
//内部定义时,T作为一种数据类型来使用
public T t;
public void setT(T t){
this.t = t;
}
public void printT(){
System.out.println(t);
}
}
编译结果:
代码语言:javascript复制Jorry
10
我们可以看到,我们在类上定义的T后来在main中直接赋值并使用
泛型方法
泛型方法的定义格式:
代码语言:javascript复制public class 类名 {
//泛型方法:
public<T> void 方法名(T t){
......
}
}
下面给出泛型方法和应用泛型方法的实例:
代码语言:javascript复制public class Demo1 {
public static void main(String[] args) {
Demo2 d = new Demo2();
d.show("s");
d.show(10);
}
}
代码语言:javascript复制public class Demo2 {
//泛型方法:
public<T> void show(T t){
System.out.println(t);
}
}
编译结果:
代码语言:javascript复制s
10
我们可以看到,通过一个方法就可以输出各种类型的数值
泛型接口
泛型接口的定义格式:
代码语言:javascript复制public interface Demo3<T> {
void show(T t);
}
泛型接口需要由泛型类来继承才可使用:
代码语言:javascript复制public class Demo2<T> implements Demo3<T>{
public void show(T t){
......
}
}
下面给出泛型接口和应用泛型接口的实例:
代码语言:javascript复制public class Demo1 {
public static void main(String[] args) {
Demo2 d = new Demo2();
d.show(10);
d.show("Jorry");
}
}
代码语言:javascript复制public class Demo2<T> implements Demo3<T>{
public void show(T t){
System.out.println(t);
}
}
代码语言:javascript复制public interface Demo3<T> {
void show(T t);
}
编译结果:
代码语言:javascript复制10
Jorry
我们通过泛型接口定义方法头,在泛型类中重写方法,最后在main中使用
类型通配符
为了表示各种泛型List的父类,可以采用类型通配符:
- 类型通配符:<?>
- List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
- 这种带通配符的List仅表示各种泛型List的父类,并不能把元素添加其中
如果我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限:
- 类型通配符上限:<? extends 类型>
- List<? extends Number>:它表示的类型是Number或子类
除了指定类型通配符的上限还可以指定下限:
- 类型通配符下限:<? super 类型>
- List<? super Number>:他表示的类型是Number或父类
下面给出类型通配符的代码解释:
代码语言:javascript复制import java.util.ArrayList;
import java.util.List;
public class Demo1 {
public static void main(String[] args) {
//正常类型通配符
List<?> l1 = new ArrayList<Object>();
List<?> l2 = new ArrayList<Number>();
List<?> l3 = new ArrayList<Integer>();
//上限类型通配符
List<? extends Number> l4 = new ArrayList<Integer>();//这里上限是Number,所以Object不能用
//下限类型通配符
List<? super Number> l5 = new ArrayList<Object>();//这里下限是Number,所以Integer不能用
}
}
可变参数
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数的个数就是可变的了
格式:
代码语言:javascript复制修饰符 返回值类型 方法名(其他类型 类型名,数据类型... 变量名){
}
下面给出实例:
代码语言:javascript复制public class Demo1 {
public static void main(String[] args) {
//调用sum方法
sum(10,20);
sum(10,20,30,50);
}
//书写sum可变参数方法(a实际上是数组)
public static void sum(int... a){
int sum=0;
for (int i : a){
sum = i;
}
System.out.println(sum);
}
}
结束语
好的,关于泛型和可变参数的话题就到这里