目录
1. 类集
Java类集框架 —— 动态对象数组,数组不再受限于固定长度
- 在Java的类集里面(java.util包)提供了两个最为核心的接口两个接口相互独立:
Collection接口 — 针对单个元素的最顶层接口,继承自Iterable迭代器接口,操作形式类似于链表
Map接口 — 针对键值对对象(多个元素)处理(key value)的顶层接口,继承自Object
2. Collection 接口
顶层接口
- Collection接口中有三个重要方法:
add(E e):向集合中添加元素
iterator():返回此集合所有元素的迭代器(遍历集合的工具)
removeIf(Predicate<? super E> filter):删除满足给定条件的此集合的所有元素
-
Collection接口中有两个使用频率很高的子接口:
List有序集合(序列):允许重复元素
Set集合:不允许重复元素
3. List接口
Collection -> List -> AbstractList -> (ArrayList、Vector、LinkedList)
- List接口中两个重要的扩展方法:
//根据索引取得数据
public E get(int index)
//根据指定索引修改相应元素
E set(int index,E element)
-
3.1 ArrayList(优先考虑)
底层实现是一个对象数组,声明一个ArrayList对象时,初始化对象数组长度为0。
- 3.1.1 ArrayList的基本使用:
import java.util.ArrayList;
import java.util.List;
/**
* List -> ArrayList基本使用
* Author: qqy
*/
public class Test {
public static void main(String[] args) {
//向上转型 实例化一个ArrayList对象 ,List类型
List<String> list=new ArrayList<>();
list.add("good");
list.add("hello");
//重复元素
list.add("good");
System.out.println(list); //[good, hello, good]
System.out.println(list.contains("good")); //true
System.out.println(list.indexof("good")); //0
System.out.println(list.lastIndexof("good")); //2
System.out.println(list.size()); //3
System.out.println(list.remove("good")); //true 删除第一个good,等价于list.remove(0)
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+" "); //hello good ,下标从0到size-1
}
list.set(1,"bonjour");
System.out.println(list); //[hello, bonjour]
//迭代器接口
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next());
System.out.print(","); //hello,bonjour,
}
list.clear();
System.out.println(list.size()); //0
}
}
-
3.1.2 数据结构:List -> ArrayList
-
ArrayList的数据通过数组存放
-
ArrayList的默认构造方法实例化,存储数据的数组初始化时在第一次添加元素时进行(lazy load延迟加载)
-
ArrayList的初始化容量的构造方法实例化,存储数据的数组立即初始化
-
-扩容50% ,默认容量10
import java.util.*;
/**
* 将List转成数组
* Author: qqy
*/
public class Test2 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("good");
list.add("hello");
list.add("good");
//Object[] elementArray = list.toArray();
String[] elementArray = new String[list.size()];
for (int i = 0, len = list.size(); i < len; i++) {
elementArray[i] = list.get(i);
}
System.out.println(Arrays.toString(elementArray));//[good, hello, good]
String[] elementArray1 = new String[list.size()+2];
list.toArray(elementArray1);
System.out.println(Arrays.toString(elementArray1));//[good, hello, good, null, null]
String[] elementArray2 = new String[list.size()-1];
list.toArray(elementArray2);
System.out.println(Arrays.toString(elementArray2));//[null, null]
//不建议直接使用Collection接口
//toArray()由Collection提供,将list中的元素转化为Object[],向下转型,有可能产生ClassCastException
Collection collection = list;
collection.toArray();
}
}
- 3.1.3 接口中要保存自定义类对象,自定义类必须覆写equals();
- 类集contains()、remove()等方法需要调用equals()来判断元素是否相等(自定义是否要覆写equals())
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Author: qqy
*/
public class Test{
public static void main(String[] args) {
Person per = new Person("张三", 18);
Person per1 = new Person("李四", 20);
Person per2 = new Person("王五", 22);
List<Person> list = new ArrayList<>();
list.add(per);
list.add(per1);
list.add(per2);
//remove()、contains()借用Object定义的equals(),比较地址是否相同(是否是同一对象)
//覆写equals()->true,true;不覆写->false.true
System.out.println(list.contains(new Person("张三", 18)));
System.out.println(list.contains(per));
list.remove(new Person("王五", 22));
System.out.println(list);
//Map<K,V> K取hashCode,因此覆写方法时equals()与hashcode()捆绑覆写
Person jack = new Person("Jack", 22);
Person jack2 = new Person("Jack", 22);
System.out.println(jack.equals(jack2));//手工equals 覆写比内容,但hashCode值不同
System.out.println(jack.hashCode() == jack2.hashCode());
}
}
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name=" + name +
" age=" + age +
"}";
}
//手工覆写
// @Override
// public boolean equals(Object obj) {
// //对象相同
// if (this == obj) {
// return true;
// }
// if (this == null) {
// return false;
// }
// if (!(obj instanceof Person)) {
// return false;
// }
// //向下转型为Person对象比较属性
// Person per = (Person) obj;
// return this.age == per.age && this.name.equals(per.name);
// }
//1. equals 和 hashCode 方法覆写一定要一起使用,只覆写一个方法并不能唯一的表示一个对象
//2. equals参与判断的属性都要参与hashCode的计算
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
-
3.2 Vector
底层实现是一个对象数组,声明一个Vector对象时,初始化对象数组长度为10。
- ArrayList与Vector区别
- 产生版本:ArrayList -> JDK1.2提供的,而Vector -> JDK1.0就提供了。
- 线程安全:ArrayList是异步处理,性能更高,非线程安全;Vector是同步处理(synchronized),性能较低,线程安全。
- 输出形式:ArrayList支持Iterator、ListIterator、foreach;Vector支持Iterator、ListIterator、 foreach、Enumeration。
- 初始化:ArrayList使用懒加载策略,在第一次添加元素是才初始化数组大小;Vector对象产生时就初始化,数组大小为10。
- 扩容策略:ArrayList变为原来数组的1.5倍,Vector变为原来数组的2倍
import java.util.*;
/**
* Author: qqy
*/
public class Test4 {
public static void main(String[] args) {
//Vector相似于ArrayList
List<String> vector=new Vector<>();
vector.add("jack");
vector.add("mary");
System.out.println(vector);
//Enumeration相当于迭代器(old API,了解即可)
Enumeration<String> enumeration=((Vector<String>) vector).elements();
while(enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());
}
}
}
-
3.3 LinkedList
双向链表
import java.util.LinkedList;
import java.util.List;
/**
* LinkedList
* Author:qqy
*/
public class Test6 {
public static void main(String[] args) {
List<String> list = new LinkedList<>();
list.add("hello");
list.add("vie");
list.add("amour");
System.out.println(list);
list.remove("hello");
System.out.println(list);
}
}
- 解释ArrayList与LinkedList区别
1. ArrayList:里面存放的是一个数组,如果实例化此类对象时传入了数组大小,则里面保存的数组就会开辟一个定长的数组,但是后面再进行数据保存的时候发现数组个数不够了会进行数组动态扩充。 所以在实际开发之中,使用ArrayList最好的做法就是设置初始化大小。时间复杂度:1
2. LinkedList:是一个纯粹的链表实现,与之前编写的链表程序的实现基本一样(性能高)。时间复杂度:n
4. Set集合接口
Set接口中没有get()方法
- Set子接口中有两个常用子类:
HashSet(无序存储)、TreeSet(有序存储 -> 字母升序)
-
4.1 HashSet
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* HashSet
* Author:qqy
*/
public class Test7 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Java");
set.add("C++");
set.add("C");
set.add("PHP");
set.add("Python");
set.add("Java");
//遍历
Iterator<String> iterator = set.iterator();
//也可使用foreach
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//判断元素是否存在(String已覆写equals())
System.out.println(set.contains("Java"));//true
System.out.println(set.contains("JavaScript"));//false
}
}
-
4.2 TreeSet
重要的两种构造方法:
无参构造方法:构造一个新的数组,根据其元素的自然排序进行排序。
有参构造方法:构造一个新的数组,根据指定的比较器进行排序。
/**
* TreeSet
* Author:qqy
*/
public class Test8 {
public static void main(String[] args) {
//1.TreeSet无参数构造方法,元素排序使用元素的排序策略
//2.TreeSet有参数,传递比较器的实例化对象,采用自定义的比较方法
//1.
Set<String> set1 = new TreeSet<>();
//2.
//比较常用方法2,灵活,比较策略容易替换
Set<String> set = new TreeSet<>(
new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//倒序
return o1.compareTo(o2)*-1;
}
}
//Lambda表达式
// (o1, o2) -> o1.compareTo(o2) * -1
);
set.add("Java");
set.add("C++");
set.add("PHP");
set.add("Python");
set.add("C");
//遍历
Iterator<String> iterator = set.iterator();
//foreach
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
- 建议:
1. 保存自定义对象的时候使用List接口;
2. 保存系统类信息的时候使用Set接口(避免重复)。