知识模块 a.为什么需要集合? b.集合的通用功能 1.集合添加,获取功能 2.集合的判断功能 3.集合的删除功能 4.集合的迭代 5.泛型 一.集合 a.为什么需要集合? 存储班级中80个同学的成绩 ? 第一种方法:使用变量存储 int student01 = 50; int student02 = 70; int student03 = 80; ...... int student80 = 76; 第二种方法:使用数组存储 int[] scores = new int[80]; scores[0] = 80; scores[1] = 90; ..... scores[79] = 100; 后来又来了20个同学,存储这20个同学的成绩 ? 由于长度为80的数组已经存满,我们无法在存储这20个同学的成绩,想要存储,我们需要在开辟一个长度位100的数组 int[] new Scores = new int [100]; newScores[0]~newScores[79] 存储原来80个人的成绩 newSorces[80]~newScores[99] 存储新来的20个人的成绩 都三种方法: 我们使用别人写好的类来存储元素,我们不需要关心空间不够的情况 我们只需要关心元素的存储,取出,删除...这一系列操作元素的行为 那么这个类或者这个类的体系就是集合 b.集合的通用功能 1.集合添加,获取功能 /* 集合体系通用功能: boolean add(Object e) 确保此 collection 包含指定的元素(可选操作)。 像集合中添加元素 int size() 返回此 collection 中的元素数。 获取数组长度,使用length属性,arr.length 获取字符串的长度,使用String类中的length()方法,"abc".length() 获取StringBuilder长度,使用StringBuilder类中的length()方法,new StringBuilder("abc").length(); 获取集合元素中的元素个数,使用集合的size()方法 void clear() 移除此 collection 中的所有元素(可选操作)。 */
public class CollectionDemo01 {
public static void main(String[] args) {
//method01();
//method02();
Collection c = new ArrayList();
c.add("abc");
c.add("f");
c.add("mhk");
System.out.println(c);//[abc, f, mhk]
c.clear();//清空集合中元素
System.out.println(c);//[]
}
private static void method02() {
Collection c = new ArrayList();
c.add(123);//Object e = 123
//装箱 Object e = new Integer(123)
c.add("abc");
c.add(456);
c.add("def");
System.out.println(c.size());
}
private static void method01() {
Collection c = new ArrayList();//父接口指向实现对象 多态
c.add("abc");//Object e = "abc"; 父类引用指向子类对象 多态
c.add("def");
System.out.println(c);//[abc, def] 集合底层重写了toString()方法
System.out.println(c.toString());
}
}
2.集合的判断功能 boolean contains(Object o) 判断集合中是否包含指定元素,如果包含,返回true 不包含,返回false contains()方法底层判断元素是否包含在集合中,他其实依赖的是存储元素的boolean equals(Object obj)方法 int[] arr{13,15,17,19} Person p1 = new Person("无忌", 19); Person p2 = new Person("敏敏", 18); c.add(p1); //p3和p1比较,其实就是调用equals()方法,相当于p3.equals(p1),Person类中默认的equals()方法,比较的是内存地址值 c.add(p2); //p3和p2比较,其实就是调用equals()方法,相当于p3.equals(p2),Person类中默认的equals()方法,比较的是内存地址值 Person p3 = new Person("无忌", 19); System.out.println(c.contains(p3)); //当所有元素都调用equals()方法和p3比较,都返回flase,说明这个集合中不包含p3 //最终contains方法会false boolean isEmpty() 判断集合是否有元素,如果有元素,返回false 无元素,返回true
public class CollectionDemo02 {
public static void main(String[] args) {
//method01();
//method02();
Person p1 = new Person("无忌", 19);
Person p2 = new Person("敏敏", 18);
Collection c = new ArrayList();
c.add(p1);//Object e = p1 = new Person("无忌",19); 多态
c.add(p2);
System.out.println(c);//[collection01.Person@4eec7777, collection01.Person@3b07d329]
//集合中的元素也会调用toString()方法
Person p3 = new Person("无忌", 19);
System.out.println(c.contains(p3));// //当所有元素都调用equals()方法和p3比较,都返回flase,说明这个集合中不包含p3
//最终contains方法会false
//当我们重写了Person类中equals()方法,比较姓名和年龄,
//此时p3和p1都是一样的,所以认为集合中包含这个人,返回true
Person p4 = new Person("无忌", 21);
System.out.println(c.contains(p4));//false
}
private static void method02() {
Collection c = new ArrayList();
c.add("张三");
c.add("李四");
c.add("王五");
System.out.println(c.contains("李四"));//true
System.out.println(c.contains("赵六"));//false
}
private static void method01() {
Collection c = new ArrayList();
c.add("abc");
c.add("def");
System.out.println(c.isEmpty());//false
c.clear();
System.out.println(c.isEmpty());//true
}
}
3.集合的删除功能 集合中的移除功能: boolean remove(Object o) 从集合中移除指定的元素,如果移除成功,返回true,否则返回false remove()方法依靠集合中的equals()方法比较,如果两个元素调用equals()方法返回true说明存在元素,可以移除,返回true 如果集合中所有元素调用equals()与被移除元素比较,都返回false,集合中不存该元素,移除失败,返回false Person p1 = new Person("乔峰", 30); Person p2 = new Person("阿朱", 20); c.add(p1); c.add(p2); Person p3 = new Person("乔峰", 30); System.out.println(c.remove(p3));//首先跟p1比较,p1.equals(p3),如果调用Object里面的equals()方法,默认比较地址值,返回false int[] arr = {15,19,21} 移除19 移除16 contains()方法与remove()方法底层在判断的时候都是依赖集合中元素的equals()方法
Person类的内容
public class Person {
private String name;
private int age;
public Person(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;
}
//比较两个人的姓名年龄
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person person)) return false;
return age == person.age && name.equals(person.name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class CollectionDemo03 {
public static void main(String[] args) {
//method01();
Collection c = new ArrayList();
Person p1 = new Person("乔峰", 30);
Person p2 = new Person("阿朱", 20);
c.add(p1);
c.add(p2);
Person p3 = new Person("乔峰", 30);
System.out.println(c.remove(p3));
System.out.println(c);
}
private static void method01() {
Collection c = new ArrayList();
c.add("abc");
c.add("def");
System.out.println(c);//[abc, def]
System.out.println(c.remove("def"));//true
System.out.println(c);//[abc]
System.out.println(c.remove("gk"));//false
}
}
4.集合的迭代 a.集合的迭代器相关的方法 集合的通用迭代(遍历)方式: Iterator iterator() 从集合中获取一个迭代器对象,这个迭代器专门用来遍历集合中的元素 Inerayor接口中的放啊: boolean hasNext() 判断集合中是否有遍历的元素,如果有,hasNext()就返回true,如果集合中没有要遍历的元素,就返回false Object next() 取出当前遍历的元素,并返回该元素
public class CollectionDemo01 {
public static void main(String[] args) {
//method01();
//method02();
Collection c = new ArrayList();
c.add("李雷");
c.add("韩梅梅");
c.add("李宁");
for (Iterator iterator = c.iterator(); iterator.hasNext();) {//没有步进表达式
System.out.println(iterator.next());
}
}
private static void method02() {
Collection c = new ArrayList();
c.add("李雷");
c.add("韩梅梅");
c.add("李宁");
Iterator iterator = c.iterator();
/*
while(判断当前遍历元素是否存在){
取出集合中的元素
}
*/
while (iterator.hasNext()) {//如果hasNext()返回true,代表当前待遍历的元素,如果返回false,没有要遍历的元素
System.out.println(iterator.next());
}
}
private static void method01() {
Collection c = new ArrayList();
c.add("李雷");
c.add("韩梅梅");
c.add("李宁");
//1.获取一个迭代器对象
Iterator iterator = c.iterator();//这个方法底层肯定是返回Iterator接口的实现类对象(多态)
//2.调用hasNext()方法和next()方法
System.out.println(iterator.hasNext());//true
//集合中有待遍历的元素,:“李雷”,因此hasNext()返回true
System.out.println(iterator.next());//李雷
//取出当前的遍历元素,“李雷”
System.out.println("------------");
System.out.println(iterator.hasNext());//true
//集合中有待遍历的元素,:“李雷”,因此hasNext()返回true
System.out.println(iterator.next());//韩梅梅
//取出当前的遍历元素,“韩梅梅”
System.out.println("--------------");
System.out.println(iterator.hasNext());//true
System.out.println(iterator.next());//李宁
System.out.println("--------------");
System.out.println(iterator.hasNext());//false
//此时集合中已经没有待遍历元素,所以hasNext()返回false
// System.out.println(iterator.next());// java.util.NoSuchElementException 当前无元素异常
}
}
b.并发修改异常 在使用迭代器遍历集合中容易引发的问题: 需求:定义一个集合,向集合中添加三个字符串:”abc“ ,”def“,”ghk“ 当遍历到”ghk”的时候,删除该元素 java.util.ConcurrentModificationException:并发修改异常 由于我们在使用迭代器的方法遍历的过程中,使用了集合的删除/添加 方法,导致并发修改异常 解决: 在使用迭代器遍历的过程中,如果需要增加/删元素,使用迭代器的方法来完成,就可以避免这个错误 void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
public class CollectionDemo02 {
public static void main(String[] args) {
//method01();
Collection c = new ArrayList();
c.add("abc");
c.add("def");
c.add("ghk");
//1.获取一个迭代器对象
Iterator iterator = c.iterator();
//2.利用迭代器的判断和获取功能
while (iterator.hasNext()) {
Object ele = iterator.next();
if (ele.equals("ghk")) {
//c.remove(ele);
iterator.remove();//删除当前迭代器遍历的元素,不用传参
//[abc, def]
}
}
//3.打印集合
System.out.println(c);
}
//会引发并发修改异常
private static void method01() {
Collection c = new ArrayList();
c.add("abc");
c.add("def");
c.add("ghk");
//1.获取一个迭代器对象
Iterator iterator = c.iterator();
//2.利用迭代器的判断和获取功能
while (iterator.hasNext()) {
Object ele = iterator.next();
if (ele.equals("ghk")) {
c.remove(ele);
}
}
//3.打印集合
System.out.println(c);
}
}
c.增强for JDK1.5新特性: 增强for: 用途:一般用来遍历数组和集合的 要求集合必须继承或实现Iterable接口 格式: for(要遍历的容器中元素的类型 变量名 : 数组/集合){ //取出元素 } 注意事项: 1.使用增强for遍历集合其实底层使用的依然是迭代器 while(iterator.hashNext){ iterator.next(); } 2.使用增强for遍历数组的时候,无法操作数组的索引
public class CollectionDemo03 {
public static void main(String[] args) {
int[] arr = {13, 17, 16, 21};
//使用增强for
//method01(arr);
Collection c = new ArrayList();
c.add(13);
c.add("abc");
c.add("ef");
for (Object obj : c) {//每次将遍历的元素赋值给了obj变量
System.out.println(obj);//第一次循环 取出第一个元素 obj = new Integer(13)
//第二次循环 取出第二个元素 obj = new Integer("abc")
}
System.out.println("--------------");
for (Object o : c) {
System.out.println(o);
}
}
private static void method01(int[] arr) {
for (int ele : arr) {//每次将遍历的元素赋值给了ele变量
System.out.println(ele);//第一次循环 取出第一个元素 ele = 13
//第二次循环 取出第二个元素 ele = 17
}
for (int i : arr) {
}
}
}
5.泛型 a.类上的泛型 类上的泛型当我们创建该类的对象的时候,类上的泛型被确定 类名 引用变量名 = new 类名<指定类型>(); 类上的泛型: 格式: class 类名<E,Q,A.....>{//泛型变量 一旦在类上定义泛型,类中均可以使用定义的泛型变量 } 如果不指定类型,那么这个泛型变量会被替换成Object类型
public class GenericDemo02<Q> { //Q = String
public void method(Q q) {//Q是泛型变量,
// q是变量名
System.out.println(q);
}
public static void main(String[] args) {
GenericDemo02<String> gd1 = new GenericDemo02<String>();//在申明对象的时候通过<>指定类型,这个类型必须是引用类型
//<String>相当于将String这个类型传递给了类上Q
//类上的泛型变量一旦有值,那么类上的所有用到Q的地方都会被替换成String
//method(Q,q) => method(String q)
gd1.method("abc");//abc
GenericDemo02<Integer> gd2 = new GenericDemo02<Integer>();//<Integer>相当于将Integer这个类型传递给了类上Q
//类上的泛型变量一旦有值,那么类上的所有用到Q的地方都会被替换成Integer
//method(Q,q) => method(Interger q)
gd2.method(13);//13
GenericDemo02 gd3 = new GenericDemo02();//如果不指定类型,那么这个泛型变量会被替换成Object类型
gd3.method(1.524);
//GenericDemo02<int> gd2 = new GenericDemo02<int>();
}
}
b.方法上的泛型 当我们调用该方法传参的时候,方法上的泛型被确定 方法上的泛型: 格式: 权限修饰符<T,Q,E....> 返回值类型 方法名(T t,Q q.....){ //<T,Q,E,....>方法上的泛型声明 //可以在方法的形参以及方法内使用 }
/*
方法上的泛型:
格式:
权限修饰符<T,Q,E....> 返回值类型 方法名(T t,Q q.....){ //<T,Q,E,....>方法上的泛型声明
//可以在方法的形参以及方法内使用
}
*/
public class GenericDemo01 {
public <T> void method(T t) {
System.out.println(t);
}
public static void main(String[] args) {
GenericDemo01 gd = new GenericDemo01();
gd.method("abc");//当我们传递字符串的时候,此时形参的T被替换为String类型
//替换为:method(String t)
gd.method(12); //当我们传递一个整数值的时候,此时形参的T被替换为int对应的包装类
//替换为:method(Integer t)
}
}
/*
Collection接口中的toArray方法
<T> T[] toArray(T[] a)
将集合中元素存储到指定的数组中,然后返回装满了嘉禾中的元素的这个数组
*/
public class GenericDemo02 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("abc");
c.add("def");
c.add("ghk");
String[] strs = new String[c.size()];
String[] arr2 = c.toArray(strs);// <T> String[] toArray(String[] a)
//由于我们这里传递的是String[](字符串数组类型),因此方法上的T就被替换成String
//遍历arr数组
for (String s : arr2) {
System.out.println(s);
}
}
}
c.接口上的泛型 第一种方式:实现这个给接口的时候指定类型,从而确定接口上的泛型 第二种方式:通过创建实现类对象来指定类型,确定类上的泛型,从而确定借口上的泛型 接口上的泛型: 格式: interface 接口名<T,E,Q.....>{ //接口上定义的泛型变量,都可以在接口中使用 }
/*
接口上的泛型:
格式:
interface 接口名<T,E,Q.....>{ //接口上定义的泛型变量,都可以在接口中使用
}
*/
public interface Father <T>{
void method(T t);
}
/*
当我们在定义类的时候实现父接口,位父接口传入类型
此时接口上的泛型变量会被替换为该类型,同时在接口中用到该泛型变量的位置都会被替换为该类型
*/
public class Son implements Father<String>{//String会被替换为接口上的T
//而method方法上使用到了T也会被替换为String
@Override
public void method(String s) {
System.out.println(s);
}
}
public class Demo01 {
public static void main(String[] args) {
Son son = new Son();
son.method("abc");
}
}