第十一章 集合
11.1 ArrayList
容器|集合 : 存储多个数据
**数组 :**存储多个数据
一段连续的内存空间
-
数组的特点:
1. 引用数据类型
2. 定长,长度一旦确定不可改变
3. 存储数据的类型相同
4. 有序,有索引
-
集合的特点:
1. 存储任意引用类型数据 2. 集合的长度可变,可以根据需求动态的增删数据,长度随之改变
11.2 手写ArrayList
MyContainer 只能存储字符串数据 String[] elementData
package com;
import java.util.ArrayList;
import java.util.Arrays;
public class Exercise1 {
public static void main(String[] args) {
Mycontainer my=new Mycontainer();
my.add("we");
my.add("ag");
System.out.println(my);
my.remove(0);
System.out.println(my);
System.out.println(my.size());
System.out.println(my.get(12));
}
}
package com;
import java.util.Arrays;
public class Mycontainer {
private String [] elementDate;//内部存储字符串的数组
private int size;//容器中存储数据的个数
// 添加数据
public void add(String value){
// 判断是否为第一次添加
if (elementDate==null || elementDate.length==0 ){
elementDate =new String[1];
elementDate[0]=value;
size++;
return;
}
// 不是第一次添加 原数组中就有数据
// 记录原数组的地址
String [] temp=elementDate;
// 创建新数组,新数组长度加一
elementDate=new String[size+1];
// 将原数组拷贝到新数组中
for (int i=0;i<temp.length;i++){
elementDate[i]=temp[i];
}
// 将新数据放到新数组的最后面
elementDate[size]=value;
size++;
}
// 根据索引获取
public String get(int index){
if (index<0 || index>=size){
throw new IndexOutOfBoundsException(index+"索引越界了!!!");
}
return elementDate[index];
}
// 根据索引进行删除
public void remove(int index){
// 判断索引是否为正常索引
if (index<0 || index>=size){
throw new IndexOutOfBoundsException(index+"索引越界了!!!");
}
// 备份原数组
String [] temp=elementDate;
// 创建新数组
elementDate=new String[size-1];
// 遍历数组进行拷贝
for (int i=0;i<size;i++){
// 分为大于index的部分和小于index的部分
if (i>=index){
if (i==index){ //索引为删除数据的索引 不进行复制直接跳过
continue;
}
elementDate[i-1]=temp[i];
}else{
elementDate[i]=temp[i];
}
// 长度减一
size--;
}
}
// 返回集合中的数据
public int size(){
return this.size;
}
@Override
public String toString() {
return "Mycontainer{" +
"elementDate=" + Arrays.toString(elementDate) +
", size=" + size +
'}';
}
}
11.3 Collection与遍历
容器中的接口层次结构
- **Collection :**单个值的集合
- Set 无序不可重复
- List 有序可重复,有索引
- **Map:**键值对的集合(KEY-VALUE)
Collection 集合层次结构中的根接口。 集合表示一组对象,称为其元素
- 常用方法
- 遍历方式
- foreach
- iterator迭代器
- 遍历方式
package com;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
public class Exercise1 {
public static void main(String[] args) {
Collection col=new ArrayList();
col.add("add");
col.add("adds");
col.add("we");
col.add("ag");
for (Object ob:col){
System.out.println(ob);
}
// 获取迭代器对象 来遍历指定的集合
// Iterator<E> iterator() 返回此集合中元素的迭代器
Iterator it=col.iterator();
// 判断是否有下一个数据
while(it.hasNext()){
System.out.println(it.next());
}
}
}
10.4 泛型
泛型:jdk1.5
参数化类型 : 数据类型作为参数传递,只能配置引用数据类型
注:
- <> 定义泛型
- 泛型的行为发生在编译期间,运行期间泛型配置的所有内容无效,泛型擦除
- 要求先定义泛型,才能使用泛型
- 泛型类 :类型的后面定义泛型,在使用类型的时候可以通过泛型传递具体的类型,类中可以进行使用
- 泛型方法
泛型的优点:
- 代码简单简洁
- 增强程序健壮性,避免类型转换异常的出现
- 增强稳定性与可读性
package com;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
public class Exercise1 {
public static void main(String[] args) {
Collection<String> col=new ArrayList<>();
col.add("add");
col.add("we");
col.add("ag");
for (String s:col){
System.out.println(s);
}
Iterator<String> it=col.iterator();
while(it.hasNext()){
String sc=it.next();
System.out.println(sc);
}
}
}
10.5 List
**List :**有序,可重复
**Set :**无序,不可重复|唯一的
**List :**有序集合(也称为序列 )
该接口的用户可以精确控制列表中每个元素的插入位置
**新增:**一些根据索引操作的方法
遍历方式 :
- for普通for循环
- foreach 增强for循环
- iterator迭代器
10.6 List练习
定义一个List集合,存储漫威中你喜欢的英雄人物,如果存在灭霸(必须存在灭霸),就添加一个惊奇队长
注:
for增强和iterator均不能使用,因为两个方法不能同时遍历又修改
package com;
import java.util.*;
public class Exercise1 {
public static void main(String[] args) {
List<String> li=new ArrayList<>();
li.add("钢铁侠");
li.add("浩克");
li.add("黑寡妇");
li.add("灭霸");
li.add("美国队长");
System.out.println(li);
// contains
if (li.contains("灭霸")){
li.add("惊奇队长");
}
System.out.println(li);
// for普通循环
for (int i=0;i<li.size();i++){
if ("灭霸".equals(li.get(i))){
li.add("惊奇队长");
}
}
System.out.println(li);
// for增强和iterator均不能使用 因为两个方法不能同时遍历又修改
// 出现java.util.ConcurrentModificationException 当不允许这样的修改时,检测到对象的并发修改的方法可能抛出此异常
//List新增方法 listItertor
// 正向遍历
ListIterator<String> sc=li.listIterator();
while(sc.hasNext()){
if ("灭霸".equals(sc.next())){
sc.add("惊奇队长");
}
}
System.out.println(li);
// 反向遍历
ListIterator<String> sd=li.listIterator();
while(sd.hasPrevious()){
if ("灭霸".equals(sc.previous())){
sd.add("惊奇队长");
}
}
System.out.println(li);
}
}
10.7 ArrayList 和 Vector
都是有序的 可以重复的
-
ArrayList : 【实现所有可选列表操作,并允许所有元素,包括null 】
-
**底层结构:**数组 Object[ ] elementData
-
**特点:**根据索引查询遍历效率较高,增删效率低
-
**应用场景:**适合应用在大量做查询,少量做增删的位置
-
扩容问题:
-
**初始容量 :**默认初始容量为10 ,在第一次添加add的时候进行构建
private static final int DEFAULT_CAPACITY = 10;
-
扩容机制 : 每次扩容原容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1)
-
-
新增功能: void forEach(Consumer<? super E> action)
遍历 :
普通for
增强for
iterator迭代器
listIterator迭代器
-
Vector :
-
**底层结构 :**数组
-
**特点 :**与ArrayList相同
-
**区别:**★★★
① Vector是同步的|线程安全
ArrayList不同步|线程不安全,相对效率较高
② Vector每次扩容原容量的2倍
ArrayList每次扩容原容量的1.5倍,相对Vector更有利于节省内存
-
总结:
如果不需要线程安全实现,建议使用ArrayList代替Vector
10.8 LinkedList
**LinkedList:**实现所有可选列表操作,并允许所有元素(包括null )
- **底层结构:**双向链表
- **特点:**查询效率低,增删效率高
- 应用场景:单个数据值的集合中,允许数据有序,且可重复,在大量做增删,少量做查询的时候适合使用链表
- 新增功能: 新增了一些与链表头尾相关的方法
注意:
- 此实现不同步
10.9 编写javabean
定义链表结构,存储javabean类型的数据,测试使用,遍历使用
注意:存储javabean类型数据时候,要求javabean类型重写equals方法,否则使用一些判断比较的方法时候会比
较地址
package Night;
import java.util.LinkedList;
public class Link {
public static void main(String[] args) {
LinkedList<Person> sc=new LinkedList<>();
sc.add(new Person("汪超",22,"男"));
sc.add(new Person("常坤",22,"男"));
sc.add(new Person("赵世祥",24,"男"));
System.out.println(sc);
System.out.println(sc.contains(new Person("汪超",22,"男")));
}
}
package Night;
import java.util.Objects;
public class Person {
private String name;
private int age;
private String gender;
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name) && Objects.equals(gender, person.gender);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}