Collection接口
Collection接口
Collection中 只要是Object的子类型,都能存储(集合中不能直接存储基本数据类型,也不能存储java对象,只是存储Java对象的内存地址)
关于java.util.Collection接口中常用的方法
boolean add(Object e)
向集合中添加元素int size()
获取集合中元素的个数void clear()
清空集合boolean isEmpty()
判断该集合中的元素个数是否为0boolean contains(Object o)
判断当前集合中是否包含元素o,包含返回true,不包含返回falseboolean remove(Object o)
删除集合中的某个元素Object[] toArray()
把集合转换成数组
public class CollectionTest {
public static void main(String[] args) {
// 创建一个集合对象
//Collection c = new Collection(); // 接口是抽象的,无法实例化
// 多态
Collection c = new ArrayList();
// 测试Collection接口中的常用方法
// 1. boolean add(Object e) 向集合中添加元素
c.add(123); // 自动装箱,实际上存储的是对象的内存地址
// 2. int size() 获取集合中元素的个数
System.out.println("集合中的元素个数是:" + c.size()); //1
// 3. void clear() 清空集合
c.clear();
System.out.println("集合中的元素个数是:" + c.size()); //0
// 4. boolean isEmpty() 判断该集合中的元素个数是否为0
System.out.println(c.isEmpty()); //true
// 再添加元素
c.add("hello");
c.add("would");
// 5. boolean contains(Object o) 判断当前集合中是否包含元素o,包含返回true,不包含返回false
System.out.println(c.contains("hello")); //true
// 6. boolean remove(Object o) 删除集合中的某个元素
System.out.println("集合中的元素个数是:" + c.size()); //2
c.remove("would");
System.out.println("集合中的元素个数是:" + c.size()); //1
}
}
集合遍历/迭代(重点)
集合遍历/迭代方式在Map集合中不能用,在所有的Collection以及子类中使用。
迭代器对象Iterator中的方法:
boolean hasNext()
如果仍有元素可以迭代,则返回trueObject next()
返回迭代器的下一个元素
public class CollectionTest01 {
public static void main(String[] args) {
// 创建集合对象,不一定要HashSet
Collection c = new HashSet();
// 添加元素
c.add("asd");
c.add("qwe");
c.add(123);
c.add(new Object());
// 对集合Collection进行遍历/迭代
// 1.获取集合对象的迭代器对象Iterator
Iterator iterator = c.iterator();
// 2.通过以上获取的迭代器对象开始迭代/遍历集合
while (iterator.hasNext()) {
Object obj = iterator.next(); //取出来的都是Object类型的
System.out.println(obj);
}
}
}
深入contains、remove方法
总结:存放在集合里的类型必须重写equals方法
public class CollectionTest02 {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
// 向集合中存储元素
String s1 = new String("asd");
c.add(s1);
String s2 = new String("qwe");
c.add(s2);
// 集合中的元素个数
System.out.println("集合中的元素个数是:" + c.size()); //2
// 新建的对象String
String s = new String("asd");
// 底层调用equals方法,比较的是内容
System.out.println(c.contains(s)); // true
System.out.println("remove:" + c.remove(s)); // true
System.out.println("集合中的元素个数是:" + c.size()); //1
System.out.println("----------------------------------------");
User u1 = new User("zxc");
c.add(u1);
User u = new User("zxc");
System.out.println("集合中的元素个数是:" + c.size()); //2
// 没有重写equals方法
//System.out.println(c.contains(u)); //false
//System.out.println("remove:" + c.remove(s)); //false
// 重写equals方法之后
System.out.println(c.contains(u)); //true
System.out.println("remove" + c.remove(s)); //true
System.out.println("集合中的元素个数是:" + c.size());
}
}
class User{
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
// 重写equals
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || !(obj instanceof User)) return false;
User user = (User) obj;
return Objects.equals(name, user.name);
}
}
重点:在迭代元素的过程中,一定要使用迭代器Iterator的remove方法删除元素,不要使用集合自带的remove方法,否则会出现ConcurrentModificationException异常
public class CollectionTest03 {
public static void main(String[] args) {
// 创建集合对象,不一定要HashSet
Collection c = new ArrayList();
// 添加元素
c.add("asd");
c.add("qwe");
c.add("zxc");
// 对集合Collection进行遍历/迭代
// 注意:集合结构只要发生改变,迭代器必须重新获取
Iterator iterator = c.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
// 删除元素之后,集合的结构发生了变化,会出现java.util.ConcurrentModificationException异常
//c.remove(obj); // 直接通过集合去删除元素,没有通知迭代器。(导致迭代器的快照与原集合不同)
// 可以使用迭代器的remove()方法
iterator.remove(); // 删除的一定是迭代器指向的当前元素(迭代器与原集合同时删除)
System.out.println(obj);
}
System.out.println("集合中的元素个数是:" + c.size()); //0
}
}
List接口
1.List集合存储元素特点:有序可重复
2.List是Collection接口的子接口,
以下是List接口特有的常用方法:
void add(int index, Object element)
在列表指定位置插入指定元素(第一个参数是下标) 使用不多,效率较低Object set(int index, Object element)
修改指定位置的元素Object get(int index)
根据下标获取元素int indexOf(Object o)
获取指定对象第一次出现处的索引int lastIndexOf(Object o)
获取指定对象最后一次出现处的索引Object remove(int index)
删除指定下标位置的元素
public class ListTest {
public static void main(String[] args) {
// 创建List类型的集合
List myList = new ArrayList();
// 添加元素
myList.add("asd"); // 默认都是向集合末尾添加元素
myList.add("qwe");
myList.add("zxc");
myList.add("zxc");
// 1. void add(int index, Object element) 在列表指定位置插入指定元素(第一个参数是下标)
// 使用不多,效率较低
myList.add(1,"asd1");
Iterator iterator = myList.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println("----------------------------");
// 2. Object set(int index, Object element) 修改指定位置的元素
myList.set(1,"asd2");
for (int i = 0; i < myList.size(); i++) {
Object obj = myList.get(i);
System.out.println(obj);
}
System.out.println("----------------------------");
// 3. Object get(int index) 根据下标获取元素
Object firstObj = myList.get(0);
System.out.println(firstObj);
// 通过下标遍历(List集合特有的方式,Set没有)
for (int i = 0; i < myList.size(); i++) {
Object obj = myList.get(i);
System.out.println(obj);
}
System.out.println("----------------------------");
// 4. int indexOf(Object o) 获取指定对象第一次出现处的索引
System.out.println(myList.indexOf("zxc")); //3
// 5. int lastIndexOf(Object o) 获取指定对象最后一次出现处的索引
System.out.println(myList.lastIndexOf("zxc")); //4
//6. Object remove(int index) 删除指定下标位置的元素
System.out.println(myList.size()); //5
myList.remove(1);
System.out.println(myList.size()); //4
}
}
ArrayList集合
- 默认初始化容量是
10
(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量为10) - 集合底层是一个
Object[]数组
- 构造方法:
new ArrayList();
new ArrayList(20); - ArrayList集合的扩容:
原容量的1.5倍
ArrayList集合底层是数组,怎么优化?尽可能少的扩容
。因为数组扩容效率比较低(因为很难找到一块连续的比较大的内存空间),建议在使用ArrayList集合的时候预估计元素的个数,给定一个初始化容量。
- 数组优点:
检索效率
比较高
(每个元素占用空间大小相同,内存地址是连续的,知道首元素内存地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高)
- 数组缺点:
随机增删
元素效率
比较低
- 向数组末尾添加元素,效率很高,不受影响
ArrayList
集合的使用最多
,因为往数组末尾添加元素,效率很高,且检索/查找某个元素的操作比较多。
public class ArrayListTest {
public static void main(String[] args) {
// 默认初始化容量 10
List list = new ArrayList();
// 集合的size()方法是获取当前集合中元素的个数,不是获取集合的容量。
System.out.println(list.size()); //0
// 指定初始化容量 20
List list1 = new ArrayList(20);
System.out.println(list1.size()); //0
// 创建一个HashSet集合
Collection c = new HashSet();
c.add(1);
c.add(2);
c.add(3);
// 通过这个构造方法就可以将HashSet集合转换成List集合
List list2 = new ArrayList(c);
for (int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
补充:位运算符 >>
<<
public class BinaryTest {
public static void main(String[] args) {
// >> 1 二进制右移1位
// 10的二进制:00001010
// 右移1位后:00000101
System.out.println(10 >> 1); //5
// << 1 二进制左移一位
// 10的二进制:00001010
// 左移1位后:00010100
System.out.println(10 << 1); //20
}
}
LinkedList集合
链表的优点:
- 由于链表上的元素在空间存储上内存地址不连续。
- 所以
随机增删
元素的时候不会有大量元素位移,因此随机增删效率较高
- 遇到
随机增删
集合中元素的业务比较多
时,建议
使用LinkedList
链表的缺点:
- 不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。
- 所以
LinkedList
集合检索/查找
效率较低
ArrayList
:把检索发挥到极致。
LinkedList
:把随机增删发挥到极致。
添加元素一般都是往末尾加,所以ArrayList
用的比LinkedList
多。
public class LinkedListTest {
public static void main(String[] args) {
// LinkedList集合没有初始化容量
// LinkedList集合底层也是有下标的
// 注意:ArrayList之所以检索效率比较高,不是单纯因为下标的原因,主要是底层数组发挥的作用。
// LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较第,因为每一次查找都是从头节点开始一个一个遍历
List list = new LinkedList(); // 底层是链表
//List list = new ArrayList(); // 底层是数组
// 面向接口编程
list.add("a");
list.add("b");
list.add("c");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
Vector集合
-
底层也是一个
数组
-
初始化容量:
10
-
Vector
集合扩容方式:扩容之后是原容量的2倍
。 -
ArrayList
集合扩容特点:扩容之后是原容量的1.5倍
。 -
Vector
中所有的方法都是线程同步
的,都带有synchronized
关键字,是线程安全
的。效率比较低,使用较少了。 -
将一个
线程不安全
的ArrayList
集合转换成线程安全
的方法:
使用集合工具类:java.util.Collections
java.util.Collection 是集合接口 java.util.Collections 是集合工具类
public class VectorList {
public static void main(String[] args) {
List vector = new Vector();
// 初始容量10
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
vector.add(6);
vector.add(7);
vector.add(8);
vector.add(9);
vector.add(10);
// 满了之后扩容(扩容之后是20)
vector.add(11);
Iterator iterator = vector.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
List myList = new ArrayList(); // 非线程安全的
// 将ArrayList集合转换成线程安全的
Collections.synchronizedList(myList);
myList.add("123");
}
}
Set接口
HsahSet集合
/*
HashSet集合存储元素特点:无序不可重复
*/
public class HashSetTest {
public static void main(String[] args) {
// 创建集合对象
Set<String> set = new HashSet<>();
// 添加元素
set.add("hello1");
set.add("hello3");
set.add("hello2");
set.add("hello1");
// 遍历
for (String s : set) {
System.out.println(s); // hello1 hello2 hello3
}
}
}
TreeSet集合
/*
TreeSet集合存储元素特点:
1.无序不可重复,但是存储的元素可以按照大小顺序排序(称为可排序集合)
2.无序:这里的无序指的是存进去的顺序和取出来的顺序不同,并且没有下标
*/
public class TreeSetTest {
public static void main(String[] args) {
// 创建集合对象
Set<String> set = new TreeSet<>();
// 添加元素
set.add("hello1");
set.add("hello3");
set.add("hello2");
set.add("hello1");
// 遍历
for (String s : set) {
System.out.println(s); // hello1 hello2 hello3
}
}
}
Collection和Collections
java.util.Collection
集合接口
java.util.Collections
集合工具类,方便集合的操作
public class CollectionsTest {
public static void main(String[] args) {
// ArrayList集合不是线程安全的
List<String> list = new ArrayList<>();
// 变成线程安全的
Collections.synchronizedList(list);
list.add("asd");
list.add("asf");
list.add("asc");
// 对元素进行排序
Collections.sort(list);
for (String s : list) {
System.out.println(s);
}
// 对Set集合排序
HashSet<String> set = new HashSet<>();
set.add("asd");
set.add("asf");
set.add("abc");
// 将Set集合转换成List集合
ArrayList<String> myList = new ArrayList<>(set);
Collections.sort(myList);
for (String s : myList) {
System.out.println(s);
}
}
}