容器
容器
/ \
Collection \ (接口)
/ \ Map (接口)
Set List \ (接口)
| / \ \
HashSet LinkedList ArrayList HashMap (实现类)
容器:长度可以根据数据的多少动态的伸缩;可以存储任意类型的数据(引用数据类型)。
1.Collection接口
Collection是一个接口,只规定了一些方法,需要通过其实现类创建对象。
1.1主要方法
- 添加 add
- 删除 remove
- 计数 size
- 包含 contains
- 清空 clear
- 是否空 isEmpty
1.2遍历方式
- 增强for循环;
- 迭代器:
1)获取迭代器对象(获取遍历当前集合的迭代器对象);
2)判断是否存在下一个元素;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class collectiondemo {
public static void main(String[] args) {
Collection col = new ArrayList();//多态,Collection接口指向ArrayList对象
Collection col2 = new ArrayList();
//多态添加元素
col.add("asd0");
col.add(123);
col.add('a');
col.add(true);
col.add(new Student());
System.out.println(col);
col2.add("aaa");
col2.add('a');
col2.add(123);
//添加另一个集合
col.addAll(col2);
System.out.println(col);
//Iterator遍历方式
Iterator it = col.iterator();//获取迭代器对象
while(it.hasNext()){//判断是否有下一个值
System.out.println(it.next());//打印集合中的内容
}
System.out.println("==========");
//增强for循环遍历
for(Object obj:col){
System.out.println(obj);
}
System.out.println("============");
//移出与()中集合交集的元素
col.removeAll(col2);
System.out.println(col);
}
}
class Student{
private int age;
private String name;
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
2.List接口
List接口有序且可重复,且新增了一些根据索引操作的方法。
泛型的作用:提高安全性、规范性,达到类型检查的作用。
2.1遍历方式
- 普通for循环,如果使用增强for循环和迭代器时会导致内部并发指向同一个对象,会产生异常。
- ListIterator—List接口独有迭代器;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Avengers {
public static void main(String[] args) {
List<String > li = new ArrayList<>();
li.add("IronMan");
li.add("灭霸");
li.add("SpiderMan");
li.add("灭霸");
li.add("Holk");
li.add("灭霸");
li.add("约翰逊");
li.add("灭霸");
System.out.println(li);
//正常for循环可以遍历,增强for循环不可以遍历,因为会并发指向同一个对象
for(int i = 0;i<li.size();i++){
System.out.println(li.get(i));
}
System.out.println("==============");
//list专用迭代器,倒序遍历前必须正序遍历,使指针停留在最后一个元素上
//正序遍历
ListIterator<String> lii = li.listIterator();
while(lii.hasNext()){
if("灭霸".equals(lii.next())){
lii.add("惊奇队长");
}
}
//倒序遍历
while(lii.hasPrevious()){
System.out.println(lii.previous());
}
System.out.println(li);
}
}
值得注意的是:在使用倒序遍历时需要先正向遍历将指针移到最后一个元素的位置,否则不会从最后一个元素遍历。
3.ArrayList实现类
优点:根据索引查询,修改效率高;
缺点:做增加删除时效率低;
应用场景:大量做查询少量做增删的时候适合用ArrayList;
扩容机制:int newCapcity = old Capcity + (oldCapcity>>2) 每次扩容原容量1.5倍;
同步:线程不安全的|不同步的
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;
public class Practice {
public static void main(String[] args) {
//创建Employee对象
Employee e1 = new Employee("张三",10000);
Employee e2 = new Employee("李四",8000);
Employee e3 = new Employee("王五",15000);
//通过调用方法,设置Employee对象的工作状态
getStatus(e1,Status.BUSY);
getStatus(e2,Status.NORMAL);
getStatus(e3,Status.FREE);
//创建ArrayList对象
ArrayList<Employee> al = new ArrayList();
//增加元素
al.add(e1);
al.add(e2);
al.add(e3);
System.out.println(al);
//遍历ArrayList,工作状态为FREE的员工扣工资
for(int i =0;i<al.size();i++){
if(Status.FREE.equals(al.get(i).getStatus())){
al.get(i).setSalary(al.get(i).getSalary()-1000);
}
}
System.out.println(al);
//通过List迭代器遍历,删除元素
ListIterator<Employee> li = al.listIterator();
while(li.hasNext()){
if(li.next().getSalary()>=10000){
li.remove();
}
}
System.out.println(al);
}
//为员工增加工作状态的方法
public static void getStatus(Employee emp,Status status){
emp.setStatus(status);
}
}
//Employee类
class Employee{
private String name;
private int salary;
private Status status;
public Employee(){
}
public Employee(String name,int salary){
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", status=" + status +
'}';
}
}
//枚举类
enum Status{
BUSY,NORMAL,FREE;
}
4.Vector实现类
也是通过数组存储数据,与ArrayList特点相同。
不同点:
- 线程安全的|同步的,如果不需要线程安全实现,建议使用ArrayList代替Vector;
- Vector每次扩容原容量2倍,ArrayList每次扩容原容量1.5倍,ArrayList有利于节省空间;
5.Set接口
无序且不可重复,存储数据的顺序与添加的顺序不同,没有新增方法。
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
//泛型规定集合中所有数据类型为String类型
Set<String> set = new HashSet<String>();
set.add("ab");
set.add("bc");
set.add("cd");
set.add("cd");
set.add("cd");
set.add("指针");
set.add("指针");
set.add("bd");
set.add("be");
set.remove("cd");
//去重且顺序与添加顺序不同
System.out.println(set);
}
}
6.TreeSets实现类
底层结构:红黑树(平衡二叉树)
特点:有序(存储数据默认升序),存放的顺序与内部存储的顺序不同
6.1比较器
内部比较器|自然排序:
- 自定义类需要实现Comparable接口,重写compareTo方法;
外部比较器|定值排序:
- 重新定义类,实现Comparator接口,重写compare方法,方法中定义规则。在定义TreeSet对象的时候将此类对象作为参数传入。
在Set进行排序时会首先选择默认比较器,即内部比较器。
内部比较器应用:
public class TreeSet {
public static void main(String[] args) {
Person p1 = new Person("张三",5000);
Person p2 = new Person("李四",10000);
Person p3 = new Person("王五",3000);
//自定义类型
Set<Person> set = new java.util.TreeSet<Person>();
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
//泛型:String类型
Set<String> set2 = new java.util.TreeSet<String>();
set2.add("123");
set2.add("abc");
set2.add("a1");
set2.add("b2");
//默认升序
System.out.println(set2);
/* Set set3 = new java.util.TreeSet();
set3.add(123);
set3.add("abc");
set3.add('a');
set3.add("b2");
System.out.println(set3);*/
}
}
class Person implements Comparable{//内部比较器首先要在自定义类开始实现Comparable接口
private int salary;
private String name;
public Person() {
}
public Person(String name,int salary) {
this.salary = salary;
this.name = name;
}
//内部比较器
@Override
public int compareTo(Object o) {//重写compareTo方法
int check = this.getSalary()-((Person)(o)).getSalary();//类型转换
if(check>0){
return 1;
}else if(check <0){
return -1;
}else{
return 0;
}
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"salary=" + salary +
", name='" + name + '\'' +
'}';
}
}
外部比较器:
import java.util.Comparator;
import java.util.Set;
public class TreeSet02 {
public static void main(String[] args) {
Person p1 = new Person("张三",5000);
Person p2 = new Person("李四",10000);
Person p3 = new Person("王五",3000);
Set<Person> set = new java.util.TreeSet<Person>(new Check());
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
}
}
//外部比较器
class Check implements Comparator<Person> {//创建新类实现Comparator接口,且泛型是自定义类型
@Override
public int compare(Person o1, Person o2) {
//判断条件
if(o1.getSalary()>o2.getSalary()){
return -1;
}else if(o1.getSalary()<o2.getSalary()){
return 1;
}else{
return 0;
}
}
}
内部比较器与外部比较器的区别:
外部比较灵活,便于后期维护;
内部比较器若要改变比较规则,每次都需要修改源代码,耦合度高,不便于后期维护。