泛型
泛型:Java集合有一个缺点,把一个对象丢进集合里去,集合就会忘掉这个数据的数据类型,当再次取出这个对象时,需要进行强制类型转换。为了解决这个问题,引入泛型这个概念。
泛型是一种推迟到创建对象,或者调用时才明确类型的特殊类型。
格式: <数据类型>
好处:(1)把运行时期的问题提前到编译期间,否则当你输入不当类型,运行时才会报类转换异常
(2)避免了强制转换,使用泛型 对象可以‘记住’输入类型
(3)优化了黄色警告线
注意:泛型在运行期擦除,且不存在泛型类
专门讲一下为什么不存在泛型,举例:
List<Integer> integers = new ArrayList<>();
List<String> strings = new ArrayList<>();
System.out.println(integers.getClass() == strings.getClass());
我们可以看到输出结果是TRUE,因为不管泛型的实际类型参数是什么,他们在运行时总有同样的类。不管为泛型形参传入那一种类型实参,对于Java来说,他们依然被当做同一个类处理,在内存中也只占一块内存空间.
泛型的类型通配符
当使用一个泛型类时,都应该为这个泛型传入一个类型实参。为了表示各中泛型 List 的父类,可以使用类型通配符:<?>。举例:
public void test (List <?> c){
for(int i=0;i<c.size();i++){
System.out.printli(c.get(i));
}
} // 不管什么类型都可以调用,其类型为Object
设定类型通配符的上限
public abstract class shape {
public abstract void draw(Canvas c);
}
public class Circle extends shape{
public void draw (Canvas c){
System.out.println(c);
}
}
public class Canvas{
public void drawAll(List<? extends shape> shapes){ // 同时画多个形状,使用被限制的泛型通配符
for(shape s:shapes){
s.draw(this);
}
}
}
List<? extends shape>就是个例子,这个未知类型一定是 shape的子类或本身,也就是说shape 就是这个通配符的上限
简而言之,这种指定通配符上限的集合,只能从集合中取元素
也称之为协变,对于协变的泛型只能调用返回类型作为返回值的方法。
注意:没有指定上限的泛型类,默认上限Object
设定通配符的下限
指定通配符下限的作用与上限刚好相反。通配符指定下限就是为了支持类型型变。举例: A <? super FOO>可以让 A A 赋给它,我们称之为逆变。
逆变的泛型类型,只能调用泛型类型作为参数的方法。
public abstract class demo {
public static void main(String[] args) {
// Comparator的实际类型是Treeset的父类,
TreeSet<String> ts1 =new TreeSet< >(new Comparator<Object>(){
public int compare(Object fst,Object Snd){
return hashCode()>Snd.hashCode()?1:hashCode()<Snd.hashCode() ? -1:0;
}
});
ts1.add("hello");
ts1.add("wa");
TreeSet<String> ts2 =new TreeSet< >(new Comparator<String>(){
public int compare(String first,String Second){
return first.hashCode()>Second.hashCode()?1:first.hashCode()<Second.hashCode() ? -1:0;
}
});
ts2.add("hello");
ts2.add("wa");
System.out.println(ts1);
System.out.println(ts2);
}
通过使用通配符下限来定义Treeset构造器的参数,就可以传入可用参数,增加代码灵活性。
增强For循环
格式: for(元素数据类型 变量:数组或集合){
变量;
}
举例:
for (Integer b : integers) {
System.out.println(b);
}
注意:增强for循环内部使用的是迭代器,所以不能直接增删元素,线程异常,出现并发修改异常。
可变参数
格式: 修饰符 返回值类型 方法名(数据类型… 变量名){}
注意事项:
这里的变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个
举例:
public static int add(int... a){
int sum = 0 ;
for(int s : a ){
sum += s ;
}
return sum;
}
Array类的asList()方法
不一一赘述了,举个嵌套的例子:
public static void main(String[] args) {
Student s1 = new Student("张三",23);
Student s2 = new Student("李四",23);
Student s3 = new Student("王五",23);
Student s4 = new Student("张三",18);
Student s5 = new Student("李四",18);
Student s6 = new Student("王五",18);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
ArrayList<Student> arrayList2 = new ArrayList<>();
arrayList2.add(s4);
arrayList2.add(s5);
arrayList2.add(s6);
List<ArrayList<Student>> arrayLists= new ArrayList<>();
arrayLists.add(arrayList);
arrayLists.add(arrayList2);
for (ArrayList<Student> list : arrayLists) {
System.out.println(list);
}
}
}
就是这么个例子,分两个班,班内各三个同学,遍历所有同学。