目录
一、集合的概念
集合有时也称为容器,用于存储、提取、管理数据。面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,存储对象,集合是存储对象最常用的一种方式。集合的出现就是为了持有对象。集合中可以存储任意类型的对象, 而且长度可变。在程序中有可能无法预先知道需要多少个对象, 那么用数组来装对象的话, 长度不好定义, 而集合解决了这样的问题。
二、集合和数组的区别
数组和集合类都是容器。
数组长度是固定的,集合长度是可变的。
数组中可以存储基本数据类型,集合只能存储对象。数组中存储数据类型是单一的,集合中可以存储任意类型的对象。
集合类的特点,用于存储对象,长度是可变的,可以存储不同类型的对象。
三、集合家族
四、Collection接口
Collection中描述的是集合共有的功能。
学习Collection中的共性方法,多个容器在不断向上抽取就出现了该体系。发现Collection接口中具有所有容器都具备的共性方法。并创建其子类对象对集合进行基本应用。当要使用集合对象中特有的方
法,在查看子类具体内容。
java.util.Collection
注意在现阶段遇到的 E T 之类的类型,需要暂时理解为object 因为涉及到了泛型。
Collection接口所定义的方法:
int size(); 返回此集合中的元素数。
boolean isEmpty(); 如果此集合不包含元素,则返回 true 。
void clear(); 从此集合中删除所有元素(可选操作)。
boolean contains(Object element); 如果此集合包含指定的元素,则返回 true 。
boolean add(Object element); 确保此集合包含指定的元素(可选操作)。
boolean remove(Object element); 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
Iterator iterator(); 返回此集合中的元素的迭代器。
boolean containsAll(Collelction c); 如果此集合包含指定 集合中的所有元素,则返回true。
boolean addAll(Collelction c); 将指定集合中的所有元素添加到此集合(可选操作)。
boolean removeAll(Collelction c); 删除指定集合中包含的所有此集合的元素(可选操作)。
boolean retionAll(Collection c); 仅保留此集合中包含在指定集合中的元素(可选操作)。
Object[] toArray(); 返回一个包含此集合中所有元素的数组。
1、增加
public static void main(String[] args) {
Collection list = new ArrayList();
// 增加:add() 将指定对象存储到容器中
list.add("计算机网络");
list.add("现代操作系统");
list.add("java编程思想");
System.out.println(list);
// [计算机网络, 现代操作系统, java编程思想]
// 增加2 将list容器元素添加到list2容器中
Collection list2 = new ArrayList();
list2.add("java核心技术");
list2.addAll(list);
list2.add("java语言程序设计");
System.out.println(list2);
// [java核心技术, 计算机网络, 现代操作系统, java编程思想, java语言程序设计]
}
2、删除
// 删除1 remove
boolean remove = list2.remove("java核心技术");
System.out.println(remove); // true
System.out.println(list2); //
//删除2 removeAll() 将list中的元素删除
boolean removeAll = list2.removeAll(list);
System.out.println(removeAll);//true
System.out.println(list2);//[java语言程序设计]
3、修改
public static void main(String[] args) {
Collection list = new ArrayList();
// 增加:add() 将指定对象存储到容器中
list.add("计算机网络");
list.add("现代操作系统");
list.add("java编程思想");
list.add("java核心技术");
list.add("java语言程序设计");
System.out.println(list);
// 修改 clear() 清空集合中的所有元素
list.clear();
System.out.println(list); //[]
}
4、判断
public static void main(String[] args) {
Collection list = new ArrayList();
// 增加:add() 将指定对象存储到容器中
list.add("计算机网络");
list.add("现代操作系统");
list.add("java编程思想");
list.add("java核心技术");
list.add("java语言程序设计");
System.out.println(list);
boolean empty = list.isEmpty();
System.out.println(empty);// false
boolean contains = list.contains("java编程思想");
System.out.println(contains);// true
Collection list2 = new ArrayList();
list2.add("水许传");
boolean containsAll = list.containsAll(list2);
System.out.println(containsAll);// false
}
5、获取
public static void main(String[] args) {
Collection list = new ArrayList();
// 增加:add() 将指定对象存储到容器中
list.add("计算机网络");
list.add("现代操作系统");
list.add("java编程思想");
list.add("java核心技术");
list.add("java语言程序设计");
System.out.println(list);
// 获取 集合容器的大小
int size = list.size();
System.out.println(size);
}
6、自定义类的对象在集合中的操作
定义一个Person类,完成在Collection中的增删改查操作。
class Person{
private int id;
private String name;
private int age;
public Person(){
}
public Person(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class TestCollection2 {
public static void main(String[] args) {
Collection c = new ArrayList();
Person p1 = new Person(1,"小毛",20);
Person p2 = new Person(2,"小邓",21);
Person p3 = new Person(3,"小江",22);
c.add(p1);
c.add(p2);
c.add(p3);
System.out.println(c);
//c.remove(p1);
//Person p4 = new Person(1,"小毛",20);
Person p4 = p1;
c.remove(p4);
System.out.println(c);
/*
System.out.println(c.size());
c.clear();
System.out.println(c.size());
*/
}
}
7、Collection接口的子接口
Collection接口有两个子接口:
List(链表|线性表)
Set(集合)
五、Set接口
该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素。用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。
该集合中没有特有的方法,直接继承自Collection。
Set集合的特点:无序、数据不重复。
主要包含的实现类有:HashSet、TreeSet、LinkedHashSet ...
1、HashSet
(1)HashSet结构和原理
用Hash技术实现的Set结构。
由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。
HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。
当你试图把对象加入HashSet时,HashSet会使用对象的hashCode来判断对象加入的位置。同时也会与其他已经加入的对象的hashCode进行比较,如果没有相等的hashCode,HashSet就会假设对象没有
重复出现。
简单一句话,如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。
因此我们自定义类的时候需要重写hashCode,来确保对象具有相同的hashCode值。如果元素(对象)的hashCode值相同,是不是就无法存入HashSet中了? 当然不是,会继续使用equals 进行比较.如果 equals
为true 那么HashSet认为新加入的对象重复了,所以加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入。
总结:
元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。
哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。
散列技术的原理:
把对象的主键直接用一个固定的公式计算,得出存储位置的方法。
优点是:可以快速命中搜索的目标。
(2)添加数据到HashSet
1 基本数据类型存入HashSet中
HashSet set = new HashSet();
set.add(100);
set.add(200);
set.add(300);
set.add(400);
set.add(500);
set.add(400); // 不会存入重复数据
2 字符串类型数据存入HashSet中
HashSet set = new HashSet();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ddd");
set.add("aaa");// 不会存入重复数据
3 自定义类型存入HashSet中
class Student{
private String name;
private int age;
public Student(){
}
public Student(String name, int age) {
super();
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;
}
}
public class TestHashSet {
public static void main(String[] args) {
HashSet hs = new HashSet();
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",21);
Student s3 = new Student("王五",23);
Student s4 = new Student("张三",20);
Student s5 = s1;
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5); //s5和s1 指向同一个对象,所以hashCode相同,不会被存入
System.out.println(hs.size());
System.out.println(hs);
}
}
修改需求。只要Student的name和age值相同,就认为是重复数据,中,如何处理? 重写Student类的hashCode和equals方法不能加入到HashSet
class Student{
private String name;
private int age;
public Student(){
}
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;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
/* public boolean equals(Object obj){
Student s = (Student)obj;
if(this.name.equals(s.getName()) && this.age==s.getAge()){
return true;
}else{
return false;
}
}
public int hashCode(){
return this.name.hashCode()+age;
}
*/
}
public class TestHashSet {
public static void main(String[] args) {
HashSet hs = new HashSet();
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",21);
Student s3 = new Student("王五",23);
Student s4 = new Student("张三",20);
System.out.println(s1.hashCode());
System.out.println(s4.hashCode());
System.out.println(s1.equals(s4));
//Student s5 = s1;
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
//hs.add(s5); //s5和s1 指向同一个对象,所以hashCode相同,不会被存入
System.out.println(hs.size());
System.out.println(hs);
}
}
2、泛型(入门)
JDK1.4之前类型不明确,装入集合的类型都被当作Object对待,从而失去自己的类型。从集合中取出时往往需要类型转换,效率低下,易出错。
解决办法: JDK1.5开始,增加了泛型的功能。
定义集合时,同时定义集合中元素的类型
好处
增强程序的可读性和稳定性
Set<String> set = new HashSet<String>();
这个集合中就只能添加String类型的数据。
泛型:可以简单理解为限制了集合中存入的数据的类型。
public class Demo06_泛型入门 {
public static void main(String[] args) {
/*
Set s = new HashSet();
s.add("aaa");
s.add("bbb");
s.add(111);
s.add(222);
s.add(new Date());
s.add(new User(1,"aaa",20));
System.out.println(s.size());
for(Object obj:s){
System.out.println(obj);
}
*/
Set<String> s = new HashSet<>();
s.add("aaa");
s.add("bbb");
s.add("ccc");
//s.add(111);
Set<Integer> s2 = new HashSet<>();
s2.add(1);
s2.add(2);
//s2.add("aaa");
}
}
3、迭代器和增强型for循环
(1)迭代器
为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator)。
对 Collection 进行迭代的类,称其为迭代器。还是面向对象的思想,专业对象做专业的事情,迭代器就是专门取出集合元素的对象。但是该对象比较特殊,不能直接创建对象(通过new),该对象是以内部类的形式存在于每个集合类的内部。
如何获取迭代器?Collection接口中定义了获取集合类迭代器的方法(iterator()),所以所有的Collection体系集合都可以获取自身的迭代器。
正是由于每一个容器都有取出元素的功能。这些功能定义都一样,只不过实现的具体方式不同(因为每一个容器的数据结构不一样)所以对共性的取出功能进行了抽取,从而出现了Iterator接口。而每一个容器都在其内部对该接口进行了内部类的实现。也就是将取出方式的细节进行封装。
Iterable接口:
Jdk1.5之后添加的新接口, Collection的父接口. 实现了Iterable的类就是可迭代的.并且支持增强for循环。该接口只有一个方法即获取迭代器的方法iterator()可以获取每个容器自身的迭代器Iterator。(Collection)集合容器都需要获取迭代器(Iterator)于是在5.0后又进行了抽取将获取容器迭代器的iterator()方法放入到了Iterable接口中。Collection接口进程了Iterable,所以Collection体系都具备获取自身迭代器的方法,只不过每个子类集合都进行了重写(因为数据结构不同)。
Iterator接口:
Iterator iterator() 返回该集合的迭代器对象
该类主要用于遍历集合对象,该类描述了遍历集合的常见方法
1:java.lang. Itreable
---| Itreable 接口 实现该接口可以使用增强for循环
---| Collection 描述所有集合共性的接口
---| List接口 可以有重复元素的集合
---| Set接口 不可以有重复元素的集合
public interface Iterable<T>
Itreable 该接口仅有一个方法,用于返回集合迭代器对象。
1: Iterator<T> iterator() 返回集合的迭代器对象
Iterator接口定义的方法
Itreator 该接口是集合的迭代器接口类,定义了常见的迭代方法
1:boolean hasNext()
判断集合中是否有元素,如果有元素可以迭代,就返回true。
2: E next()
返回迭代的下一个元素,注意: 如果没有下一个元素时,调用next元素会抛出NoSuchElementException
3: void remove()
从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。
思考:为什么next方法的返回类型是Object的呢? 为了可以接收任意类型的对象,那么返回的时候,不知道是什么类型的就定义为object。
使用Iterator遍历HashSet集合
Set<String> set = new HashSet<String>();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ddd");
Iterator<String> it = set.iterator();
/*
it.hasNext(); // 判断是否有下一个元素
it.next(); // 取到元素
*/
while(it.hasNext()){
String str = it.next();
System.out.println(str);
}
(2)增强型for循环
只要实现了Iterable接口的集合就可以使用增强型for循环进行遍历。
Set<String> set = new HashSet<String>();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ddd");
for(String str:set){
System.out.println(str);
}
4、HashSet案例
String[] names = {"A","B","C","D","E","F","G"};
String[] scores = {"A,数学,89", "A,语文,86","B,数学,88","B,英语,98","C,英语,67","G,数学,60"};
求names中,谁全部缺考?
提示:使用removeAll方法。
String[] names = {"A","B","C","D","E","F","G"};
String[] scores = {"A,数学,89", "A,语文,86","B,数学,88","B,英语,98","C,英语,67","G,数学,60"};
Set<String> namesSet = new HashSet<>();
for(String name:names){
namesSet.add(name);
}
Set<String> scoresSet = new HashSet<>();
for(String str:scores){
scoresSet.add(str.split(",")[0]);
}
namesSet.removeAll(scoresSet);
Iterator<String> it = namesSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
5、TreeSet类
TreeSet是一个可排序集合,基于红黑树(自平衡二叉树),默认按元素的自然顺序升序排列。
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>(); //会对存入的数据自动排序(升序)
set.add(2);
set.add(5);
set.add(3);
set.add(1);
set.add(4);
set.add(5);
System.out.println("集合中元素个数:"+set.size());
for(int x:set){
System.out.println(x);
}
Set<String> s = new TreeSet<>();
s.add("bbb");
s.add("aaa");
s.add("ccc");
s.add("abc");
s.add("cba");
for(String str:s){
System.out.println(str);
}
Set<Student> stuSet = new TreeSet<>();
Student s1 = new Student(4,"aaa",20);
Student s2 = new Student(2,"bbb",30);
Student s3 = new Student(3,"ccc",40);
Student s4 = new Student(4,"cba",50);
stuSet.add(s1);
stuSet.add(s2);
stuSet.add(s3);
stuSet.add(s4);
for(Student stu:stuSet){
System.out.println(stu);
}
Set<Teacher> teacherSet = new TreeSet<>(new TeacherCaiPan());
Teacher t1 = new Teacher(1,"aaa",20);
Teacher t2 = new Teacher(2,"bbb",30);
Teacher t3 = new Teacher(3,"ccc",40);
Teacher t4 = new Teacher(4,"cba",20);
teacherSet.add(t1);
teacherSet.add(t2);
teacherSet.add(t3);
teacherSet.add(t4);
for(Teacher t:teacherSet){
System.out.println(t);
}
}
}
以上案例可以看出,当存入的是基本数据类型和字符串时,TreeSet有自动升序排列的能力。而当存入的是自定义引用类型,遍历时会抛出异常。因为TreeSet并不知道如何排序。
6、比较器
(1)Comparable接口
TreeSet集合排序的两种方式:
第一种方式让元素自身具备比较性。也就是元素需要实现Comparable接口,重写compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。
compareTo 方法:this和参数的比较。
-
返回整数 this比参数大 (this排在参数后面)
-
返回负数 this比参数小 (this排在参数前面)
-
返回零 this和参数相等(认为是重复数据)
class Student implements Comparable<Student>{
private int id;
private String name;
private int age;
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(){}
public Student(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student stu) {
// this 和 参数 stu 比大小
// 返回整数 this > stu (也就是 this排在后面)
// 返回负数 this < stu
// 返回0 this 等于 stu
/*if(this.id>stu.getId()){
return 1;
}
else if(this.id<stu.getId()){
return -1;
}
else{
return 0;
}*/
//return this.id-stu.getId();
//return stu.getId()-this.id;
//return this.name.compareTo(stu.getName());
int x = this.id-stu.getId();
if(x==0){
return this.name.compareTo(stu.getName());
}else{
return x;
}
}
}
(2)Comparator接口
当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。那么这时只能让容器自身具备。
定义一个类实现Comparator 接口,重写compare方法。并将该接口的子类对象作为参数传递给TreeSet集合的构造方法。
当Comparable比较方式,及Comparator比较方式同时存在,以Comparator比较方式为主。
compare方法比较规则:
-
返回整数 参数1大于参数2 (参数1排在参数2的后面)
-
返回负数 参数1小于参数2 (参数1排在参数2的前面)
-
返回零 参数1等于参数2 (认为是重复数据)
class TeacherCaiPan implements Comparator<Teacher>{
public int compare(Teacher t1, Teacher t2) {
// t1>t2 返回整数
// t1<t2 返回负数
// t1==t2 返回0
//return t1.getId()-t2.getId();
return t1.getName().compareTo(t2.getName());
}
}
class Teacher{
private int id;
private String name;
private int age;
public Teacher(){
}
public Teacher(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
Set<Teacher> teacherSet = new TreeSet<>(new TeacherCaiPan());
Teacher t1 = new Teacher(1,"aaa",20);
Teacher t2 = new Teacher(2,"bbb",30);
Teacher t3 = new Teacher(3,"ccc",40);
Teacher t4 = new Teacher(4,"cba",20);
teacherSet.add(t1);
teacherSet.add(t2);
teacherSet.add(t3);
teacherSet.add(t4);
(3)TreeSet去重复
情况1:
当存入的数据是根据类型本身实现 Comparable接口方式比较大小,判断重复就是根据重写的compareTo方法。如果返回的是0 则认为是重复数据
public class Demo12_TreeSet去重复 {
public static void main(String[] args) {
Set<Cat> set = new TreeSet<>();
Cat c1 = new Cat(1,"aaa");
Cat c2 = new Cat(2,"bbb");
Cat c3 = new Cat(3,"ccc");
Cat c4 = new Cat(1,"ddd");
set.add(c1);
System.out.println(set.add(c2));
System.out.println(set.add(c3));
System.out.println(set.add(c4));
for(Cat c:set){
System.out.println(c);
}
}
}
class Cat implements Comparable<Cat>{
private int id;
private String name;
public Cat(){}
public Cat(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;
}
public int compareTo(Cat o) {
return this.id-o.getId();
}
@Override
public String toString() {
return "Cat [id=" + id + ", name=" + name + "]";
}
}
情况2: 当存入对象本身没有比较大小能力,而是根据比较器比较大小时,根据比较器中的compare方法的返回值来决定是否重复。返回0则认为是重复数据
public class Demo12_TreeSet去重复2 {
public static void main(String[] args) {
Set<Dog> set = new TreeSet<>(new DogComparator());
Dog d1 = new Dog(1,"aaa");
Dog d2 = new Dog(2,"bbb");
Dog d3 = new Dog(3,"ccc");
Dog d4 = new Dog(4,"aaa");
set.add(d1);
System.out.println(set.add(d2));
System.out.println(set.add(d3));
System.out.println(set.add(d4));
for(Dog c:set){
System.out.println(c);
}
}
}
class DogComparator implements Comparator<Dog>{
public int compare(Dog o1, Dog o2) {
//return 0;
return o1.getName().compareTo(o2.getName());
}
}
class Dog{
private int id;
private String name;
public Dog(){}
public Dog(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;
}
public String toString() {
return "Cat [id=" + id + ", name=" + name + "]";
}
}
7、TreeSet案例
将字符串中的数值进行排序。
例如String str="8 10 15 5 2 7";
使用 TreeSet完成。
思路:
1、将字符串切割。
2、可以将这些对象存入TreeSet集合。
因为TreeSet自身具备排序功能。
public class Demo11_TreeSet练习 {
public static void main(String[] args) {
String str="8 10 15 5 2 7";
Set<Integer> set = new TreeSet<>();
String[] ss = str.split(" +");
for(String s:ss){
set.add(Integer.parseInt(s));
}
System.out.println(set);
}
}
六、List接口
List接口是Collection的子接口,实现List接口的容器类中的元素是有顺序的,而且可以重复。
List容器中的元素都对应一个整数型的序号记录其在容器中的位置,可以根据此序号存取元素。
主要实现类有 ArrayList 和 LinkedList。
1、List中的方法
相对Collection接口扩展的方法有:
Object get(int index);
Object set(int index,Object element);
void add(int index,Object element);
Object remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
public class Demo01_ArrayList {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
//添加数据
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("aaa");
//元素个数
System.out.println("list中的元素个数为:"+list.size());
System.out.println(list); // list是有序的(和添加时的顺序相同)
for(String s:list){
System.out.println(s);
}
//根据索引获取元素
System.out.println("第2个元素为:"+list.get(1));
System.out.println("第6个元素为:"+list.get(5));
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
System.out.println(list.indexOf("aaa"));
System.out.println(list.indexOf("bbb"));
System.out.println(list.lastIndexOf("bbb"));
System.out.println(list.lastIndexOf("aaa"));
list.add(1,"xxx"); //在指定位置添加一个元素,后面的元素依次后移
System.out.println(list);
list.set(1,"yyy"); // 在指定位置添加一个元素,替换原有的元素
System.out.println(list);
list.remove("aaa"); //只会移除第一个aaa
System.out.println(list);
list.remove(0); //移除指定位置的元素
System.out.println(list);
}
}
删除list中全部元素
for(String str:list){
list.remove(str); // 增强型for循环不允许调用remove方法删除元素
}
System.out.println(list);
int size = list.size();
for(int i=0;i<size;i++){
list.remove(list.get(0));
}
System.out.println(list);
for(int i=list.size()-1;i>=0;i--){
list.remove(list.get(i));
}
System.out.println(list);
2、ArrayList
--| Iterable
----| Collection
----| List
-----| ArrayList 底层采用数组实现,默认10。每次增长60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。
-----| LinkedList
ArrayList:实现原理:数组实现, 查找快, 增删慢
数组为什么是查询快?因为数组的内存空间地址是连续的.
ArrayList底层维护了一个Object[] 用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。
当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。
由于ArrayList是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。数组是可以直接按索引查找, 所以查找时较快
可以考虑,假设向数组的0角标未知添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要要将老数组的内容拷贝到新数组中.所以数组的增删的效率是很低的
3、LinkedList
LinkedList:链表实现, 增删快, 查找慢
由于LinkedList:在内存中的地址不连续,需要让上一个元素记住下一个元素.所以每个元素中保存的有下一个元素的位置.虽然也有角标,但是查找的时候,需要从头往下找,显然是没有数组查找快的.但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了.所以插入很快.
由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高。
但查询时需要一个一个的遍历, 所以效率较低。
特有方法:
addFirst(E e)
addLast(E e)
getFirst()
getLast()
removeFirst()
removeLast()
如果集合中没有元素,获取或者删除元素抛:NoSuchElementException
4、面试
ArrayList与LinkedList的区别?
他们都是线性表,但是ArrayList基于数组(顺序存储),LinkedList基于链表(链式存储)
由于实现的不同,ArrayList在随机访问元素时性能较高,插入和删除元素时效率较低,LinkedList则反之。
5、Vector(不常用)
Vector: 描述的是一个线程安全的ArrayList。
ArrayList: 单线程效率高
Vector : 多线程安全的,所以效率低
特有的方法:
void addElement(E obj) 在集合末尾添加元素
E elementAt( int index) 返回指定角标的元素
Enumeration elements() 返回集合中的所有元素,封装到Enumeration对象中
Enumeration 接口:
boolean hasMoreElements()
测试此枚举是否包含更多的元素。
E nextElement()
如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素
public static void main(String[] args) {
Vector v = new Vector();
v.addElement("aaa");
v.addElement("bbb");
v.addElement("ccc");
System.out.println( v );
System.out.println( v.elementAt(2) ); // ccc
// 遍历Vector遍历
Enumeration ens = v.elements();
while ( ens.hasMoreElements() ){
System.out.println( ens.nextElement() );
}
}
七、操作集合的工具类
Collections常用功能
List排序:sort方法
Collection元素搜索:binarySearch方法
改变Collection中的元素:addAll方法
- int binarySearch(List<E> list, E e ):在一个有升序顺序的List集合中,通过二分查找寻找元素e的索引
- fill(List<E> list, E e):将list集合中的所有元素都填充为元素e
- int frequency(Collection<E> c, E e):返回在集合c中的元素e的个数
- max、min:获取集合的最大值或者最小值
- replaceAll(List<E> list, E oldVal, E newVal):将集合list中的所有指定老元素oldVal都替换成新元素newVal
- reverse(List<E> list):将参数集合list进行反转
- shuffle(List<E> list):将list集合中的元素进行随机置换
- swap(List<E> list, int a, int b):将a索引和b索引的元素进行交换
- synchronizedXxx方法系列:将一个线程不安全的集合传入方法,返回一个线程安全的集合
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(1);
list.add(3);
list.add(5);
list.add(2);
/*
//Collections.sort(list);
Collections.sort(list,new Comparator<Integer>(){
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
System.out.println(list);
*/
Collections.shuffle(list); // 乱序 洗牌
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
System.out.println(Collections.max(list));
Set<Integer> set = new HashSet<>();
set.add(2);
set.add(21);
set.add(3);
System.out.println(Collections.max(set));
}
八、栈(Stack)
Stack类是Vector类的子类。特点是先进后出。
常用方法:
boolean | empty() |
E | peek() |
E | pop() |
E | push(E item) |
int | search(Object o) |
public class Demo03_Stack {
public static void main(String[] args) {
Stack<String> st = new Stack<>();
st.push("aaa");
st.push("bbb");
st.push("ccc");
st.push("ddd");
System.out.println(st.peek()); // 获取栈顶元素,但不移除
System.out.println(st.peek());
System.out.println(st.pop()); // 弹出栈顶元素 --- 获得栈顶元素,并将其从栈中移除
System.out.println(st);
System.out.println(st.isEmpty());
System.out.println(st.search("aaa")); // 自顶向下找,从1开始数
}
}
上一篇:(44)Java基础 --异常
下一篇:(46)Java基础 --泛型