欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > Java基础关键_018_集合(二)

Java基础关键_018_集合(二)

2025/3/11 21:47:31 来源:https://blog.csdn.net/lu_shao_feng/article/details/146028450  浏览:    关键词:Java基础关键_018_集合(二)

目  录

一、泛型 ※

1.说明

2.实例 

3.擦除与补偿

4.泛型的定义

(1)类定义

(2)静态方法定义

(3)接口定义

5.通配符

(1)无限定

(2)上限

(3)下限

二、集合迭代的并发修改异常

1.示例

2.说明

3. fail-fast 机制实现原理

三、List 接口

1.特点

2.常见实现类

3.特有方法

(1)add(int index, E element) 

(2) set(int index, E element) 

(3) get(int index)

(4)remove(int index)

(5)indexOf(Object o)

(6)lastIndexOf(Object o)

(7)subList(int fromIndex, int toIndex)

(8)of(E... elements)

4.特有迭代

(1)listIterator()

(2) listIterator(int index)

四、ListIterator 的方法

1.hasNext()

2.next()

3.remove()

4.add(E e) 

5.hasPrevious()

6.previous()

7.nextIndex()

8.previousIndex()

9.set(E e)

五、比较 

1.回顾数组 Comparable 比较

2.集合 Comparator 比较


一、泛型 ※

1.说明

  1. jdk 5 新增,属于编译阶段功能;
  2. 不使用泛型,会导致代码冗长,从集合中抽取的元素若要访问子类中特有的方法,需要向下转型;
  3. 泛型可以在开发时指定集合中存储的数据类型;
  4. 使用泛型除了可以简化代码,避免类型转换操作之外,还可以在编译时进行类型检查,避免了在运行时出现类型错误的问题;
  5. jdk 7 之后,可以省略表达式后面的泛型类型。

2.实例 

public class GenericTest {public static void main(String[] args) {
//        Collection<Person> c = new ArrayList<Person>();   //  jdk 1.7之前,必须写后面的泛型类型Collection<Person> c = new ArrayList<>();   //  jdk 1.7之后,可以省略后面的泛型类型// Collection<Person> c = new ArrayList<Person>();Person p1 = new Person("张三");Person p2 = new Person("李四");Person p3 = new Person("王五");c.add(p1);c.add(p2);c.add(p3);
//        c.add("赵六");    // 报错,类型不匹配Iterator<Person> iterator = c.iterator();while (iterator.hasNext()) {Person p = iterator.next();p.eat();}/** 张三正在吃饭!* 李四正在吃饭!* 王五正在吃饭!* */}
}

3.擦除与补偿

  1. 泛型的出现提高了编译时的安全性,在编译时对数据类型进行检查,属于编译时期的技术。加载类时,会将泛型擦除,擦除后类型为 Object 类型;

  2. 泛型擦除是为了让 jdk 5 与之前版本的 jdk 能够兼容同一个类加载器;

  3. 因为泛型擦除后,变为 Object 类型。为了保证获得集合元素类型为实际类型,虚拟机会根据元素实际类型自动进行向下转型,这一过程称为泛型补偿。


4.泛型的定义

(1)类定义

public class GenericTest<T> {private T name;public T getName() {return name;}public void setName(T name) {this.name = name;}public GenericTest(T name) {this.name = name;}public static void main(String[] args) {GenericTest<String> gt = new GenericTest<>("张三");System.out.println(gt.getName());
//        GenericTest<String> gt1 = new GenericTest<>(123);   // 报错,类型不匹配,应该是String类型}
}

(2)静态方法定义

public class GenericTest {public static <E> void test(E[] elts) {for (E elt : elts) {System.out.print(elt + "\t");}// 1	2	3	4	5}public static void main(String[] args) {Integer[] ints = {1, 2, 3, 4, 5};GenericTest.test(ints);}
}

(3)接口定义

public interface GenericTest01<T> {String get(T t);
}
public class GenericTest01Impl implements GenericTest01<GenericTest01Impl> {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public GenericTest01Impl(String name) {this.name = name;}@Overridepublic String get(GenericTest01Impl gti) {return getName();}public static void main(String[] args) {GenericTest01Impl gt = new GenericTest01Impl("GenericTest01Impl");System.out.println(gt.get(gt));    // GenericTest01Impl}
}

5.通配符

(1)无限定

        【 <?> 】,其中 【 ? 】 可以是任意引用数据类型。

public class GenericTest {public static void get(ArrayList<?> list) {}public static void main(String[] args) {get(new ArrayList<String>());get(new ArrayList<Integer>());get(new ArrayList<Double>());get(new ArrayList<Object>());}
}

(2)上限

        【 <? extends T> 】,其中 【 ? 】 必须是 T 及其子类。

public class GenericTest {public static void get(ArrayList<? extends Number> list) {}public static void main(String[] args) {
//        get(new ArrayList<String>());   // 报错, 不能将类型为java.util.ArrayList<java.lang.String>的表达式赋给类型为java.util.ArrayList<? extends java.lang.Number>的变量get(new ArrayList<Integer>());get(new ArrayList<Double>());
//        get(new ArrayList<Object>());   // 报错, 不能将类型为java.util.ArrayList<java.lang.Object>的表达式赋给类型为java.util.ArrayList<? extends java.lang.Number>的变量}
}

(3)下限

        【 <? super T> 】,其中 【 ? 】 必须是 T 及其父类。

public class GenericTest {public static void get(ArrayList<? super Number> list) {}public static void main(String[] args) {
//        get(new ArrayList<String>());  // 报错,不允许
//        get(new ArrayList<Double>());   // 报错,不允许get(new ArrayList<Object>());get(new ArrayList<Number>());}
}

二、集合迭代的并发修改异常

1.示例

        在进行集合迭代需要三个步骤,可以参考 Java基础关键_017_集合(一) ,但是在删除集合中的元素时,会抛出并发修改异常,示例如下:

public class GenericTest {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String name = iterator.next();if (name.equals("李四")) {list.remove(name);  // 调用集合remove方法删除元素会报错 java.util.ConcurrentModificationException(并发修改异常)}System.out.println(name);}}
}

        面对以上异常,应该怎么做呢?

        应该将集合的 remove 方法替换为迭代器的 remove 方法,在第二次迭代时就会发现“李四”被删除了,示例如下:

public class GenericTest {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String name = iterator.next();if (name.equals("李四")) {iterator.remove();  // 调用迭代器的remove方法删除当前元素}}Iterator<String> iterator1 = list.iterator();while (iterator1.hasNext()) {String name = iterator1.next();System.out.println(name);}}
}

2.说明

        因为使用迭代器遍历,而使用集合删除操作去删除,底层为防止多线程导致的错误发生,所以抛出并发修改异常,这一机制称为快速失败,即 fail-fast 。


3. fail-fast 机制实现原理

  1. 集合中设置有 modCount 属性,记录修改次数使用集合对象进行 增、删、改 操作时,modCount 会加 1 ;

  2. 获取迭代器对象时,会初始化一个 expectedModCount 属性,并将其值初始化为 modCount ;

  3. 当使用集合的 remove 方法删除元素时,会导致 modCount 加 1 ,而 expectedModCount 不变;

  4. 当 modCount 和 expectedModCount 值不相等时,底层代码会抛出并发修改异常。


三、List 接口

1.特点

        有序、可重复。


2.常见实现类

  1. ArrayList:数组;
  2. Vector、Stack:线程安全的数组;
  3. LinkedList:双向链表。


3.特有方法

        只适合在 List 中使用,都与下标有关。

(1)add(int index, E element) 

        在指定索引处插入元素。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add(1, "赵六");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {System.out.print(iterator.next() + "\t");}// 张三	赵六	李四	王五	}
}

(2) set(int index, E element) 

        修改索引处的元素。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.set(0, "赵六");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {System.out.print(iterator.next() + "\t");}// 赵六	李四	王五}
}

(3) get(int index)

        根据索引获取元素。List 集合独特的遍历方式:通过下标遍历。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");System.out.println(list.get(1));    // 李四}
}

(4)remove(int index)

        删除索引处的元素。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.remove(1);for (String s : list) {System.out.println(s);}// 张三// 王五}
}

(5)indexOf(Object o)

        获取对象 o 在集合中第一次出现的索引。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("张三");list.add("王五");System.out.println(list.indexOf("张三")); // 0}
}

(6)lastIndexOf(Object o)

         获取对象 o 在集合中最后一次出现的索引。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("张三");list.add("王五");System.out.println(list.lastIndexOf("张三")); // 2}
}

(7)subList(int fromIndex, int toIndex)

        截取子 List 集合,生成一个新的集合,范围是 [ fromIndex, toIndex )。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("张三");list.add("王五");System.out.println(list.subList(1, 3)); // [李四, 张三]}
}

(8)of(E... elements)

        静态方法,返回包含任意数量元素的不可修改列表,所获取的集合是只读的。

public class ListTest {public static void main(String[] args) {List<String> strings = List.of("H", "e", "l", "l", "o");strings.set(1, "Q");    // 报错,java.lang.UnsupportedOperationException}
}

4.特有迭代

(1)listIterator()

        获取 List 集合特有的迭代器。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");/** 通用迭代器* */Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String next = iterator.next();System.out.print("Iterator:" + next + "\t");}// Iterator:张三	Iterator:李四	Iterator:王五	Iterator:赵六System.out.println();/** 特有迭代器* */ListIterator<String> listIterator = list.listIterator();while (listIterator.hasNext()) {String next = listIterator.next();System.out.print("ListIterator:" + next + "\t");}// ListIterator:张三	ListIterator:李四	ListIterator:王五	ListIterator:赵六}
}

(2) listIterator(int index)

        从列表指定位置开始,返回列表中元素的列表迭代器。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");/** 特有迭代器* */ListIterator<String> listIterator = list.listIterator(2);while (listIterator.hasNext()) {String next = listIterator.next();System.out.print(next + "\t");}// 王五	赵六}
}

四、ListIterator 的方法

1.hasNext()

        通用方法,判断当前指向位置是否有元素。


2.next()

        通用方法,将当前指向元素返回,并指向下一位。


3.remove()

        通用方法,删除上一次 next() 方法返回的数据。必须先调用 next() 方法或 previous() 方法,否则会报错。


4.add(E e) 

        特有方法,将元素添加到指向位置,然后指向下一位。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");ListIterator<String> listIterator = list.listIterator();while (listIterator.hasNext()) {if ("王五".equals(listIterator.next())){listIterator.add("冯七");}}System.out.println(list);   // [张三, 李四, 王五, 冯七, 赵六]}
}

5.hasPrevious()

        特有方法,判断当前指向位置的上一个位置是否存在元素。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");ListIterator<String> listIterator = list.listIterator();System.out.println(listIterator.hasPrevious()); // falsewhile (listIterator.hasNext()) {listIterator.next();}System.out.println(listIterator.hasPrevious()); // true}
}

6.previous()

        特有方法,获取上一个元素,即指向上一个元素并返回。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");ListIterator<String> listIterator = list.listIterator();while (listIterator.hasNext()) {listIterator.next();}System.out.println(listIterator.previous()); // 赵六System.out.println(listIterator.previous()); // 王五}
}

7.nextIndex()

        特有方法,获取指向位置的下标。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");ListIterator<String> listIterator = list.listIterator();while (listIterator.hasNext()) {listIterator.next();}System.out.println(listIterator.nextIndex()); // 4System.out.println(listIterator.previous()); // 赵六System.out.println(listIterator.nextIndex()); // 3}
}

8.previousIndex()

        特有方法,获取指向位置的上一个位置的下标。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");ListIterator<String> listIterator = list.listIterator();while (listIterator.hasNext()) {listIterator.next();}System.out.println(listIterator.previousIndex()); // 3System.out.println(listIterator.previous()); // 赵六System.out.println(listIterator.previousIndex()); // 2}
}

9.set(E e)

        特有方法,修改上一次 next() 方法返回的数据。必须先调用 next() 方法或 previous() 方法,否则会报错。

public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("赵六");ListIterator<String> listIterator = list.listIterator();while (listIterator.hasNext()) {if ("王五".equals(listIterator.next())) {listIterator.set("冯七");}}System.out.println(list);   // [张三, 李四, 冯七, 赵六]}
}

五、比较 

1.回顾数组 Comparable 比较

public class Student implements Comparable<Student>{private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {
//        return this.age - o.age;    // 比较规则, 年龄升序//        return o.age - this.age;    // 比较规则, 年龄降序//        return this.name.compareTo(o.name);    // 比较规则,姓名升序return o.name.compareTo(this.name);    // 比较规则,姓名降序}
}
public class ComparableTest {public static void main(String[] args) {Student s1 = new Student("张三", 18);Student s2 = new Student("李四", 22);Student s3 = new Student("王五", 7);Student[] students = {s1, s2, s3};Arrays.sort(students);System.out.println(Arrays.toString(students));}
}

2.集合 Comparator 比较

public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class StudentComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.getAge() - o2.getAge();   // 排序规则,年龄升序//        return o2.getAge() - o1.getAge();   // 排序规则,年龄降序//        return o1.getName().compareTo(o2.getName());    // 排序规则,姓名升序//        return o2.getName().compareTo(o1.getName());    // 排序规则,姓名降序}
}
public class ComparatorTest {public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("张三", 18));students.add(new Student("李四", 22));students.add(new Student("王五", 7));students.sort(new StudentComparator());ListIterator<Student> iterator = students.listIterator();while (iterator.hasNext()){System.out.println(iterator.next());}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词