java基础中的-------- 集合 Colleciton 家族

一、集合介绍

1、集合的概念

    集合有时也称为容器,它可以将系列元素组合成一个单元,用于存储、提取、管理数据。面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,存储对象,集合是存储对象最常用的一种方式。集合的出现就是为了持有对象。集合中可以存储任意类型的对象, 而且长度可变。在程序中有可能无法预先知道需要多少个对象, 那么用数组来装对象的话, 长度不好定义, 而集合解决了这样的问题。

2、集合和数组的区别

数组和集合类都是容器。

数组长度是固定的,集合长度是可变的。

数组中可以存储基本数据类型,集合只能存储对象。数组中存储数据类型是单一的,集合中可以存储任意类型的对象。

集合类的特点,用于存储对象,长度是可变的,可以存储不同类型的对象。

 

 

集合家族


二、 Collection接口

Collection中描述的是集合共有的功能。

学习Collection中的共性方法,多个容器在不断向上抽取就出现了该体系。发现Collection接口中具有所有容器都具备的共性方法。查阅API时,就可以直接看该接口中的方法。并创建其子类对象对集合进行基本应用。当要使用集合对象中特有的方法,在查看子类具体内容。

    查看api 文档Collection在java.util 中(注意是大写Collection)

注意在现阶段遇到的 E、T 之类的类型,需要暂时理解为object。因为涉及到了泛型。

 

 Collection接口所定义的方法:

 

 


int size();

boolean isEmpty();

void clear();

boolean contains(Object element);

boolean add(Object element);

boolean remove(Object element);

Iterator iterator();

boolean containsAll(Collelction c);

boolean addAll(Collelction c);

boolean removeAll(Collelction c);

boolean retionAll(Collection c);

Object[] toArray

 

 

测试:可以创建一个具体的实现类,例如:

 

Collection c = new ArrayList();
  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语言程序设计]

}

 

 

  1. 删除:

示例代码


// 删除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语言程序设计]

 

  1. 修改:

示例代码


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); //[]

}

 

  1. 判断:

示例代码

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



}

 

  1. 获取:

示例代码


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接口

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值相同,就认为是重复数据,不加入到HashSet中,如何处理? 重写Student类的hashCode和equals方法

 

示例代码

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并不知道如何排序。

  1. 比较器

(1)Comparable接口

TreeSet集合排序的两种方式:

第一种方式让元素自身具备比较性。也就是元素需要实现Comparable接口,重写compareTo 方法。

这种方式也作为元素的自然排序,也可称为默认排序。

 

compareTo 方法:this和参数的比较。

  1. 返回整数  this比参数大 (this排在参数后面)
  2. 返回负数  this比参数小 (this排在参数前面)
  3. 返回零    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;

}

}

}

  1. Comparator接口

当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。

那么这时只能让容器自身具备。

 

定义一个类实现Comparator 接口,重写compare方法。并将该接口的子类对象作为参数传递给TreeSet集合的构造方法。

Comparable比较方式,及Comparator比较方式同时存在,以Comparator

比较方式为主。

 

compare方法比较规则:

  1. 返回整数   参数1大于参数2 (参数1排在参数2的后面)
  2. 返回负数   参数1小于参数2 (参数1排在参数2的前面)
  3. 返回零     参数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

Collections常用功能

List排序:sort方法

Collection元素搜索:binarySearch方法

改变Collection中的元素:addAll方法

 

  1. int  binarySearch(List<E> list, E e ):在一个有升序顺序的List集合中,通过二分查找寻找元素e的索引
  2. fill(List<E> list, E e):将list集合中的所有元素都填充为元素e
  3. int frequency(Collection<E> c, E e):返回在集合c中的元素e的个数
  4. max、min:获取集合的最大值或者最小值
  5. replaceAll(List<E> list, E oldVal, E newVal):将集合list中的所有指定旧元素oldVal都替换成新元素newVal
  6. reverse(List<E> list):将参数集合list进行反转
  7. shuffle(List<E> list):将list集合中的元素进行随机置换
  8. swap(List<E> list, int a, int b):将a索引和b索引的元素进行交换
  9. 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)
返回对象在堆栈中的位置,以 1 为基数。

 

示例代码

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开始数

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值