Java集合(一)
一、集合概述与Collection (掌握)
1.1 数组的特点和弊端
* 一、Java的内存层面,对多个对象进行统一的管理和操作的容器有什么呢? 数组、集合
*
* 二、1. 数组在存储数据方面的特点:
* > 数组一旦初始化以后,其长度就是确定的。
* > 数组有索引,可以方便的对指定位置上的元素进行查找、替换
* > 数组存储的数据:有序的、使用连续的内存空间
* > 数组在定义时,就明确了存储的数据的类型。
* 比如:String[] arr,Object[]
* 2. 数组在存储数据方面的弊端:
* > 数组一旦初始化以后,其长度就不可改变--->如果需要扩容,必须新建数组
* > 数组在插入、删除等操作时,效率很差
* > 可以表达的多个对象的关系较为简单,不能描述更为丰富的对象关系
* > 数组中可以使用的方法非常少
1.2 集合框架结构
* |-----Collection:存储一个一个的数据
* |-----List:存储有序的、可以重复的数据 : 替换数组,"动态数组"
* |-----ArrayList/LinkedList/Vector
* |-----Set:存储无序的、不可重复的数据: 高中的集合
* |-----HashSet/LinkedHashSet/TreeSet
* |-----Map:存储一对一对的数据(key-value):高中的函数。 y = f(x) (x1,y1),(x2,y2)
* |-----HashMap/LinkedHashMap/TreeMap/Hashtable/Properties
1.3 本章要求
* 本章对大家的要求:
* 层次一:针对不同特点的数据,能够选择对应接口的主要的类进行实例化和方法的调用
* 层次二:熟悉接口的不同的实现类的区别、特点
* 层次三:相关接口实现类的底层实现:存储结构
1.4 Collection中的常用方法
@Test
public void test1(){
Collection c1 = new ArrayList();
//1. add(Object obj):添加元素obj到当前集合中
c1.add(123);//自动装箱
c1.add("AA");
c1.add(new Date(234234324L));
c1.add("BB");
System.out.println(c1);
//2.size():获取集合中元素的个数
System.out.println(c1.size());
//3.addAll(Collection coll):将coll集合中的元素添加到当前集合中。
Collection c2 = new ArrayList();
c2.add(345);
c2.add("CC");
c1.addAll(c2);
// c1.add(c2);
System.out.println(c1.size());
//5.clear():清空当前集合
c1.clear();
//4.isEmpty():判断当前集合是否为空。
System.out.println(c1.isEmpty());
System.out.println(c1);
}
@Test
public void test2(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(new Date(234234324L));
c1.add("BB");
//6.contains(Object obj):判断当前集合中是否包含obj元素
//具体的:需要调用obj对象所在类的equals(Object o)
System.out.println(c1.contains(new String("AA")));
System.out.println(c1.contains(new Person("Tom",12)));
//7.containsAll(Collection coll):判断当前集合中是否包含coll集合中的所有元素
Collection c2 = new ArrayList();
c2.add(1234);
c2.add(new String("BB"));
System.out.println(c1.containsAll(c2));
}
@Test
public void test3(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(123);//自动装箱
c1.add(new Date(234234324L));
c1.add("BB");
//8.remove(Object obj):删除当前集合中首次出现的obj元素
System.out.println(c1.remove(1234));
System.out.println(c1);
//9.removeAll(Collection coll):差集:从当前集合中移除其与coll集合共有的元素
Collection c2 = new ArrayList();
c2.add(1234);
c2.add(new String("BB"));
c1.removeAll(c2);
System.out.println(c1);
}
@Test
public void test4(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(new Date(234234324L));
c1.add("BB");
//10.retainAll(Collection coll):交集:获取当期集合与coll集合共有的元素
Collection c2 = new ArrayList();
c2.add(123);//自动装箱
c2.add(new Person("Tom",12));
c2.add(new String("AA"));
c2.add("BB");
c2.add(new Date(234234324L));
// c1.retainAll(c2);
// System.out.println(c1);
//11. equals(Object obj):判断当前集合与obj元素是否相等
//要想返回true,要求形参obj也是一个同类型的集合对象,同时集合元素都相同。(如果是List的话,要求顺序也相同)
System.out.println(c1.equals(c2));
//12.hashCode():返回当前集合对象的哈希值
System.out.println(c1.hashCode());
}
1.5 数组与集合的转换
@Test
public void test5(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(new Date(234234324L));
c1.add("BB");
//13.toArray():将集合转换为数组
Object[] arr = c1.toArray();
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
//如何将数组转换为集合?yes!
//使用Arrays的asList(T...t)
String[] arr1 = {"AA","CC","MM","GG"};
List list = Arrays.asList(arr1);
System.out.println(list);
List list1 = Arrays.asList("AA","CC","MM");
//笔试题:
Integer[] arr2 = new Integer[]{1,2,3};
int[] arr3 = new int[]{1,2,3};
List list2 = Arrays.asList(arr2);
List list3 = Arrays.asList(arr3);
List list4 = Arrays.asList(1,2,3);
System.out.println(list2.size());//3
System.out.println(list3.size());//1
System.out.println(list4.size());//3
System.out.println(list3);//[[I@4459eb14]
}
1.6 集合的遍历:使用Iterator接口
@Test
public void test1(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(new Date(234234324L));
c1.add("BB");
// System.out.println(c1);
//Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。
Iterator iterator = c1.iterator();
//方式一:
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// //报NoSuchElementException
// System.out.println(iterator.next());
//方式二:不推荐
// for(int i = 0;i < c1.size();i++){
// System.out.println(iterator.next());
// }
//方式三:推荐
//hasNext():判断集合的下个位置是否还有元素
while(iterator.hasNext()){
//next():① 指针下移 ② 将下移以后位置上的元素返回
Object obj = iterator.next();
System.out.println(obj);
}
}
对应的迭代器的执行原理:
错误的写法:
//错误的遍历方式
@Test
public void test2(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(new Date(234234324L));
c1.add("BB");
//错误方式一:
// Iterator iterator = c1.iterator();
// while(iterator.next() != null){
// System.out.println(iterator.next());
//
// }
//错误方式二:每次调用iterator()时,都会返回一个迭代器对象,指针从头开始
// while(c1.iterator().hasNext()){
// Object obj = c1.iterator().next();
// System.out.println(obj);
// }
}
1.7 增强for循环
- 用来遍历集合
@Test
public void test1(){
Collection c1 = new ArrayList();
c1.add(123);//自动装箱
c1.add(new Person("Tom",12));
c1.add(new String("AA"));
c1.add(new Date(234234324L));
c1.add("BB");
//格式:for(集合元素类型 变量名 : 待遍历的集合对象的引用)
for(Object obj : c1){
System.out.println(obj);
}
}
- 用来遍历数组
@Test
public void test2(){
int[] arr = {1,2,3,4,5};
for(int i : arr){
System.out.println(i);
}
}
- 面试题
//面试题
@Test
public void test3(){
int[] arr = {1,2,3,4,5};
//操作一:
// for(int i : arr){
// i = 6;
// System.out.println(i);
// }
//操作二:
for(int i = 0;i < arr.length;i++){
arr[i] = 6;
}
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
}
二、List接口
2.1 List中的常用方法
//List是Collection的子接口,Collection中声明的方法,在List的实现类中都可以使用。
//此外,由于List是有序的,所有额外添加了一些方法。
/*
* void add(int index, Object ele):在index位置插入ele元素
* boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
* Object get(int index):获取指定index位置的元素
* int indexOf(Object obj):返回obj在集合中首次出现的位置
* int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
* Object remove(int index):移除指定index位置的元素,并返回此元素
* Object set(int index, Object ele):设置指定index位置的元素为ele
* List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
*
*
* 总结:(必须掌握)
* 增:add(Object obj)
* 删:remove(Object obj)/remove(int index)
* 改:set(int index, Object ele)
* 查:get(int index)
* 插:add(int index, Object ele)
* 长度:size()
* 遍历:iterator() / 增强for
*/
@Test
public void test1(){
List list = new ArrayList();
list.add(123);//自动装箱
list.add(567);
list.add("AA");
// list.remove("AA");
// list.remove(new Integer(123));
// list.set(1, "BB");
list.add(1, "CC");
System.out.println(list);
// System.out.println(list.get(2));
System.out.println(list.size());
}
@Test
public void test2(){
List list = new ArrayList();
list.add(123);//自动装箱
list.add(567);
list.add("AA");
//方式一:使用迭代器
// Iterator iterator = list.iterator();
// while(iterator.hasNext()){
// System.out.println(iterator.next());
// }
//方式二:增强for
// for(Object obj : list){
// System.out.println(obj);
// }
//方式三:一般for循环
for(int i = 0;i < list.size();i++){
System.out.println(list.get(i));
}
}
@Test
public void test3(){
List list = new ArrayList();
list.add(123);//自动装箱
list.add(567);
list.add("AA");
List list1 = Arrays.asList(1,2,3);
list.addAll(1, list1);
System.out.println(list);
List list2 = list.subList(1,3);
System.out.println(list2);
}
2.2 不同的实现类
|-----Collection:存储一个一个的数据
|-----List:存储有序的、可以重复的数据 : 替换数组,"动态数组"
|-----ArrayList:List的主要实现类;线程不安全的,效率高;底层使用Object[]存储
|-----LinkedList:底层使用双向链表存储数据;对于频繁的插入、删除操作,使用此类效率高。
|-----Vector:List的古老实现类;线程安全的,效率低;底层使用Object[]存储
面试题:区分ArrayList、LinkedList、Vector
数据结构中的数据存储结构:
> 真实结构:① 顺序表(一维数组)
② 链表
> 抽象数据结构(ADT):栈、队列、树、图
@Test
public void test3(){
List list = new ArrayList();
list.add(123);//自动装箱
list.add(567);
list.add("AA");
List list1 = Arrays.asList(1,2,3);
list.addAll(1, list1);
System.out.println(list);
List list2 = list.subList(1,3);
System.out.println(list2);
}
三、练习题
练习1:
• 键盘录入学生信息,保存到集合中。
o 循环录入的方式,1:表示继续录入,0:表示结束录入。
o 定义学生类,属性为姓名,年龄,使用学生对象保存录入数据。
o 使用ArrayList集合,保存学生对象,录入结束后,用foreach遍历集合。
• 代码实现,效果如图所示:
public class StudentTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ArrayList stuList = new ArrayList();
for (;;) {
System.out.println("选择(录入 1 ;结束 0)");
int x = scanner.nextInt();//根据x的值,判断是否需要继续循环
if (x == 1) {
System.out.println("姓名");
String name = scanner.next();
System.out.println("年龄");
int age = scanner.nextInt();
Student stu = new Student(age, name);
stuList.add(stu);
} else if (x == 0) {
break;
} else {
System.out.println("输入有误,请重新输入");
}
}
for (Object stu : stuList) {
System.out.println(stu);
}
}
}
练习2:
• 随机生成30个数,范围2-100,获取其中的质数。
• 代码实现,效果如图所示:
写法一:
public class PrimeNumberPrintTest1 {
public static void main(String[] args) {
ArrayList numberList = new ArrayList();
int num = 0;
for (int i = 0; i < 30; i++) {
num = (int)(Math.random() * (100-2+1) ) + 2;
if(!numberList.contains(num)){
numberList.add(num);
}else{
i--;
}
}
System.out.println(numberList);
ArrayList primeList = new ArrayList();//用于存储所有的质数
int j;
boolean flag;
for (int i = 0; i < numberList.size(); i++) {
flag = false;
int number = (int) numberList.get(i);
for (j = 2; j <= Math.sqrt(number); j++) {
if (number % j == 0){
flag = true;
break;
}
}
if (!flag){
primeList.add(number);
}
}
System.out.println("当前随机数中的质数有:");
for(Object obj : primeList){
System.out.println(obj);
}
}
}
写法二:
public class PrimeNumberPrintTest2 {
public static void main(String[] args) {
List numberList = generateRandomNumber(30, 2, 100);
System.out.println(numberList);
List primeList = getPrimeNumber(numberList);
System.out.println("当前随机数中的质数有:");
System.out.println(primeList);
}
/**
* 获取30个随机数,范围为2-100
*
* @Description
* @author shkstart
* @date 2020年3月16日上午9:34:37
* @param size
* @param startNumber
* @param endNumber
* @return
*/
private static List generateRandomNumber(int size, int startNumber, int endNumber) {
ArrayList numberList = new ArrayList();
for (int i = 0; i < size; i++) {
int num = (int) (Math.random() * (endNumber - startNumber + 1)) + startNumber;
if (!numberList.contains(num)) {
numberList.add(num);
} else {
i--;
}
}
return numberList;
}
/**
* 获取指定List中所有数值中的质数
* @Description
* @author shkstart
* @date 2020年3月16日上午9:37:08
* @param numberList
* @return
*/
private static List getPrimeNumber(List numberList) {
ArrayList primeList = new ArrayList();// 用于存储所有的质数
for (int i = 0; i < numberList.size(); i++) {
boolean flag = false;
int number = (int) numberList.get(i);
for (int j = 2; j <= Math.sqrt(number); j++) {
if (number % j == 0) {
flag = true;
break;
}
}
if (!flag) {
primeList.add(number);
}
}
return primeList;
}
}
四、小结
-
字符串相关的类:String\StringBuffer\StringBuilder (重点)
-
比较器:Comparable \ Comparator (可以实现java中的对象比较大小、排序) (重点)
-
日期时间的API
- jdk 8之前的API:java.util.Date (子类:java.sql.Date) 、Calendar、SimpleSDateFormat(格式化、解析)
- jdk8中API:Instant、LocalDate\LocalTime\ LocalDateTime、DateTimeFormater
-
其他的常用类:BigInteger、BigDecimal
-
Collection\List\Set\Map存储数据的特点
-
Collection中的常用方法(掌握)
- 遍历时,使用迭代器(Iterator)
-
List
- List中的常用方法: 增、删、改、查、插、长度、遍历
- 三个实现类的对比—>面试题
- ArrayList、LinkedList的源码分析