(45)Java基础 --集合

目录

一、集合的概念

二、集合和数组的区别

三、集合家族

四、Collection接口

1、增加

2、删除

3、修改

4、判断

5、获取

6、自定义类的对象在集合中的操作

7、Collection接口的子接口

五、Set接口

1、HashSet

2、泛型(入门)

3、迭代器和增强型for循环

4、HashSet案例

5、TreeSet类

6、比较器

7、TreeSet案例

六、List接口

1、List中的方法

2、ArrayList

3、LinkedList

4、面试

5、Vector(不常用)

七、操作集合的工具类

八、栈(Stack)


一、集合的概念

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

二、集合和数组的区别

数组和集合类都是容器。

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

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

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

三、集合家族

四、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和参数的比较。

  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;
		}
	}
}

(2)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常用功能

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

上一篇:(44)Java基础 --异常

下一篇:(46)Java基础 --泛型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值