集合框架Collection
在实际开发中,需要将使用的对象存储于特定数据结构的容器中,JDK提供了这样的容器——集合(Collection)
- Collection是一个接口,统一功能,定义了集合相关的操作方法,具有两个子接口:List和Set
- List:可重复集 和数组相似,有顺序,允许重复
实现类:
ArrayList:底层数组
LinkedList:底层链表
- Set:不可重复集 散列表,没有顺序,不允许重复
实现类:
HashSet
- 元素是否重复,取决于元素的equals()比较的结果
- 集合中存储的都是引用类型元素,并且集合只保存每个元素对象的引用,并非将元素对象本身存入集合
add-添加
- 往集合中添加元素
- 如果集合由于调用而更改-返回true
size-查看
- 查看集合中的元素个数
- 返回此集合中的元素数。 如果此收藏包含超过Integer.MAX_VALUE个元素,则返回Integer.MAX_VALUE
remove-删除某个元素
- 删除集合中的某个元素(如果存在)(可选操作)——返回true
clear-清空
- 清空集合中的元素
isEmpty-查看是否为空
查看集合是否为空
public static void main(String[] args) {
//向上造型:能调用的是Collection里的方法,最终使用的是ArrayList的重写方法
//也可以将ArrayList改为HashSet/LinkedList
//如果不是Collection,是上面三个,后面的就不能随意更改了
//集合可以添加的元素,是Object类型
Collection coll=new ArrayList();
//1.向集合中添加元素-可以是int、char、double、String
coll.add(1);
coll.add(6.28);
coll.add('e');
coll.add("hello");
//2.查看集合中有多少个元素
System.out.println(coll.size());//4
//3.删除集合中的某个元素
coll.remove('e');
System.out.println(coll);//[1, 6.28, hello]
//4.清空集合中的元素
coll.clear();
//5.查看集合是否为空
System.out.println(coll.isEmpty());//true
}
- 针对All的方法都是对集合的操作
contains-查看包含元素
- 集合中包含指定元素–返回true——集合&元素
containsAll-查看包含集合所有元素
- 如果集合包含 指定集合 中的所有元素——大集合&小集合——包含&被包含——返回true
public static void main(String[] args) {
Collection coll=new ArrayList();
coll.add(2);
coll.add('i');
coll.add("love");
coll.add("you");
//1.查看集合中指定的元素
System.out.println(coll.contains('j'));//false
System.out.println(coll.contains(1));//false
System.out.println(coll.contains("love"));//true
//2.判断当前集合是否包含给定集合中的所有元素
Collection coll1=new HashSet();
coll1.add("love");
coll1.add("you");
System.out.println(coll1.containsAll(coll));//false
System.out.println(coll.containsAll(coll1));//true
}
addAll-添加集合所有元素
- 传入一个集合——将该集合中的所有元素添加到当前集合中
//3.添加某集合中的所有元素到另一个集合中
coll.addAll(coll1);
System.out.println(coll);//[2, i, love, you, love, you]
retainAll-保留公共元素
- 仅保留此集合中 包含 在指定集合中 的元素(可选操作)
- 即在此集合中 删除 不包含在指定集合 中的元素
- 留下两个集合公共元素
//4.留下集合中相同的元素
coll.retainAll(coll1);
System.out.println(coll);//[love, you, love, you]
removeAll-删除公共元素
- 删除指定集合中 包含的所有 此集合 的元素
- 删掉A里面含有B的元素
//5.删除指定集合中 包含的所有 此集合 的元素
Collection coll2=new HashSet();
coll2.add("12345");
coll2.add("love");
coll2.removeAll(coll);
System.out.println(coll2);//[12345]
coll1.removeAll(coll);
System.out.println(coll1);//[]
System.out.println(coll);//[love, you, love, you]
toArray-返回所有元素的数组
- 返回一个包含集合中所有元素的数组
- 如果此集合对其迭代器返回的元素的顺序作出任何保证,此方法必须以相同的顺序返回元素
子接口List
- List接口是Collection的子接口,用于定义线性表数据结构。可以将List理解为存放对象的数组,其元素个数可以动态的增加或减少。
- List:可重复集 和数组相似,有顺序,允许重复
实现类:
ArrayList:底层数组——动态数组的方式实现接口
适合随机访问
LinkedList:底层链表——链表的方式实现接口
适合插入和删除
实现类ArrayList
- ArrayList:底层数组——动态数组的方式实现接口
- 适合随机访问
实现类LinkedList
- LinkedList:底层链表——链表的方式实现接口
- 适合插入和删除
add插入
- 将指定的元素插入此列表的指定位置(第几个位置)(可选操作)
- 重载的方法:add(E e)——将指定的元素追加到此列表的末尾
List<String> list=new ArrayList<String>();
//1.在指定位置插入指定元素
List list=new ArrayList();
list.add("we");
list.add("are");
list.add("family");
list.add(2,"big");
System.out.println(list);//[we, are, big, family]
remove删除
- remove(int index)删除该列表中指定位置的元素(可选操作)
- remove(Object o)从列表中删除第一个出现的指定元素(如果存在)(可选操作)
//2.删除指定位置的元素
list.remove(2);
System.out.println(list);//[we, are, family]
list.add(2,"big");
list.add(4,"big");
System.out.println(list);//[we, are, big, family, big]
//删除第一个出现的指定元素
list.remove("big");
System.out.println(list);//[we, are, family, big]
get获得
- 获得此列表中指定位置的元素
//3.返回指定位置的元素
String str=list.get(3);//index范围0~list.size()-1
System.out.println(str);//big
用for循环迭代
//list迭代除了可以使用迭代器,还可以使用for循环
for(int i=0;i<list.size();i++){
String str1=list.get(i);
System.out.print(str1+" ");//we are family big
}
size返回
- 返回此列表中的元素数
int a=list.size();
System.out.println(a);//4
set替换
- 用指定元素(可选操作)替换 此列表中指定位置的元素
//4.用指定元素替换指定位置的元素
list.set(2,"very");
System.out.println(list);//[we, are, very, big]
iterator迭代器
- 以正确的顺序返回列表中的元素的迭代器
//5.以正确的顺序返回列表中的元素的迭代器
list.iterator();
System.out.println(list);//[we, are, very, big]
clear删除所有
- 从此列表中删除所有元素(可选操作)
//6.删除列表中所有元素
list.clear();
System.out.println(list);//[]
subList获取
-
List的subList方法用于获取子List。
-
需要注意的是,subList获取的List与原List占有相同的存储空间,对子List的操作会影响原List。
— List subList(int fromIndex, int toIndex);
fromIndex和toIndex是截取子List的首尾下标(前包括,后不包括)
List<Integer>list=new ArrayList<Integer>();
for(int i=0;i<10;i++){
list.add(i);
}
System.out.println(list);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
List<Integer>subList=list.subList(3,8);
System.out.println(subList);//[3, 4, 5, 6, 7]
//subList获得的List和源List占用相同的数据空间
for(int i=0;i<subList.size();i++) {
subList.set(i, subList.get(i) * 10);
}
System.out.println(subList);//[30, 40, 50, 60, 70]
list.subList(3,8).clear();//用于删除连续元素
System.out.println(list);//[0, 1, 2, 8, 9]
ArrayList&&LinkedList
- ArrayList基于数组
- LinkedList基于链表——>和C语言一样
- 查找效率上——ArrayList更高——get(300)
LinkedList——从头开始
- 删除、插入效率:
ArrayList插入的时候,后面的要往后移动
LinkedList插入的时候,将指定节点上的线连接到插入的一端,再另一端连接到断掉的另一个节点一端
-
但是是就删除和插入这个动作而言——之前要查找
-
LinkedList:双向列表(无头尾相连那条线)
头—>尾
尾—>头
- 补充:单向列表:头—>尾
循环列表:头—>尾—>头
public class Demo02ArrayListAndLinkedList {
public static void main(String[] args) {
List<Integer> list1=new ArrayList<Integer>();
List<Integer> list2=new LinkedList<Integer>();
//做准备数据
for(int i=0;i<10000000;i++){
list1.add(i);
list2.add(i);
}
//比较他们的查询效率
//1.比较从头部查询
long time1=System.currentTimeMillis();
list1.get(10);
long time2=System.currentTimeMillis();
list2.get(10);
long time3=System.currentTimeMillis();
System.out.println("ArrayList从头部查询时间:"+(time2-time1));//0
System.out.println("LinkedList从头部查询时间:"+(time3-time2));//0
//2.从中间查询
long time4=System.currentTimeMillis();
list1.get(5000000);
long time5=System.currentTimeMillis();
list2.get(5000000);
long time6=System.currentTimeMillis();
System.out.println("ArrayList从中间查询时间:"+(time5-time4));//0
System.out.println("LinkedList从中间查询时间:"+(time6-time5));//38
//3.从尾部查询
long time7=System.currentTimeMillis();
list1.get(9999990);
long time8=System.currentTimeMillis();
list2.get(9999990);
long time9=System.currentTimeMillis();
System.out.println("ArrayList从尾部查询时间:"+(time8-time7));//0
System.out.println("LinkedList从尾部查询时间:"+(time9-time8));//0
}
}
List转换为数组–toArray
-
List的toArray方法用于将 集合转换为数组。但实际上该方法是在Collection中定义的,所以所有的集合都具备这个功能。
-
其有两个方法:
— Object[] toArray()
— T[] toArray(T[] a)
其中第二个方法是比较常用的,我们可以传入一个指定类型的数组,该数组的元素类型应与集合的元素类型一致。返回值则是转换后的数组,该数组会保存集合中所有的元素。
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String[]strArr=list.toArray(new String[]{});//声明一个String类型的数组对象,长度为0,添加元素后,长度++
System.out.println(Arrays.toString(strArr));//[a, b, c]
数组转换为List–asList
-
Arrays类中提供了一个静态方法asList,使用该方法我们可以将一个数组转换为对应的List集合。
-
其方法定义为:
— static List asList<T… a>
返回的List的集合元素类型由传入的数组的元素类型决定。
并且要注意的是,返回的集合我们不能对其增删元素,否则会抛出异常。并且对集合的元素进行修改会影响数组对应的元素。
String[]strArr={"a","b","c"};
List<String>list= Arrays.asList(strArr);
System.out.println(list);//[a, b, c]
//list.add("d");//会抛出UnsupportedOperationException
System.out.println(list.getClass().getName());//java.util.Arrays$ArrayList
List<String>list1=new ArrayList<String>();
list1.addAll(Arrays.asList(strArr));
System.out.println(list1);//[a, b, c]
子接口Set
- Set:不可重复集 散列表,没有顺序,(有顺序,但是它自己懂,我们不懂) 不允许重复
实现类:
HashSet
实现类HashSet
- Set没有额外的方法,使用的是Collection里的方法
public static void main(String[] args) {
Set<String> sets=new HashSet<String>();
sets.add("bai bai");
sets.add("see you");
sets.add("say goodbye");
sets.add("nani");
sets.add("what");
System.out.println(sets);//[what, bai bai, see you, say goodbye, nani]
}
- 能使用forEach循环
for(String str : sets){
System.out.print(str+" ");
//what bai bai see you say goodbye nani
}
- HashSet中不允许对象重复,取决于两个方法,equals hashCode方法
public class People {
private String name;
private int age;
private char gendar;
public People(String name,int age,char gendar){
this.name=name;
this.age=age;
this.gendar=gendar;
}
public String grtName(){
return name;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", gendar=" + gendar +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return age == people.age && gendar == people.gendar && Objects.equals(name, people.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, gendar);
}
}
public class Demo02 {
@Override
public String toString() {
return "Demo02{}";
}
public static void main(String[] args) {
Set<People>sets=new HashSet<People>();
sets.add(new People("zhangsan",18,'m') );
sets.add(new People("zhangsan",18,'m') );
sets.add(new People("lisi",20,'m') );
sets.add(new People("lisi",20,'m') );
sets.add(new People("zhaowu",33,'m') );
System.out.println(sets.size());//3
System.out.println(sets);
//[People{name='lisi', age=20, gendar=m}, People{name='zhaowu', age=33, gendar=m}, People{name='zhangsan', age=18, gendar=m}]
}
}
实现类TreeSet
- 二叉树,本身有序,中序遍历[由小到大]
- TreeSet不允许重复,看compareTo方法
public class Demo03TreeSet {
public static void main(String[] args) {
Set<String> set=new TreeSet<String>();
set.add("strong");
set.add("height");
set.add("width");
set.add("weak");
set.add("beautiful");
//按照字典顺序排序
System.out.println(set);//[beautiful, height, strong, weak, width]
//重写了equals和hashCode方法,所以People在hashSet中不允许重复的
//TreeSet不允许重复,看compareTo方法
//若不能修改People类,有要求People对象在TreeSet中按照姓名排序,如果名字一样的时候,再根据年龄排序
//用比较器 comparator
Comparator comparator=new MyComparator();
Set<People>ps=new TreeSet<People>();
ps.add(new People("zhangsan",18,'m'));
ps.add(new People("lisi",20,'m'));
ps.add(new People("lisi",20,'m'));
ps.add(new People("zhaowu",33,'m'));
System.out.println(ps);//[People{name='zhangsan', age=18, gendar=m}, People{name='lisi', age=20, gendar=m}, People{name='zhaowu', age=33, gendar=m}]
//修改compareTo方法的返回值为0,返回一个对象
}
}
class MyComparator implements Comparator<People>{
/**
* 比较o1,o2对象
* @param o1
* @param o2
* @return>0 说明o1>o2
* <0 说明o1<o2
* =0 说明o1=o2
*/
@Override
public int compare(People o1, People o2) {
return o1.getName().compareTo(o2.getName());
}
}