1. 数组存储数据方面的特点和弊端
数组存储多个数据方面的特点:
> 数组一旦初始化,其长度就是确定的。
> 数组中的多个元素是依次紧密排列的,有序的,可重复的
> (优点) 数组一旦初始化完成,其元素的类型就是确定的。不是此类型的元素,就不能添加到此数组中。
int[] arr = new int[10];
arr[0] = 1;
arr[1] = "AA";//编译报错
Object[] arr1 = new Object[10];
arr1[0] = new String();
arr1[1] = new Date();
> (优点)元素的类型既可以是基本数据类型,也可以是引用数据类型。
数组存储多个数据方面的弊端:
> 数组一旦初始化,其长度就不可变了。
> 数组中存储数据特点的单一性。对于无序的、不可重复的场景的多个数据就无能为力了。
> 数组中可用的方法、属性都极少。具体的需求,都需要自己来组织相关的代码逻辑。
> 针对于数组中元素的删除、插入操作,性能较差。
2. 集合框架概述
java.util.Collection:存储一个一个的数据
(主要) |-----子接口:List:存储有序的、可重复的数据 ("动态"数组)
|---- ArrayList(主要实现类)、LinkedList、Vector
|-----子接口:Set:存储无序的、不可重复的数据(高中学习的集合)
|---- HashSet(主要实现类)、LinkedHashSet、TreeSet
java.util.Map:存储一对一对的数据(key-value键值对,(x1,y1)、(x2,y2) --> y=f(x),类似于高中的函数)
|---- HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties
学习的程度把握:
层次1:针对于具体特点的多个数据,知道选择相应的适合的接口的主要实现类,会实例化,会调用常用的方法。
层次2:区分接口中不同的实现类的区别。
层次3:① 针对于常用的实现类,需要熟悉底层的源码 ② 熟悉常见的数据结构(数据结构和集合源码中重点)
3. Collection的常用方法list和set的父接口
3.1 常用方法
add(Object obj)
addAll(Collection coll)
clear()
isEmpty()
size()
contains(Object obj)
containsAll(Collection coll)
retainAll(Collection coll)
remove(Object obj)
removeAll(Collection coll)
hashCode()
equals()
toArray()
**************
iterator() ---> 引出了迭代器接口
向Collection中添加元素的要求:
> 要求元素所属的类一定要重写equals()
集合与数组的相互转换:
集合 ---> 数组:toArray()
数组 ---> 集合:调用Arrays的静态方法asList(Object ... objs),返回一个List
3.2 迭代器接口
-
设计模式的一种
-
迭代器不负责数据的存储;负责对集合类的遍历
1. 如何获取迭代器(Iterator)对象?
Iterator iterator = coll.iterator();
2. 如何实现遍历(代码实现)
while(iterator.hasNext()){
System.out.println(iterator.next()); //next():①指针下移 ② 将下移以后集合位置上的元素返回
}
4. Collection的子接口:List
-
常用方法
重点
增
add(Object obj)
addAll(Collection coll)
删
remove(Object obj)
remove(int index)
改
set(int index, Object ele)
查
get(int index)
插
add(int index, Object ele)
addAll(int index, Collection eles)
长度
size()
遍历
iterator() :使用迭代器进行遍历
增强for循环
一般的for循环
List及其实现类特点
java.util.Collection:存储一个一个的数据
|-----子接口:List:存储有序的、可重复的数据 ("动态"数组)
|---- ArrayList:List的主要实现类;线程不安全的、效率高;底层使用Object[]数组存储
在添加数据、查找数据时,效率较高;在插入、删除数据时,效率较低
|---- LinkedList:底层使用双向链表的方式进行存储;在对集合中的数据进行频繁的删除、插入操作时,建议 使用此类在插入、删除数据时,效率较高;在添加数据、查找数据时,效率较低;
|---- Vector:List的古老实现类;线程安全的、效率低;底层使用Object[]数组存储
练习
案例:键盘录入学生信息,保存到集合List中。 (1) 定义学生类,属性为姓名、年龄,提供必要的getter、setter方法,构造器,toString(),equals()方法。 (2) 使用ArrayList集合,保存录入的多个学生对象。 (3) 循环录入的方式,1:继续录入,0:结束录入。 (4) 录入结束后,用foreach遍历集合。
public class student {
private String name;
private int age;
public student() {
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
student student = (student) o;
return getAge() == student.getAge() && Objects.equals(getName(), student.getName());
}
@Override
public String toString() {
return "student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class studenttest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ArrayList list = new ArrayList();///存放数据的容器
System.out.println("请录入学生信息");
student xs = null;
while (true) {
System.out.println("1.继续录入;0.结束录入");
int select = sc.nextInt();
if (select == 0) {
break;
}
System.out.println("请输入学生的姓名");
String name = sc.next();
System.out.println("请输入学生的年龄");
int age = sc.nextInt();
/**
* 向容器里增加数据
*/
xs = new student(name, age);
list.add(xs);///将参数添加进容器中
}
/// 遍历学生信息
System.out.println("遍历学生信息:");
/// 方式1.增强for循环
// for(Object xs:list){
student stu = (student) xs;
// System.out.println(stu.toString());///虚拟方法调用
// }
/// 方式2.iterator() :使用迭代器进行遍历
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
sc.close();
}
}
5. Collection的子接口:Set
-
Set中的常用的方法都是Collection中声明的方法,没有新增的方法
-
常见的实现类的对比
java.util.Collection:存储一个一个的数据
|-----子接口:Set:存储无序的、不可重复的数据(高中学习的集合)
|---- HashSet:主要实现类;底层使用的是HashMap,即使用数组+单向链表+红黑树结构进行存储。(jdk8中)
|---- LinkedHashSet:是HashSet的子类;在现有的数组+单向链表+红黑树结构的基础上,又添加了一组双向链表,用于记录添加元素的先后顺序。即:我们可以按照添加元素的顺序实现遍历。便于频繁的查询操作。
|---- TreeSet:底层使用红黑树存储。可以按照添加的元素的指定的属性的大小顺序进行遍历。
-
难点: Set中无序性、不可重复性的理解(以HashSet及其子类为例说明)
-
>无序性: != 随机性。
添加元素的顺序和遍历元素的顺序不一致,是不是就是无序性呢? No!
到底什么是无序性?与添加的元素的位置有关,不像ArrayList一样是依次紧密排列的。
这里是根据添加的元素的哈希值,计算的其在数组中的存储位置。此位置不是依次排列的,表现为无序性。>不可重复性:添加到Set中的元素是不能相同的。
比较的标准,需要判断hashCode()得到的哈希值以及equals()得到的boolean型的结果。
哈希值相同且equals()返回true,则认为元素是相同的。 -
添加到HashSet/LinkedHashSet中元素的要求:
>要求元素所在的类要重写两个方法:equals() 和 hashCode()。
>同时,要求equals() 和 hashCode()要保持一致性!我们只需要在IDEA中自动生成两个方法的重写即可,即能保证两个方法的一致性。
6. Map接口
-
常用的方法
增:
put(Object key,Object value)
putAll(Map m)
删:
Object remove(Object key)
改:
put(Object key,Object value)
putAll(Map m)
查:
Object get(Object key)
长度:
size()
遍历:
遍历key集:Set keySet()
遍历value集:Collection values()
遍历entry集:Set entrySet()
-
常用的实现类
-
java.util.Map:存储一对一对的数据(key-value键值对,(x1,y1)、(x2,y2) --> y=f(x),类似于高中的函数)
|---- HashMap:主要实现类;线程不安全的,效率高;可以添加null的key和value值;底层使用数组+单向链表+红黑树结构存储(jdk8)
|---- LinkedHashMap:是HashMap的子类;在HashMap使用的数据结构的基础上,增加了一对双向链表,用于记录添加的元素的先后顺序,进而我们在遍历元素时,就可以按照添加的顺序显示。开发中,对于频繁的遍历操作,建议使用此类。
|---- TreeMap:底层使用红黑树存储;可以按照添加的key-value中的key元素的指定的属性的大小顺序进行遍历。需要考虑使用①自然排序 ②定制排序。
|---- Hashtable:古老实现类;线程安全的,效率低;不可以添加null的key或value值;底层使用数组+单向链表结构存储(jdk8)
|---- Properties:其key和value都是String类型。常用来处理属性文件。 -
HashMap中元素的特点:
> HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key就构成一个Set集合。--->key所在的类要重写hashCode()和equals()
> HashMap中的所有的value彼此之间是可重复的、无序的。所有的value就构成一个Collection集合。--->value所在的类要重写equals()
> HashMap中的一个key-value,就构成了一个entry。
> HashMap中的所有的entry彼此之间是不可重复的、无序的。所有的entry就构成了一个Set集合。 -
Properties的使用(重点)
-
public class PropertiesTest { @Test public void test() throws IOException { //注意:因为设计到流的操作,为了确保流能关闭,建议使用try-catch-finally //方式1:数据和代码耦合度高;如果修改的话,需要重写的编译代码、打包发布,繁琐 //数据 // String name = "Tom"; // String password = "abc123"; //代码:用于操作name,password //get,set,构造器 //方式2:将数据封装到具体的配置文件中,在程序中读取配置文件中的信息。实现了 //数据和代码的解耦;由于我们没有修改代码,就省去了重新编译和打包的过程。 File file = new File("info.properties"); //注意,要提前创建好 // System.out.println(file.getAbsolutePath()); FileInputStream fis = new FileInputStream(file); Properties pros = new Properties(); pros.load(fis); //加载流中的文件中的数据 //读取数据 String name = pros.getProperty("name"); String pwd = pros.getProperty("password"); System.out.println(name + ":" + pwd); fis.close(); } }
7. Collections工具类的使用
- 区分Collection 和 Collections
Collection:集合框架中的用于存储一个一个元素的接口,又分为List和Set等子接口。
Collections:用于操作集合框架的一个工具类。此时的集合框架包括:Set、List、Map