集合的含义:
集合是一个可变的容器,可以随时向集合中添加元素,也可以随时从集合中删除元素。另外,集合还提供了若干个用来操作集合中数据的方法。集合里的数据,我们称之为元素(elements);集合只能用来存储引用类型的数据,不能存储八大基本数据类型的数据。
泛型
Java SE 5.0 以后,可以使用新特性”泛型”,用来指定要存放在集合中的对象类型。避免了强制转换的麻烦。
public class Person<T> {private T idCard;public Person(T idCard) {this.idCard = idCard;}public static void main(String[] args) {Person person = new Person<String>("1001");}
/*** 当一个子类继承带有泛型的父类时,一般情况下要给泛型参数赋值具体类名*/
Class Student extends Person<Integer>{public Student(Integer idcard){super(idcard);
}class Teacher<E> extends Person<E>{public Teacher(E idcard){super (idcard);
}class Persident extends Person{public Presidert(Object idCard){super (idcard);
}
}
}}}
泛型接口
Public interface MyComparable<T,M>{public int mycompare(T o1, M o2);public static void main(String[] args) {Employee[] employees = new Employee[3];employees[0] = new Employee("John Doe", 23);employees[1] = new Employee("Bane Doe", 33);employees[2] = new Employee("Yane Doe", 18);
Comparator c = new Comparator<Employee>(){
public int compara(Employee o1 ,Employee o2){return o1.mycompare(o1,o2);
}
};
Arrays.sort(employees,c);
System.out.println(Arrays.toString(employees));
}//子类实现接口: 通常子类要给泛型接口的泛型参数赋值具体类型名class Employee implements MyComparable<Employee, Employee> {String name;int age;public Employee(String name ,int age){this.name = name;this.age = age;};//在我们自己定义的方法,来实现比较规则public int mycompare(Employee o1, Employee o2) {return o2.age - o1.age;}@Overridepublic String toString(){return name + " " + age;}}
泛型方法:泛型应用在方法上, 位置位于返回值类型的前面
案例演示:定义一个工具类,用于比较两个对象长得是否一样。
public class MyUtil{public static <T> boolean equals(T t1,T t2){return t1.equals(t2);
}
public class MyUtil{//工具类public static <T> boolean equals(T t1,T t2){return t1.equals(t2);}public static void main(String[] args) {Cat c1 = new Cat("十八八");Cat c2 = new Cat("十八八");//泛型方法在调用期间,不需要指定具体类型,只需要传入具体对象, 编译器会自动推断对象的类型//泛型方法调用期间,并没有给泛型参数赋值。下面的案例是c1给t1,c2给t2赋值,没有给T赋值。boolean equals = MyUtil.equals(c1, c2);System.out.println(equals);}
}
class Cat{//自定义的类都应该重写equals(),toString()等方法String name;public Cat(String name){this.name = name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Cat cat = (Cat) o;return Objects.equals(name, cat.name);}@Overridepublic int hashCode() {return Objects.hashCode(name);}
}}
泛型通配符: ? 用于表名不关心调用时的具体类型。
public class MyUtil {/*** 将集合元素打印到控制台上*/public static void print(List<?> lists){for (int i = 0; i < lists.size(); i++) {System.out.println(lists.get(i));}}/*** 上边界的定义: <? extends 具体类名>* 具体使用的时候,可以是上边界的任何子类型或者是本类型* @param list*/public static void print2(List<? extends Number> list){for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}/*** 下边界的定义:<? super 具体类名>* 具体使用的时候,可以是下边界的任何父类型或者本类型* @param*/public static void print3(List<? super Integer> list){for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}public static void main(String[] args) {List<Integer> nums = new ArrayList<Integer>();nums.add(1);nums.add(2);nums.add(3);MyUtil.print(nums);List<Long> ns = new ArrayList<Long>();ns.add(1L);ns.add(2L);ns.add(3L);MyUtil.print(ns);//上边界的测试:print2(new ArrayList<Long>());print2(new ArrayList<Number>());//print2(new ArrayList<Object>()); 最高到达Number类型//下边界的测试:print3(new ArrayList<Integer>());print3(new ArrayList<Number>());print3(new ArrayList<Object>());//print3(new ArrayList<Long>()); Long和Integer没有关系。}
}
集合与数组
-
数组是定长的容器,一旦实例化完成,长度不能改变。集合是变长的,可以随时的进行增删操作。
-
数组中可以存储基本数据类型和引用数据类型的元素,集合中只能存储引用数据类型的元素。
-
数组的操作比较单一,只能通过下标进行访问。集合中提供了若干个方便对元素进行操作的方法
-
在存储引用类型时,集合与数组,存储的其实都是==对象的地址==
集合框架体系图
Collection接口
含义:Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义了他们三个子接口的共同方法。既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。作为父接口,其子类集合的对象,存储元素的特点,可能是无序的,也可能是有序的,因此在父接口中并没有定义通过下标获取元素的方法功能。
常用方法:
public class CollectionDemo {public static void main(String[] args) {//使用多态的向上造型创建一个子类型对象Collection<String> c1 = new ArrayList<>();//1. E add(E e) 向集合中添加元素c1.add("A");c1.add("B");c1.add("C");//2. boolean isEmpty()boolean empty = c1.isEmpty();System.out.println("empty: " + empty);//3. int size(): 返回的是集合元素的个数System.out.println(c1.size());//4. String toString()System.out.println(c1);Collection<String> c2 = new ArrayList<>();c2.add("B");c2.add("C");c2.add("D");//5. addAll(Collection c)c1.addAll(c2);System.out.println(c1);/** 6. boolean contains(Object o):* 查看是否包含字符串 "B"*/boolean b = c1.contains("B");System.out.println("是否包含字符串B :"+b);/** 7. boolean containsAll(Collection c)* 查看c1是否包含c2*/boolean b1 = c1.containsAll(c2);System.out.println("c1集合是否包含c2集合:"+b1);/** 8. boolean equals(Object o)* 测试: 创建一个新的集合c3 添加元素 "A" "B" "C" "B","D","D"* 判断两个集合是否相同*/Collection<String> c3 = new ArrayList<>();c3.add("A");c3.add("B");c3.add("C");c3.add("B");c3.add("C");c3.add("D");System.out.println("c1和c3相同吗? :" + c1.equals(c3));/** 9. boolean remove(Object o)* 移除c1集合里的元素B,并查看剩下的元素 */boolean d = c1.remove("B");System.out.println(" 移除元素B :" + d);System.out.println(c1);/** 10. boolean removeAll(Collection<?> c)* 解析: 从集合中删除另一个集合c中所具有的元素。** 新建一个集合c4, 添加元素"B","C"* 测试c1移除子集c4 */Collection<String> c4 = new ArrayList<>();c4.add("B");c4.add("C");c1.removeAll(c4);System.out.println(c1);/** 11. boolean retainAll(Collection c)* 测试:向c1里添加"E","F","G", 然后保留子集c5, c5里的元素有"A","E" */c1.add("E");c1.add("F");c1.add("G");Collection<String> c5 = new ArrayList<>();c5.add("A");c5.add("E");c5.add("H");c1.retainAll(c5);System.out.println(c1);/** 12. void clear():* 测试:清空c1 */c1.clear();System.out.println(c1);System.out.println(c1.size());}
}
集合的迭代
1. 集合的迭代,就是指集合的遍历操作。2. 几乎所有的集合子类型都实现了迭代接口Iterable.
迭代接口提供的方法:
boolean hasNext() 可以形象的认为有指针,指针的最初位置在第一个元素的前面。
E next() 用于返回指针指向的那个元素,然后指针向后移动,为下一次的判断。
E remove() 用于删除指针指向的那个元素。
在使用迭代器时,不可以调用集合自己的remove方法。
public class CollectionDemo02 {public static void main(String[] args) {Collection<Integer> c1 = new ArrayList();c1.add(1);c1.add(2);c1.add(3);c1.add(4);c1.add(5);for(Integer i: c1){System.out.print(i+" ");
}
System.out.println();
//使用迭代器iterator进行遍历Iterator<Integer> it = c1.iterator();
while(it.hasNext()){Integer a = it.next;System.out.println("a:"+a);
}}}
迭代器的源码解析
三个成员变量: * cursor: 记录下一次要返回的元素的下标 * lastRet: 记录上一次刚刚返回的元素的下标 * expectedModCount: 预计的修改次数。 默认为集合的长度 ,与modCount的值息息相关 * 注意:集合在调用add(E e)方法添加元素时,modCount++。 * * hasNext(): return cursor!=size : 当光标的值为集合长度时,没有下一个元素了。 * next(): * 1. 检查 expectedModCount和modCount 是否一样,如果不一致,就抛异常。 * 2. 光标的值先赋值给lastRet。 相当于指针后移。 光标的值+1,为下一次的hasNext()做准备工作 * 新的lastRet的值就是指针指向的元素,也就是刚刚取出来的元素 * remove(): * 1. 检查 expectedModCount和modCount 是否一样,如果不一致,就抛异常。 * 2. 调用ArrayList的 E remove(int index) 做真正的删除元素操作。 * 而E remove(int index)里面调用了System.arraycopy()方法, * 从指定的index+1处,向前移动一位,以此形式做删除工作。 * * index的值是lastRet赋值的。 * * 因为后续的元素向前移动了,因此cursor也要向前移动一次, 即cursor=lastRet. * 如果不向前移动,会漏掉元素。 即 index+1这个位置上的元素,就会被漏掉。 * * 最重要的是: remove(int index)里面进行了modCount++操作。 * 但是 迭代器的remove里,进行重新赋值expectedModCount = modCount;