集合(collection)概述:
- 长度是可以随意改变的
- 集合只能存储对象,不能存储基本数据类型(但基本数据类型可以转化为对应的包装类)
- 集合没有默认值
- 接口,不能直接创建对象
包装类
* 数据想拥有自己的方法 包装类
* byte short int long Byte Short Integer Long
* float double Float Double
* char Charater
* boolean Boolean
集合体系
Collection中的常用功能
迭代器作用:遍历集合
迭代器进行遍历的步骤
- 先有一个迭代器对象Iterator()返回collection里的元素进行迭代的迭代器
- 要判断集合中是否有下一个元素可取boolean hasnext();
public static void main(String[] args) {
// 创建一个ArrayList的对象
ArrayList c = new ArrayList();
// 添加元素
c.add("小明");
c.add("二明");
// 遍历器
Iterator it=c.iterator();
//用hasNext判断是否还有元素可以取
while(it.hasNext()){
System.out.println(it.next());//取元素
}
并发修改异常:当使用迭代器遍历集合的时候,使用了集合中的增加/删除方法,导致并发修改异常
public static void main(String[] args) {
ArrayList c = new ArrayList();
c.add("小明");
c.add("二明");
c.add("三明");
Iterator it=c.iterator();
while (it.hasNext()){
//如果输出的下一个元素是小明就添加四明
if(it.next().equals("小明")){
c.add("四明");
}
System.out.println(it.next());
}
}
输出结果如下:
避免并发修改异常
public static void main(String[] args) {
ArrayList c = new ArrayList();
c.add("小明");
c.add("二明");
c.add("三明");
//ListIterator extends Iterator(){}
ListIterator it=c.listIterator();
while (it.hasNext()){
if(it.next().equals("小明")){
it.add("四明");
}
}
System.out.println(c);
输出结果如下图:
增强for&泛型
增强for(foreach)
格式:for(元素的数据类型 变量名:集合对象){
}
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("小明");
c.add("二明");
c.add("三明");
//foreach进行数组的遍历 Object obj:接收每一次遍历的元素的变量 c:要遍历的对象
for(Object obj:c){
System.out.println(obj);
}
//判断集合中是否有小明,如果有就加入四明
//注意:增强for的时候不要对集合进行增加和删除的操作
/* for (Object o : c) {
String s=(String)o;//"o"的数据类型为Object需要强转
if(s.equals("小明")){
c.add("四明");
}
}
System.out.println(c);*/
}
输出结果如下:
泛型:为集合规定存储的数据类型的
:代表我们全部的数据类型,集合本身是存储对象的但因为基本数据类型可以转化为包装类所以可以存储,得到的数据类型是Object类型的数据,想得到对应的类型需要强转。
< >:给定了泛型就是规定了这个集合只能存储这种我们规定的数据类型的数据,集合在添加数据的时候只能添加对应类型的数据,得到的元素也不需要强转。
代码对比:
//定义存储String类型的集合
Collection<String> c=new ArrayList<String>();
c.add("q");
c.add("小明");
for (String s : c) {
System.out.println(s);
}
/***********************************************************************/
//全部数据类型
Collection<E> c=new ArrayList<>();
c.add("q");
c.add("小明");
for (Object o : c) {
//需要强制转换为String类型
String s=(String) o;
System.out.println(s);
}
List集合与Set集合的区别
List集合(列表):
- 有顺序的存取数据
- 有索引标志
- 接口,不能直接创建对象
- 允许重复
数组:
1、存储多个同一种类型的数据(基本数据类型、引用数据类型的对象)
2、长度是固定的
3、有默认值
定义方式:
1、动态声明int[] arr=new int[];
2、静态声明int[] arr={1,2,3};
ArrayList特有功能
描述 | 方法 |
---|---|
向集合中添加元素 | boolean add(Object e) |
清空集合中所有元素 | void clear() |
判断集合中是否包含某个元素 | boolean contains(Object o) |
判断集合中的元素是否为空 | boolean isEmpty() |
根据元素的内容来删除某个元素 | boolean remove(Object o) |
获取集合的长度 | int size() |
能够将集合转换成数组并把集合中的元素存储到数组中 | Object[] toArray() |
// 创建集合对象
ArrayList a=new ArrayList();
// 多态----父类引用指向子类
Collection c = new ArrayList();
// **boolean add(Object e): 向集合中添加元素
c.add(2);//自动装箱:包装类(interage) object存储任意类型
c.add("java");
c.add("world");
c.add("world");//允许重复 因为add方法的返回值永远是true
// void clear():清空集合中所有元素
// c.clear();
System.out.println(c);
// boolean contains(Object o):判断集合中是否包含某个元素
boolean flag1 = c.contains("w");
System.out.println(flag1);
// boolean isEmpty():判断集合中的元素是否为空
boolean flag2 = c.isEmpty();
System.out.println("是否为空集合:"+flag2);
// boolean remove(Object o):根据元素的内容来删除某个元素
boolean flag3 = c.remove("world");
System.out.println("是否删除成功"+flag3);//一次删除一个
System.out.println(c);
// ** int size():获取集合的长度
System.out.println("集合的元素个数"+c.size());
// ** Object[] toArray():能够将集合转换成数组并把集合中的元素存储到数组中
// 遍历集合的第一种方式:通过toArray把集合转化为object()数组,再遍历数组
Object[] arr = c.toArray();
for (int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
}
输出结果为:
LinkedList特有功能
描述 | 方法 |
---|---|
向链表的头部添加元素 | void addFirst(E e) |
向链表的尾部添加元素 | void addLast(E e) |
获取链头的元素,不删除元素 | E getFirst() |
获取链尾的元素,不删除元素 | E getLast() |
返回链头的元素并删除链头的元素 | E removeFirst() |
返回链尾的元素并删除链尾的元素 | E removeLast() |
LinkedList底层使用的是链表结构,因此增删快,查询相对ArrayList较慢
public static void main(String[] args) {
LinkedList list=new LinkedList();
list.add("hello");
list.add("world");
list.add("haha");
list.add("java");
// 添加第一个位元素
list.addFirst("heihei");
// 获取第一个位置的元素,不删除元素
// Object first=list.getFirst();
// System.out.println("第一个位置的元素:"+first);
// 返回链头的元素并删除链头的元素
list.removeFirst();
// 向链表的尾部添加元素
list.addLast("javaEE");
// 返回链尾的元素并删除链尾的元素
list.removeLast();
//增强for循环
for (Object o : list) {
System.out.println(o);
}
}
Collections:集合的操作工具类,封装了很多进行集合操作的方法
描述 | 方法 |
---|---|
复制集合(目标集合长度必须大于原来的集合长度) | Collections.copy() |
填充全部元素 | Collections.fill() |
反转 | Collections.reverse |
随机置换 | Collections.shuffle() |
互换指定索引位置的元素 | Collections.swap() |
排序 | Collections.sort() |
向指定集合中添加元素 | Collections.addAll() |
二分法查找 | Collections.binarySearch() |
Set集合(桶):
- 存取数据是没有顺序的
- 没有索引标志(没有get通过索引获取元素的方法),不允许重复
- 接口,不能直接创建对象
- Set集合体系包括HashSet集合和TreeSet集合
HashSet集合
1.新添加到HashSet集合的元素都会与集合中已有的元素进行一一比较,首先比较哈希值(每个元素都会调用hashCode()产生一个哈希值),如果新添加的元素与集合中已有的元素的哈希值都不同新添加的元素存入集合
2.如果新添加的元素与集合中已有的某个元素哈希值相同,此时还需要比较对象的内容。
equals(Object obj)比较
Object的equals()比较的是两个对象的系统给定的真正的地址值,所以为了比较两个对象的内容而不是地址值,所以要重写Object和equals()
注意:HashSet存储的对象如果想去重,要重写Object的HashCode()和equals();
获取的HashCode—物理层次给予对象的唯一标识(是人为可以更改的)
identityHashCode----是系统层次的唯一标识(是不可以人为更改的)
//把学生类添加进集合
public static void main(String[] args) {
Set set=new HashSet();//Set接口:无序 无索引(没有get通过索引获取元素的方法) 不允许重复
Student s1 = new Student("小明",18);
Student s2 = new Student("小兰",19);
Student s3 = new Student("小红",20);
Student s4 = new Student("小红",20);
// Object的HashCode方法
System.out.println(set);
System.out.println(System.identityHashCode(set));
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
// 增强for
for (Object o:set) {
System.out.println(o);
}
}
public static void main(String[] args) {
Student s=new Student("小明");
Student s1=new Student("小明");
//object的equals相当于是一个== 比较的是两个对象真正的地址值
System.out.println(s.equals(s1));
//获取s的哈希值---物理层次给予的对象的唯一标识(是人为可以更改的)
System.out.println(s.hashCode());
//获取s的地址值(系统层次给予对象的唯一标识---不可以人为更改的)
System.out.println(System.identityHashCode(s));
System.out.println(s1.hashCode());
}
//再Student.class里重写hashCode()和equals() 方法
@Override
public boolean equals(Object obj) {
Student s=(Student)obj;
if(this.name.equals(s.getName())){
return true;
}
return false;
}
@Override
public int hashCode() {
return 1;
}
HashSet
1、因为哈希值是物理层次的地址值,每new出来一个对象尽管内容是一样的,但是哈希值肯定是不一样的
因为HashSet的add首先判断的是哈希值,如果不一样就直接添加到集合中,所以要重写Object中的Hashcode方法,把每个哈希值更改为一样的
2、所以HashCode的add方法,如果判断对象的哈希值一致,那么久会去判断对象的内容,如果内容不一样就添加到集合,如果内容一样就去重.
因为Object的equals比较的是真正的地址值,要想只要比较内容,那么还要去重写equals()
Hashcode()优化
因为如果把HashCode()的返回值定义为1,集合每添加一个元素,都要跟集合所有元素进行比较调用
Hashcode的次数会很多,也会消耗更多的内存空间,只要让不同的属性的值产生不同的哈希值,那么就可以不再调用equals方法了,比较提高效率。
public class Student {
//属性私有化
private String name;
private int age;
//创建构造方法
public Student(){
}
public Student(String name){
this.name=name;
}
public Student(String name,int age){
this.age=age;
this.name=name;
}
//get和set方法
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;
}
//重写toString()方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写equals() 方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return getAge() == student.getAge() &&
Objects.equals(getName(), student.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
public static void main(String[] args) {
Student s=new Student("小明");
Student s1=new Student("小明");
//object的equals相当于是一个== 比较的是两个对象真正的地址值
System.out.println(s.equals(s1));
//获取s的哈希值---物理层次给予的对象的唯一标识(是人为可以更改的)
System.out.println(s.hashCode());
//获取s的地址值(系统层次给予对象的唯一标识---不可以人为更改的)
System.out.println(System.identityHashCode(s));
System.out.println(s1.hashCode());
}
TreeSet集合特点:可以对Set集合中的元素进行自然排序,所有往Set集合中保存的对象应该具备自然排序规则。
TreeSet底层的数据结构使用的是二叉树
三种TreeSet集合排序方法
第一种排序方法:让元素本身具备比较功能
//往TreeSet里保存的对象要实现(implements)Comparable接口
public class Person implements Comparable {
String name;
int age;
@Override
public int compareTo(Object o) {
// 向下转型
Person p=(Person)o;
//大于返回正整数,小于返回负整数,等于返回零。
if(this.age>p.getAge()){
return 1;
}
if(this.age<p.getAge()){
return -1;
}
return 0;
第二种排序方法:集合自身具备比较排序功能
public static void main(String[] args) {
// 匿名内部类
TreeSet ts=new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Person p = (Person) o1;
Person p1 = (Person) o2;
if (p.age > p1.getAge()) {
return 1;
}
if (p.age < p1.getAge()) {
return -1;
}
return 0;
}
});
}
第三种集合排序方法
//内部类🤣
class CompareDemo implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Person p = (Person) o1;
Person p1 = (Person) o2;
if (p.age > p1.getAge()) {
return 1;
}
if (p.age < p1.getAge()) {
return -1;
}
return 0;
}
}