Java 笔记 21:modcount, 泛型
程序员文章站
2022-05-04 08:43:24
@TOCmodcountmodCount:记录当前集合被修改的次数(1)添加(2)删除这两个操作都会影响元素的个数。当我们使用迭代器或foreach遍历时,如果你在foreach遍历时,自动调用迭代器的迭代方法,此时在遍历过程中调用了集合的add,remove方法时,modCount就会改变,而迭代器记录的modCount是开始迭代之前的,如果两个不一致,就会报异常,说明有两个线路(线程)同时操作集合。这种操作有风险,为了保证结果的正确性,避免这样的情况发生,一旦发现modCount...
modcount
modCount:记录当前集合被修改的次数
- (1)添加
- (2)删除
- 这两个操作都会影响元素的个数。
- 当我们使用迭代器或foreach遍历时,如果你在foreach遍历时,自动调用迭代器的迭代方法,
- 此时在遍历过程中调用了集合的add,remove方法时,modCount就会改变,
- 而迭代器记录的modCount是开始迭代之前的,如果两个不一致,就会报异常,
- 说明有两个线路(线程)同时操作集合。这种操作有风险,为了保证结果的正确性,
- 避免这样的情况发生,一旦发现modCount与expectedModCount不一致,立即保错。
- 此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:
- 在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,
- 否则在任何时间以任何方式对列表进行修改,
- 迭代器都会抛出 ConcurrentModificationException。
- 因此,面对并发的修改,迭代器很快就会完全失败,
- 而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
泛型
泛型:JDK1.5之后引入的
*
- 泛型:泛化的类型,参数化类型
- 生活中:
- 生产瓶子的厂商,只负责生产瓶子,不管你这个瓶子将来用来装什么。
- 在超市中,大家看到的瓶子上都有标签(商标),表明这个瓶子中是什么。
- 生产饮料、酒、调料的厂商买回这个瓶子后,在装东西时,就给这个瓶子加上商标(标签)。
- 贴上标签后,下次看到时,就知道里面是什么,我可以放心的使用。
- Java中:
- 例如:在设计集合这个容器的数据结构时,不知道我们程序员会用它来装什么对象。
- 可能用它装字符串对象,可能用它装Apple对象…
- 在设计时不确定元素的类型,但是在使用时,程序员是知道类型的。
- 现在需要一个方式,渠道,让使用者在使用这个集合等时,告知这个集合我里面装的是什么对象。这就需要泛型。
- 现在在设计这个集合时,元素的类型不确定,所以我把这个类型用形参表示,让使用者用实参给我确定这个类型。
- 因为它代表的是数据的类型,所以把这种形参称为类型形参和类型实参。
- 泛型:包括类型形参和类型实参
- 泛型:<类型>
- 例如:,…
泛型的好处:
- (1)安全
- (2)避免类型转换
泛型的使用形式有2种:
- 1、泛型类\泛型接口
- 2、泛型方法
- 一、泛型类/接口
- 1、语法格式:
- 【修饰符】 class 类名<泛型形参列表>{
- }
- 【修饰符】 interface 接口名<泛型形参列表>{
- }
- 例如:
- public interface Collection 就是泛型形参列表
- public class ArrayList 就是泛型形参列表
- public class HashMap<K,V> <K,V>就是泛型形参列表
- 我们看到在声明类或接口时,,<K,V>,,…都是泛型的形参列表
- 这些E,K,V,T等代表的是某种元素的类型
- ArrayList list = new ArrayList();
- 此时:泛型的实参列表
- //存储本组学员的姓名(key)和它的年龄(value)
- HashMap<String,Integer> map = new HashMap<String,Integer>();
- 此时:<String,Integer>是泛型的实参列表
- 2、要求
- 泛型实参必须是一个引用数据类型,不能是基本数据类型
- 3、如何为泛型类、泛型接口指定泛型实参
- (1)创建泛型类的对象时
- Student chinese = new Student(“张三”,“优秀”);
- (2)继承泛型类、泛型接口时可以指定泛型实参
- class ChineseStudent extends Student
- (3)实现泛型接口时,可以指定泛型实参
- class Employee implements Comparable
public class TestGenericClass {
@Test
public void test1(){
// ArrayList<int> list = new ArrayList<int>();//错误
ArrayList<Integer> list = new ArrayList<Integer>();//对
}
@Test
public void test2(){
//语文老师
Student<String> chinese = new Student<String>("张三","优秀");
//数学老师
Student<Double> math = new Student<Double>("张三",89.5);
//英语老师
Student<Character> english = new Student<Character>("张三",'A');
}
@Test
public void test3(){
//语文老师
ChineseStudent c = new ChineseStudent("张三","优秀");
}
}
/*
* 自定义一个泛型类:
* 定义一个“特殊”的学生类,学生类包含两个属性:姓名,成绩
* 此时成绩的情况很复杂:
* 语文老师在表示学生时:成绩登记为:优秀、良好、及格、不及格
* 数学老师在表示学生时:成绩登记为:89.5 ....
* 英语老师在表示学生时:成绩登记为:A,B,C,D...
*
* <T>:泛型形参
* T在这个Student当做就是score的类型,凡是需要表示score的类型的地方都用T
*/
class Student<T>{
private String name;
private T score;
public Student(String name, T score) {
super();
this.name = name;
this.score = score;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getScore() {
return score;
}
public void setScore(T score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + "]";
}
}
//语文老师
class ChineseStudent extends Student<String>{
public ChineseStudent() {
super();
}
public ChineseStudent(String name, String score) {
super(name, score);
}
}
//接口:java.lang.Comparable<T>
class Employee implements Comparable<Employee>{
private int id;
private String name;
public Employee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
@Override
public int compareTo(Employee o) {
return this.id - o.id;
}
}
4、泛型类或泛型接口上的<泛型形参>这个类型可以用在哪些地方?
- (1)可以用于属性、方法的数据形参、局部变量等的类型
- (2)不能用于静态成员上
- 5、泛型类或泛型接口的泛型形参,可以设定上限
- <T extends 上限>
- T的类型实参只能上限本身或上限的子类
- <T extends 上限1 & 上限2 & 。。。。>
- 如果多个上限,都要满足
- 6、 泛型的形参一般代表什么的类型?
- ArrayList:这个E代表集合的元素的类型
- Map<K,V>:这个K代表key的类型,V代表的value的类型
- Comparable:这个T代表,要与当前对象比较的另一个对象的类型
- Student:这个T代表成绩的类型
- 7、如果在使用泛型类或泛型接口的时候,没有指定泛型实参,会怎么样?
- 泛型被擦除,泛型被擦除后,泛型形参被解析为什么类型呢?
- 被解析为泛型形参的第一个上限的类型。
- (1)如果没有指定泛型形参的上限,就按照Object处理
- (2)如果指定泛型形参的上限,就按照上限处理,如果有多个上限,多个上限用&连接,按照最左边的第一个上限处理(是左面第一个上限的类型,并满足多个上限)
二、泛型方法
- 1、什么情况需要声明泛型方法?
- (1)如果某个静态方法想要使用泛型,需要单独设计
- 例如:java.util.Arrays数组工具类
- public static List asList(T… a)
-
T...是可变参数
- (2)如果泛型类或泛型接口上的泛型形参不适用于某一个方法(可以是静态的,也可以是非静态),那么这个方法,可以单独设计泛型
- 例如:java.util.Collection
- public abstract T[] toArray(T[] a)
- 2、泛型方法的语法格式
- 【修饰符】 <泛型形参列表> 返回值类型 方法名(【数据形参列表】)
- 3、泛型方法的<泛型形参列表>这个类型就用于当前方法的形参类型、返回值类型、局部变量,和其他方法无关
- 4、泛型方法的类型形参,什么时候指定类型实参
- 当你调用这个方法时,编译器会根据方法的实参的类型,来确定泛型的类型实参的具体类型
- 5、泛型方法的<泛型形参列表>中的类型也可以指定上限
- <T extends 上限>
- T的类型实参只能上限本身或上限的子类
- <T extends 上限1 & 上限2 & 。。。。>
- 如果多个上限,都要满足
public class TestGenericMethod {
public <T extends Number> T test(T t){
//...
return t;
}
@Test
public void test03(){
Integer num = test(1);
Double d = test(1.0);
// test("hello");//错的,因为String不符合Number的上限
}
@Test
public void test02(){
Collection<String> c = new ArrayList<String>();
c.add("张三");
c.add("李四");
String[] arr = new String[2];
String[] array = c.toArray(arr);//根据arr的数组类型,来确定返回值的T[]的类型
Object[] all = new Object[2];
Object[] array2 = c.toArray(all);//根据all的数组类型,来确定返回值的T[]的类型
}
@Test
public void test01(){
List<Integer> list1 = Arrays.asList(1,2,3,4,5);//根据1,2,3,4,5可以确定T是Integer类型
List<String> list2 = Arrays.asList("hello","java");//根据"hello","java"确定T是String类型
}
}
通配符:wildcard
- 通配符:?
- 1、<?>:代表可以是任意类型
- 2、<? extends 上限>:?代表是上限或上限的子类
- 3、<? super 下限>:?代表的是下限或下限的父类
- 看java.util.Collections:集合工具类
- (1)public static boolean disjoint(Collection<?> c1, Collection<?> c2)看c1和c2是否有交集,如果没有交集返回true
本文地址:https://blog.csdn.net/qq_40473204/article/details/107669505
上一篇: 关于稀疏数组的学习和实现
下一篇: java入门~第九天 面向对象的继承