泛型的好处是在编译的时候检查类型安全,并能捕捉类型不匹配的错误,并且所有的强制转换都是隐式的和自动的,提高代码的重用率 泛型类:
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
定义格式: 修饰符 class 类名 <类型>{ } public class Generic<T> { }
A 在调用方法时使用?通配符的过程中无法使用add方法。
原因分析:因为通配符?代表任意的数据类型,但是当我们调用的时候或者用在方法的声明上,其实这个时候还是没有给?通配符一个指定的引用数据类型,那么Java出于安全起见,就不可能允许添加元素。
B 以上的add方法虽然无法调用,add<null>是例外。
原因分析:因为null可以给任意引用数据类型赋值,代表任意引用数据,但是很容易引起NullPointerException。
C 注意使用List<?>和List<Object>当作形参时的作用不能等同,比如当传入List<Integer>时List<?>可以接收,但是List<Object>无法接收。
原因分析:因为?代表任何参数类型可以接收,但是List<Object>中虽然Object是所有子类的父类,但是List<Object>不是List<Integer>的父类,List<Object>是ArrayList<Object>等类的父类,这就是为什么泛型前后要一致的原因,从数组的角度去理解集合就比如Object[ ] arr不是Integer[ ] arr1的父类。
public class WildCardTest<E> {
public static void main(String[] args) {
// ArrayList<Object> list2 = new ArrayList<Integer>();//泛型前后一致
ArrayList<?> list = new ArrayList<String>();
// list.add("122");//注意此处无法添加"122"字符串,但是可以添加null,因为null可以给任何引用数据类型赋值
list.add(null);//添加null没有报错
Object o = list.get(0);
System.out.println(list);
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(34);
// printCollection1(list1);//报错了,原因因为这里要接收的是List<Object>,那么可以接收的有ArrayList<Object>或者List<Object>等与List<Object>有继承关系的集合,但是无法接收ArrayList<Integer>,因为和List<Object>没有继承关系,写成List<?>才能使用
printCollection(list1);//?通配符可以正常接收
}
public static void printCollection (List<?> col){//此方法使用了无限通配符
for (Object object : col) {
System.out.println(object);
}
}
public static void printCollection1 (List<Object> col){//此方法没有使用泛型通配符
for (Object object : col) {
System.out.println(object);
}
}
}
原文链接:https://blog.csdn.net/l13591302862/article/details/82378622
B 在使用上界通配符时,无法调用add方法来添加非null的元素。
原因分析:由于上面已经说得很清楚了,<? extends E>作为形参时例如List<? extends E>这时最大类型是E和Object,但是我们不清楚最小的类型是什么,因为此时?这个通配符没有被赋值,我们调用add方法是要添加集合元素或者集合元素的子类,但是我们没法明确肯定该集合元素类型,或者比该集合元素范围更小的子类,那么Java就不会允许添加元素。
public class WildCardTest2 {
public static void main(String[] args) {
ArrayList<? extends Number> list = new ArrayList<>();
// list.add(3);报错了,无法添加非null元素
list.add(null);//没有报错
Object o = list.get(0);//用Object接收没有报错
Number n = list.get(0);//用Number接收没有报错
}
}
3. <? super E>:这个表明的是通配符的下界,通俗讲其取值范围就是E到最大值Object(因为Object是所有类的基类),就是大于等于E,小于等于Object类。
下界通配符<? super E>的使用:可以传入E或者E的父类
A 在使用下界通配符时,无法使用get方法获取Object以外的元素,或者需要向下转型,但是可能出现ClassCastException的异常。
原因分析:上界通配符,在使用get方法的时候,此时类型没有明确还是问号?我们只能明确其最大父类或者接口时,我们才能接收,但是我们只能明白<? super E>作为形参时例如List<? super E>时,只能明确Object是最大父类,其他的一概不知,所以只能Object o = list.get(0)。
B 可以使用集合的add方法添加E或者E的子类。
原因分析:上界通配符已经解释很清楚了,add方法添加元素时,?类型不确定就要明确该?类型的最小子类,只要比可能存在的最小子类或者子接口小的任意引用数据类型的对象,我们都可以将其添加,而下界通配符<? super E>当作形参时例如List<? super E>,此时E就是最小子类,此时add方法可以添加E或者E的父类或者接口。
public class WildCardTest3 {
public static void main(String[] args) {
ArrayList<? super Number> list = new ArrayList<>();
list.add(3);//没有报错,自动装箱成Integer,Number的子类
list.add(3.4F);//没有报错,自动装箱成Float,Number的子类
list.add(32L);//没有报错,自动装箱成Long,Number的子类
Object o = list.get(1);
// Integer i = list.get(0);//报错了,无法用Integer接收
}
}
public static void main(String[] args) {
// 1
int[] arr = {23,43,54};
int sum = add(arr);
System.out.println("sum="+sum);
// 2
int[] arr1 = {25,46,50,23,54,66,78};
int sum1 = add(arr1);
System.out.println("sum1="+sum1);
// API1.5之后出现了简化操作 ...只用于参数上称之为可变参数
// 同样是代表数组但是在调用这个可变参数时不可以创建数组(这就是简单之处)
// 直接将数组中的元素作为实际参数进行传递,其实编译成的class文件将这些实参先封装到一个数组中在进行传递
// 这些动作在编译器生成class文件时就帮你完成了
// 注意:可变参数一定要定义在参数列表的最后
// public static int add(int a,int...arr) 正确
// public static int add(int...arr,int a) 错误
int sum2 =add(23,43,54);
System.out.println("sum2="+sum2);
int sum3 = add(25,46,50,23,54,66,78);
System.out.println("sum3="+sum3);
}
// 两个整数 的和
public static int add(int a , int b)
{
return a + b ;
}
// 三个整数和
public static int add(int a , int b ,int c)
{
return a + b + c;
}
// 多个整数和1
/*public static int add(int[] arr)
{
int sum = 0 ;
for(int i = 0 ; i < arr.length ; i++ )
{
sum += arr;
}
return sum;
}*/
// 多个整数和2 API1.5之后的方法
public static int add(int.../*int类型的数据*/arr)//数组参数的简化表现形式
{
int sum = 0 ;
for(int i = 0 ; i < arr.length ; i++ )
{
sum += arr;
}
return sum;
}
}