集合的含义:
集合是一个可变的容器,可以随时向集合中添加元素,也可以随时从集合中删除元素。另外,集合还提供了若干个用来操作集合中数据的方法。集合里的数据,我们称之为元素(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;
}
@Override
public 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;
}
@Override
public 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);
}
@Override
public 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;标签:之一,框架,System,add,集合,new,c1,public From: https://blog.csdn.net/st03zy/article/details/141101893