泛型
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
参数化类型:将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
参数化类型可以用在类,方法和接口中,分别被称为:泛型类,泛型方法,泛型接口
泛型的好处
- 把运行时期的错误提前到了编译期间
- 避免了强制类型转换
泛型类
定义格式:修饰符 class 类名 < 类型 > { } (如 public class Run< T > { } ,其中,T为随意标识,T ,E ,V ,K 一般都用来标识泛型)
// Box.java
public class Box<T> { // 泛型类
private T t; // 泛型
public void add(T t) { // 可以接收任何类型
this.t = t;
}
public T get() {
return t;
}
// main.java
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("菜鸟教程"));
System.out.printf("整型值为 :%d\n\n", integerBox.get()); // 整型值为 :10
System.out.printf("字符串为 :%s\n", stringBox.get()); // 字符串为 :菜鸟教程
}
}
泛型方法
定义格式:修饰符< 类型 > 返回值类型 方法名( 类型 变量名 ){ },(如 public < T > void run( T t ) { })
public class Demo{
public static void main(String[] args) {
Demo demo = new Demo();
demo.run(1); // 1 is running
demo.run(3.33333333); // 3.33333333 is running
demo.run("小飞侠"); // 小飞侠 is running
}
public <T> void run(T t){
System.out.println(t + " is running");
}
}
泛型接口
定义格式:修饰符 interface 接口名 < 类型 > { } ,如( public interface Generic < T > { } )
// Run.java
public interface Run<T> { // 泛型接口
void run(T t);
}
// RunImpl.java
public class RunImpl<T> implements Run<T> { // 泛型接口的实现类
@Override
public void run(T t) {
System.out.println(t + " is running");
}
}
//Demo.java
public class Demo{
public static void main(String[] args) {
RunImpl<Object> r = new RunImpl<>();
r.run("s"); // s is running
r.run(1); // 1 is running
boolean flag = true;
r.run(flag); // true is running
}
}
类型通配符
- 类型通配符:< ? >
- List< ? >:表示元素类型未知的List,他的元素可以匹配任何类型
- 这种带通配符的List仅表示他是各种泛型List的父亲,并不能把元素添加到其中
设置类型通配符的上限
类型通配符上限:< ? extends 类型 > ,List< ? extends Number >表示他的类型是Number或者他的子类型
设置类型通配符的下限
类型通配符下限: < ? super 类型 > ,List< ? super Number > 表示他的类型是Number或者他的父类型
public static void main(String[] args) {
// Object > Number > Integer
// 类型通配符
List<?> list = new ArrayList<Object>();
List<?> list1 = new ArrayList<Number>();
List<?> list2 = new ArrayList<Outer.Inner>();
// 类型通配符上限
List< ? extends Number> list3 = new ArrayList<Number>();
List< ? extends Number> list4 = new ArrayList<Integer>();
// 类型通配符下限
List< ? super Number> list5 = new ArrayList<Number>();
List< ? super Number> list6 = new ArrayList<Object>();
}
可变参数
可变参数指参数个数可变,用作方法的形参出现,方法参数则可以为不定数量
-
格式:修饰符 返回值类型 方法名( 数据类型 … 变量名 ){ } ,如( public static int sum( int … a ))
-
可变参数变量其实是一个数组,如 int … a ,其实a就是一个int类型的不定长数组
-
如果一个方法有多个参数,并且包含可变参数,那么可变参数要放在参数列表的最后面
public class Demo{
public static void main(String[] args) {
Demo.sum(1,2,3,4,5,6,7,8,9,10); // 总数为:55
Demo.sum("张三",true,1,2,3,4,5,6,7,8,9,10); // 姓名为:张三 flag为:true 总数为:55
}
public static void sum(int ... a){ // 可变参数,int ... a 实际代表 a 为一个不定长整数数组
int sum = 0;
for (int i:a) {
sum += i;
}
System.out.println("总数为:" + sum);
}
public static void sum(String name, boolean b,int ... a){ // 可变参数必须放在最后面
int sum = 0;
for (int i:a) {
sum += i;
}
System.out.println("姓名为:" + name + "\tflag为:" + b + "\t总数为:" + sum);
}
}
可变参数常用方法
- Arrays工具类中的静态方法:public static < T > List < T > asList( T … a ):返回由指定数组支持的固定大小的列表
- List接口中的静态方法:public static < E > List < E > of ( E … elements ):返回包含任意数量元素的不可变列表
- Set接口中的静态方法:public static < E > Set < E > of (E … elements):返回一个包含任意数量元素的不可变集合
- 该方法返回的集合不能做增删操作,没有修改的方法,并且赋值时不能赋予重复值
public static void main(String[] args) {
List<String> list = Arrays.asList("I","Love","Java");
List<String> list1 = List.of("I", "Love", "Java");
Set<String> list2 = Set.of("I", "Love", "Java");
// list.add() ,list.remove 这两种方法,三者都不能执行
// asList可以执行 list.set() 方法,List.of无法执行,Set.of没有该方法
// Set<String> list2 = Set.of("I", "Love", "Java","Java"); 是错误的,不能录入重复值
}