第一章:ArrayList:
ArrayList介绍:
ArrayList存储元素:
1 package cn.zcb.demo01; 2 3 import java.util.ArrayList; 4 5 public class Test { 6 /* 7 * ArrayList 中是不装基础类型的 8 * */ 9 public static void main(String[] args) { 10 ArrayList <Integer> arrayList = new ArrayList<Integer>(); 11 arrayList.add(12); 12 arrayList.add(13); 13 arrayList.add(14); 14 arrayList.add(15); 15 16 //遍历 17 for (int i =0;i<arrayList.size();i++){ 18 System.out.println(arrayList.get(i)); 19 } 20 21 } 22 }
下面是存储自定义的数据类型:
1 package cn.zcb.demo01; 2 3 public class Person { 4 5 private String name; 6 private int age; 7 8 public Person(){} //空参 9 public Person(String name,int age){ //满参 10 super(); 11 this.name = name; 12 this.age = age; 13 } 14 //重写 toString() 方法,使print() 的时候不打印内存地址 15 public String toString(){ 16 return String.format("Person [name:%s age:%d]", name,age); 17 } 18 public void setName(String name){ 19 this.name = name; 20 } 21 public void setAge(int age){ 22 this.age = age; 23 } 24 public String getName(){ 25 return this.name; 26 } 27 public int getAge(){ 28 return this.age; 29 } 30 }
1 package cn.zcb.demo01; 2 3 import java.util.ArrayList; 4 5 public class Test { 6 public static void main(String[] args) { 7 ArrayList<Person> arrayList = new ArrayList<Person>(); 8 arrayList.add(new Person("tom",18)); 9 arrayList.add(new Person("egon",28)); 10 arrayList.add(new Person("jane",38)); 11 12 //遍历 13 for (int i=0;i<arrayList.size();i++){ 14 System.out.println(arrayList.get(i)); 15 } 16 17 } 18 } 19 /* 输出结果 20 Person [name:tom age:18] 21 Person [name:egon age:28] 22 Person [name:jane age:38] 23 * */
注意Person中的toString() 被重写了。
学习一个容器,我们有三个方面:
1,会存储对象
2,会遍历,取出对象
3,它自己所具有的特性!
ArrayList的 继承 实现关系:
Collection接口 的学习:
但是,list和 set 是有共同点的,就是 Collection接口!
Collection接口 的基本方法:
因为ArrayList 类 实现了 List 接口,而List 接口又继承自 Collection接口。所以,ArrayList 是Collection 的实现类!!!
我们下面通过实现类的重写方法来 学习Collection 中的基本方法!
穿插总结:
1 package cn.zcb.demo01; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 6 public class Test { 7 public static void main(String[] args) { 8 9 //以多态的形式调用 10 Collection <String> collection = new ArrayList<>(); 11 collection.add("a"); 12 collection.add("dfj"); 13 collection.add("i"); 14 System.out.println(collection); //根据输出结果可以推测,ArrayList 中重写了toString() !!! 15 /*输出: 16 *[a, dfj, i] 17 * */ //它表明ArrayList 是有序的。 18 19 collection.clear(); //此时的集合只是为空[ ],而不是释放! 20 21 /* 22 * contains () 方法 23 * boolean contains(Object obj); 注意参数是 Object obj 产生了多态!!! 24 * */ 25 boolean ret = collection.contains("a"); 26 System.out.println(ret); //false 27 28 collection.add("tom"); 29 ret = collection.contains("egon"); 30 System.out.println(ret); //false 31 ret = collection.contains("tom"); 32 System.out.println(ret); //true 33 34 collection.add("alex"); 35 System.out.println(collection); 36 //输出: [tom,alex] 37 38 /* 39 * toArray() 方法 40 * 转成一个数组。 数组类型是 Object [] 41 * */ 42 // String[] res = collection.toArray(); //错误!! 43 Object[] res = collection.toArray(); 44 //此时res 就是个数组了 45 for (Object s :res){ 46 System.out.println(s); //tom alex 47 } 48 // for (int i =0;i<res.length;i++){ 49 // System.out.println(res[i]); 50 // } 51 52 53 54 /* 55 * boolean remove(Object o) 方法 56 * 删除指定的元素 57 * 删除失败的时候,返回false 58 * 而且,只会删除第一个。不会删除ArrayList 中的每一个 59 * */ 60 System.out.println(collection); 61 collection.remove("tom"); 62 System.out.println(collection); 63 64 } 65 66 }
Iterator 接口 (Iterator 迭代器) 的学习:
之所以有迭代器,就是为了应对 对于不同的容器,取出的方式保持不变!!!
Iterator 是个接口,它对collection 进行迭代的迭代器!
Iterator 接口 中的抽象方法:
我们用它的实现类对象 来学习它的抽象方法。
我们可以知道,Collection 接口中定义了一个方法 Iterator iterator();
所以,我们可以通过使用Collection 的实现类 ArrayList, 然后它重写Collection 的iterator() 方法,该方法就返回了一个 Iterator 接口的对象。就可以用它了!
1 package cn.zcb.demo01; 2 3 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 7 public class Test { 8 public static void main(String[] args) { 9 ArrayList <String> arrayList = new ArrayList<>(); 10 arrayList.add("ad"); 11 arrayList.add("tom"); 12 arrayList.add("egon"); 13 arrayList.add("alex"); 14 15 //得到 Iterator 接口的 可用对象。 Collection 中的 Iterator iterator() 方法会返回! 16 //得到迭代器 17 Iterator iterator = arrayList.iterator(); //发生多态!方法的返回值是 Iterator 实现类的对象,具体是实现类是什么不重要! 18 while (iterator.hasNext()){ 19 System.out.println(iterator.next()); 20 } 21 } 22 23 }
迭代器的执行过程:
迭代器是遍历所有集合的通用模式!
而且迭代器只能使用一次,迭代完之后,就不能再次使用了!!!
除了使用while() 以外,也可以使用for 循环 来迭代!
1 package cn.zcb.demo01; 2 3 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 7 public class Test { 8 public static void main(String[] args) { 9 ArrayList <String> arrayList = new ArrayList<>(); 10 arrayList.add("ad"); 11 arrayList.add("tom"); 12 arrayList.add("egon"); 13 arrayList.add("alex"); 14 15 Iterator iterator = arrayList.iterator(); 16 while (iterator.hasNext()){ 17 System.out.println(iterator.next()); 18 } 19 20 //使用for 循环进行遍历, 注意:它比while 节约内存,因为 它的迭代器是个局部变量,而while的迭代器是个main中的变量。 21 for (Iterator iterator1 = arrayList.iterator();iterator1.hasNext();){ 22 System.out.println(iterator1.next()); 23 } 24 } 25 }
while的形式比for 的简洁。 for 比while 节约内存 ,for 循环执行完之后,就立即释放了内存,而while 要当main执行完毕之后!
集合迭代器 中的转型:
1 package cn.zcb.demo01; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.Iterator; 6 7 public class Test { 8 public static void main(String[] args) { 9 /* 10 * 集合Collection 可以存储任意的对象。 11 * */ 12 13 // Collection <String> collection = new ArrayList<>(); //我们通常使用的形式 。。 14 //但是,也可以使用下面的形式 15 Collection collection = new ArrayList(); //这时的 对象里可以有任意类型! 16 collection.add("tom"); //String 但是,放进去都被提升为了 Object类型 向上转型! 17 collection.add(1); //Integer 18 collection.add('1'); //Character 19 20 21 Iterator iterator = collection.iterator(); 22 while (iterator.hasNext()){ 23 // System.out.println(iterator.next()); //iterator.next() 的返回值的类型也是 Object 类型。 24 Object obj = iterator.next(); 25 System.out.println(obj); 26 } 27 //上述 虽然可以,但是如果此时想调用 子类的特有方法的时候就必须 要进行强转。强制向下强制。例如。想使用String() 的.length 属性 28 //所以,总结,在使用集合Collection 的时候,最好还是加上类型,这样可以避免 转型,以及后面 要使用子类的特有方法时候的向下强转。 29 30 } 31 }
总结,在使用集合Collection 的时候,最好还是加上类型!
增强的for 循环:
原来的接口 Collection 就不是根接口了,而是变成了Iterable .
这个Iterable 的出现就是 实现 增强的for循环。
案例:
集合中存储 我们自定义的Person 类型,然后用增强for 去遍历它!
1 package cn.zcb.demo02; 2 3 public class Person { 4 public String name; 5 public int age; 6 7 public Person(){} 8 public Person(String name,int age){ 9 this.name = name; 10 this.age = age; 11 } 12 }
1 package cn.zcb.demo01; //当前的包 2 import cn.zcb.demo02.Person; 3 import java.util.ArrayList; 4 5 public class Test { 6 public static void main(String[] args) { 7 ArrayList <Person> arrayList = new ArrayList<>(); 8 arrayList.add(new Person("tom",18)); 9 arrayList.add(new Person("alex",10)); 10 arrayList.add(new Person("egon",20)); 11 arrayList.add(new Person("tim",9)); 12 13 for (Person person : arrayList){ 14 System.out.println("Name: "+person.name + " Age: "+person.age); 15 } 16 } 17 }
增强for 循环是不能操作索引的,它的出现的主要目的是用来进行遍历!
泛型:
使用泛型(加入 尖括号),使得程序变得更加安全。因为如果没有使用泛型 的话,那么如果使用子类特有方法时候必须要强制,如果一个集合中有不同的类型,当迭代的时候就可能报错!
Java 中的伪泛型:
Java中的泛型只是在 编译之前体现的,一旦编译成功之后得到的class 文件是不能体现出泛型的!
如果不符合的数据,它在编译的时候就不会通过了,所以说 ,它是通过 编译的收到来保证安全的。
据说,C++ 就是真泛型。
泛型的定义与使用:
带有泛型的类:
E 接收的就是一个一种类型!
Interator<E> 也是一个带有泛型的类!
泛型就是使得 类中的方法的参数的类型 更加灵活。
带有泛型的接口:
使用接口的时候有两种使用方法:
1,先实现接口,不理会泛型。
这样,在使用实现类的时候一起指定具体的数据类型。
2,在实现接口,也指定了数据类型
这时候的数据类型就已经定了,就是固定的了,不灵活,
所以一般都是使用第一个。
使用泛型的好处:
最大的好处就是安全问题,主要是在强转的时候出现的。
例如,如果不用泛型指定具体的数据类型,此时可能会出现异常,如下程序:
1 //遍历 2 for (Object item :arrayList1){ 3 //强制转为 String 4 String s = (String)item; 5 System.out.println(s.length()); 6 //此时的问题是 因为没有使用泛型指定具体的数据类型,所以 7 //ArrayList 中可以存任意的数据类型, 8 //但是,此时第四个不是String ,它不能强转为String . 9 //于是,编译失败 10 }
!
将运行时期的报错提前到了编译时候。
泛型的通配符:
1 package cn.zcb.demo01; //当前的包 2 3 import com.sun.jdi.ArrayReference; 4 5 import java.util.ArrayList; 6 import java.util.Collection; 7 import java.util.HashSet; 8 import java.util.Iterator; 9 10 public class Test { 11 public static void main(String[] args) { 12 13 ArrayList<String> arrayList = new ArrayList<>(); 14 arrayList.add("tom"); 15 arrayList.add("egon"); 16 arrayList.add("ALEX"); 17 18 HashSet<Integer> hashSet = new HashSet<>(); 19 hashSet.add(10); 20 hashSet.add(54); 21 hashSet.add(5); 22 23 myIterator(arrayList); 24 myIterator(hashSet); 25 26 } 27 /* 28 * 现在的需求是 :定义个方法 既能遍历ArrayList 也可以遍历HashSet 29 * //它的参数 既不能是 ArrayList 也不能是 HashSet 30 * 只能是它们共同的接口 Collection 但是,Collection 的泛型用什么类型呢? 31 * 32 * 这又是个问题。 33 * 这里用泛型的通配符 , 这里用的不是* 而是 ? ! 34 * 35 * */ 36 public static void myIterator(Collection<?> collection){ 37 Iterator<?> it = collection.iterator(); 38 while (it.hasNext()){ 39 System.out.println(it.next()); 40 41 //这时的it 已经不确定是什么类型了,所以此时是不能强转的。 42 //所以总结:通配符? 的时候,只是用于遍历!!! 43 } 44 } 45 46 47 48 }
通配符一般只用来做遍历用。
泛型的限定:
为了解决上述通配符 不能进行强制转换,只能用来遍历的缺点,于是有了泛型的限定。
三个类 它们的父类都是 Employee.
此时我们想 写一个方法,然后调用三个子类的work() 方法。
如果方法的参数直接写为 ArrayList<?> arrayList ,
这时的?代表的是Object 类,如果调用work() 方法,必要要强制转为它们共有的父类Employee(方法走子类重写!!!),但是这是有风险的。 因为如果假设有一个新的类 ArrayList<String> arr,它里面的元素是不能强制转为Employee 的。
这时可以使用泛型的限定。
?代表子类不确定,但是它们的父类都是一定的。都是Employee。
限定有上限,也可以有下限。
关于多态的补充:
运行时候:成员变量是调父类, 成员方法是调子类。 (重点)
编译的时候:全部调用父类,父类没有报错。