集合Collection
1、数组与集合
/*
1.集合与数组存储数据概述:
集合、数组都是对多个数据进行存储操作的结构,简称ava容器
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)
2.数组存储的特点:
>一旦初始化以后,其长度就确定了。
〉数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。*
比如: String[]arr;int[]arr1;object[] arr2;
3.数组存储的弊端:
>一旦初始化以后,其长度就不可修改。
〉数组中提供的方法非常限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
〉获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
〉数组存储数据的特点:序、可重复。对于无序、不可重复的需求,不能满足。
4.集合存储的优点:
解决数组存储数据方面的弊端。
*/
2、Collection接口
1.collection集合框架结构
/*
1.单列集合框架结构
collection接口:单列集台用来存储一个一个的对象
----List接口:存储序的、可重复的数据。-->“动态”数组
----ArrayList、LinkedList、Vector
----Set接口:存储无序的、不可重复的数据——>高中讲的"集合”
----HashSet、 LinkedHashSet、 TreeSet
*/
2.collection接口常用方法:
1.常用方法一:
/*
常用方法一:
1.add() 增加
2.addAll() 增加所有
3.size() 大小
4.clear() 清理
5.isEmpty() 是否为空
*/
//collection接口常用方法一:
@Test
public void collect1(){
Collection collection=new ArrayList ();
//add() 增加
collection.add("AA");
collection.add (123);
collection.add ("BB");
//addAll() 增加所有
Collection collection1=new ArrayList ();
collection1.add (456);
collection.addAll (collection1);
//size() 大小
System.out.println (collection.size ()); //4
//clear() 清理
collection1.clear ();
//isEmpty() 是否为空
System.out.println (collection.isEmpty ()); // false
System.out.println (collection1.isEmpty ()); //true
}
2.常用方法二:
//collection接口常用方法二:
/*
1.contains(0bject obj):
判断当前集合中是否包含obj我们在判断时会调用obi对象所在类的equals().
2.containsAlL(collection coll):
判断形参coll1中的所有元素是否都存在于当前集合中e
*/
@Test
public void collect2(){
Collection collect=new ArrayList ();
collect.add(123);
collect.add("FF");
collect.add(new Date ());
//1.contains(0bject obj):
// 判断当前集合中是否包含obj我们在判断时会调用obi对象所在类的equals().
System.out.println (collect.contains (123));//true
//2.containsAlL(collection coll):
// 判断形参coll1中的所有元素是否都存在于当前集合中e
Collection collect2=new ArrayList ();
collect2.add("FF");
System.out.println (collect.containsAll (collect2));//true
}
3.常用方法三:
//collection接口常用方法三:
/*
1.remove(Object o) 删除
2.removeAll(Collection collection) 两个集合的差集
3.retainAll(Collection collection) 两个集合的交集
4.equals(Object o) 判断是否相等,存在有序
*/
@Test
public void test3(){
Collection collection=new ArrayList ();
collection.add("AA");
collection.add (123);
collection.add ("BB");
collection.add(456);
//remove(Object o) 删除
collection.remove (123);
System.out.println (collection);
//removeAll(Collection collection) 两个集合的差集
Collection collect1= Arrays.asList ("AA",456);
collection.removeAll (collect1);
System.out.println (collection);
}
@Test
public void test44(){
Collection collection=new ArrayList ();
collection.add("AA");
collection.add (123);
collection.add ("BB");
collection.add(456);
Collection collect1= Arrays.asList ("AA",456);
//retainAll(Collection collection) 两个集合的交集
collection.retainAll (collect1);
System.out.println (collection);
//equals(Object o) 判断是否相等,存在有序
System.out.println (collection.equals (collect1));
}
4.常用方法四:
//collection接口常用方法四:
/*
1.hashCode() 返回当前对象的哈希值
2.toArray() 集合——>数组
3.Arrays.asList() 数组——>集合
*/
@Test
public void test4(){
Collection collection=new ArrayList ();
collection.add("AA");
collection.add (123);
collection.add ("BB");
collection.add(456);
//hashCode() 返回当前对象的哈希值
System.out.println (collection.hashCode ());
//toArray() 集合——>数组
Object[] objects = collection.toArray ();
for(int i=0;i<objects.length;i++){
System.out.println (objects[i]);
}
//Arrays.asList() 数组——>集合
List<String> strings = Arrays.asList (new String []{"YY", "FF"});
System.out.println (strings);
//注意:
// List<int[]> list = Arrays.asList (new int[]{123, 111});// 输出为[[I@5891e32e]
// System.out.println (list.size ());//此时默认长度为1
List<Integer> list1 = Arrays.asList (new Integer[]{123, 234});//输出为[123, 234]
System.out.println (list1);
System.out.println (list1.size ());//此时默认长度为2
}
3、Iterator接口遍历集合元素
/*
集合元素的遍历操作:迭代器Iterator接口
1.内部的方法:
hasNext()
next()
2.集合对象每次调用iterator()方法都得到一个全新的迭代器对象,
默认游标都在集合的第一个元素之前。
3.内部定义了remove(),可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove()
*/
@Test
public void test(){
Collection collection=new ArrayList ();
collection.add("AA");
collection.add (123);
collection.add ("BB");
collection.add(456);
java.util.Iterator iterator = collection.iterator ();
//遍历此集合中的所有元素————>三选一,不能同时运行
//next () 遍历集合中的元素
//方式一:若要遍历集合中的所有的,则需要重复操作 不推荐
System.out.println (iterator.next ());//AA
System.out.println (iterator.next ());//123
System.out.println (iterator.next ());//BB
System.out.println (iterator.next ());//456
System.out.println ("************");
//方式二: for循环+iterator.next () 不推荐
for(int i=0;i<collection.size ();i++){
System.out.println (iterator.next ());
}
System.out.println ("************");
//方式三:iterator.hasNext ()+iterator.next () 推荐
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
//错误写法一:类似于指针,不能用非空判断 NoSuchElementException
// while(iterator.next ()!=null){
// System.out.println (iterator.next ());
// }
//
// //错误写法二:重复输出集合中的第一个元素
// // 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,
默认游标都在集合的第一个元素之前。
// while(collection.iterator ().hasNext ()){
// System.out.println (collection.iterator ().next ());
// }
}
@Test
public void test5(){
Collection collection=new ArrayList ();
collection.add("AA");
collection.add (123);
collection.add ("BB");
collection.add(456);
java.util.Iterator iterator = collection.iterator ();
while(iterator.hasNext ()){
Object obj = iterator.next ();
if("BB".equals (obj)){
/*
remove()移除
如果还未调用next()或在上一次调用next方法之后已经调用了remove方法,
再调用remove都会报ILegalStateException。
*/
iterator.remove ();
}
}
java.util.Iterator iterator1 = collection.iterator ();
while(iterator1.hasNext ()){
System.out.println (iterator1.next ());
}
}
4、forEach循环遍历
@Test
public void test6(){
Collection collection=new ArrayList ();
collection.add("AA");
collection.add (123);
collection.add ("BB");
collection.add(456);
// for (集合类型 参数名 :集合名 )
for (Object o:collection
) {
System.out.println (o);
}
System.out.println ("**************");
//数组的循环遍历
// for (数组类型 参数名 :数组名 )
String[] arr=new String[]{"YY","FF"};
for (String s: arr
) {
System.out.println (s);
}
System.out.println ("************");
//测试题:
// forEach循环的遍历跟for循环遍历
String[] strings=new String[]{"FF","FF"};
for (String s: strings
) {
s="YY";
}
for (String s: strings
) {
//forEach循环的遍历,不改变其原本的元素,因为 s="YY";这里的s只是参数名
System.out.println (s);
}
System.out.println ("_______________");
String[] string=new String[]{"FF","FF"};
for(int i=0;i<string.length;i++){
string[i]="YY";
}
for (String s: string
) {
//for循环的遍历,改变其原本的元素,因为 string[i]="YY";
System.out.println (s);
}
}
5、Collection子接口
1. List接口
1. list框架
/*
List接口框架
collection接口:单列集合,用来存储一个一个的对象
----List接口:存储有序的、可重复的数据。
“动态数组,替换原有的数组
----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;
底层使用Object[] elementData存储
----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;
底层使用双向链表存储
----Vector:作为List接口的古老实现类;线程安全的,效率低;
底层使用Object[] elementData存储
面试题:ArrayList、 LinkedList、Vector三者的异同?
同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
不同:见上
*/
2.ArrayList的源码分析:
/*
ArrayList的源码分析:
1. 在jdk 7情况下
ArrayList list = new ArrayList();//底层创建了长度是10的object[]数组elementDataList.add(123);//eLementData[e] = new Integer(123);
...
list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
2. 在jdk 8情况下
ArrayList list = new ArrayList();//底层object[] elementData初始化为{}.并没有创建
list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到eleme...
后续的添加和扩容操作与jdk 7无异。
3小结: jdk7中的ArrayList的对象的创建类似于单例的饿汉式,
而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,
延迟了数组的创建,节省内存。
*/
3.LinkedList的源码分析:
/*
3.LinkedList的源码分析:
LinkedList list = new LinkedList();内部声明了Node类型的first和Last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象
其中,Node定义为:体现了LinkedList的双向链表的说法
*/
4. Vector的源码分析:
/*
Vector的源码分析:
jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组
在扩容方面,默认扩容为原来的数组长度的2倍。
*/
5. 常用方法:
/*
list常用方法
void add(int index, object ele):在index位置插入eLe元素
boolean addALll(int index, Collection eLes):从index位置开始将eLes中的所有元素添加进来object get(int index):获取指定index位置的元素
int indexOf(object obj):返回obj在集合中首次出现的位置
int lastIndex0f(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(int index) / remove(object obj)
改: set(int index,object ele)
查: get(int index)
插: add(int index,object ele)长度: size()
遍历: ①Iterator迭代器方式
②增强for循环
③普通的循环
*/
/*
注意:
区分List中remove(int index)和remove(Object obj)
*/
@Test
public void test(){
ArrayList list =new ArrayList ();
list.add(123);
list.add(456);
list.add("BB");
list.add(456);
System.out.println (list);
System.out.println ("***********");
// void add(int index, object ele):在index位置插入eLe元素
list.add(1,"AA");
System.out.println (list);
System.out.println ("***********");
// boolean addAll(int index, Collection eLes):从index位置开始将eLes中的所有元素添加进来object get(int index):获取指定index位置的元素
java.util.List<String> asList = Arrays.asList ("YY", "XX");
list.addAll (asList);
System.out.println (list);
System.out.println ("***********");
// int indexOf(object obj):返回obj在集合中首次出现的位置
int i = list.indexOf (456);
System.out.println (i);
System.out.println ("***********");
// int lastIndex0f(Object obj):返回obj在当前集合中末次出现的位置
int i1 = list.lastIndexOf (456);
System.out.println (i1);
System.out.println ("************");
// object remove(int index):移除指定index位置的元素,并返回此元素
System.out.println (list);
list.remove ("BB");
System.out.println (list);
System.out.println ("****************");
// object set(int index, object ele):设置指定index位置的元素为else
System.out.println (list);
list.set (0, "FF");
System.out.println (list);
System.out.println ("*****************");
// list sublist(int fromIndex, int toIndex):返回从fromIndex到toIndex左闭右开位置的子集合
System.out.println (list);
java.util.List list1 = list.subList (1,3);
System.out.println (list1);
System.out.println ("*****************");
}
6.面试总结:
/*
1.集合Collection中存储的如果是自定义类的对象,需要自定义类重写哪个方法?为什么?
——equals()方法
Set:(HashSet、LinkedHashSet为例): equals()、hashCode()
(TreeSet为例): Comparable: compareTo(Object obj)
Comparator: compare(Object o1,Object o2)
2.面试题:ArrayList、 LinkedList、Vector三者的异同?
同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
不同:见下
collection接口:单列集合,用来存储一个一个的对象
----List接口:存储有序的、可重复的数据。
“动态数组,替换原有的数组
----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;
底层使用Object[] elementData存储
----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;
底层使用双向链表存储
----Vector:作为List接口的古老实现类;线程安全的,效率低;
底层使用Object[] elementData存储
*/
2. Set接口(不常用)
1. set接口的框架:
/*
set接口的框架:
Collection接口:单列集合,用来存储一个一个的对象
——Set接口:存储无序的、不可重复的据-->高中讲的“集合”
----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的上顺序遍历,时于频繁的遍历操作,LinkedHashSet效率高于HashSet
----TreeSet:可以按照添加对象的指定属性,进行排序。
注意: Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。
1.Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。
2.要求:向Set中添加的数据,其所在的类一定要重写hashcode()和equals()
要求:重写的hashcode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
*/
2. set:存储无序的、不可重复的数据
/*
set:存储无序的、不可重复的数据
以HashSet为例说明:
1.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值
2.不可重复性:保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一个。
*/
3. 添加元素的过程:以HashSet为例:
/*添加元素的过程:以HashSet为例:
我们向HashSet中添加元素a,首先调用元素a所在类的hashcode()方法,计算元素a的哈希值,
此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:
——如果此位置上没有其他元素,则元素α添加成功。--->情况1
——如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
——如果hash值不相同,则元素a添加成功。--->情况2
——如果hash 值相同,进而需要调用元素α所在类的equLas()方法:
——equals( )返回true,元素α添加失败
——equals()返回faLse,则元素a添加成功。--->情况3
对于添加成功的情况2和情况3而言:元素α与已经存在指定索引位置上数据以链表的方式存储。
jdk 7 ∶元素α放到数组中,指向原来的元素。
jdk 8 ∶原来的元素在数组中,指向元素a
总结:七上八下
HashSet底层:数组+链表的结构。
*/
4. LinkedHashSet的使用
/*
LinkedHashSet的使用
LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据的前一个数据和后一个数据。
优点:时于频繁的遍历操作,LinkedHashSet效率高于HashSet
*/
***5. TreeSet的排序
/*
TreeSet的使用
1.向TreeSet中添加的数据,要求是相同类的对象。
2.两种排序方式: 自然排序(实现Comparable接口) 和 定制排序(Comparator)
3.自然排序中,比较两个对象是否相同的标准为: compareTo()返回,不再是equals().
4.定制排序中,比较两个对象是否相同的标准为: compare()返回e.不再是equals().
*/
package production.collection.day01;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class Set {
//自然排序
@Test
public void test(){
TreeSet treeSet = new TreeSet ();
treeSet.add(new User ("Mike",15));
treeSet.add(new User ("Mike",35));
treeSet.add(new User ("Amy",5));
treeSet.add(new User ("Jerry",34));
treeSet.add(new User ("Joy",34));
treeSet.add(new User ("Bob",4));
//循环遍历
Iterator iterator = treeSet.iterator ();
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
}
//定制排序
@Test
public void test2(){
Comparator com =new Comparator () {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1=(User)o1;
User u2=(User)o2;
return Integer.compare (u1.getAge (),u2.getAge ());
}else{
throw new RuntimeException ("输入的数据类型错误!");
}
}
};
TreeSet treeSet = new TreeSet (com);
treeSet.add(new User ("Mike",15));
treeSet.add(new User ("Mike",35));
treeSet.add(new User ("Amy",5));
treeSet.add(new User ("Jerry",34));
treeSet.add(new User ("Joy",34));
treeSet.add(new User ("Bob",4));
//循环遍历
Iterator iterator = treeSet.iterator ();
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
}
}
package production.collection.day01;
import java.util.Objects;
public class User implements Comparable{
private String name;
private int age;
public User() {
}
public User(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 String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return getAge () == user.getAge () && Objects.equals (getName (), user.getName ());
}
@Override
public int hashCode() {
return Objects.hash (getName (), getAge ());
}
//重写比较方法
@Override
public int compareTo(Object o) {
if(o instanceof User){
User u=(User)o;
//判断名字是否相等
int i = this.name.compareTo (u.name);
if(i!=0){
return i;
}else{
//如果姓名相同,则对年龄进行从小到大的排序
//错误写法:System.out.println (this.age.compareTo (u.age));
return Integer.compare (this.age,u.age);
}
}else{
throw new RuntimeException ("输入的数据类型错误!");
}
}
}
6.课后题
/*
1.定义一个Employee类。
该类包含: private成员变量name,age,birthday,其中 birthday为MyDate 类的对象;,
并为每一个属性定义 getter, setter方法;v并重写 toString方法输出name, age, birthday
MyDate类包含:
private成员变量 year,month,day;
并为每一个属性定义getter,setter方法;
创建该类的5个对象,并把这些对象放入TreeSet集合中(下一章:TreeSet需使用泛型来定义)。
分别按以下两种方式对集合中的元素进行排序,并遍历输出:
1).使Employee实现 Comparable接口,并按name 排序
2).创建 TreeSet时传入Comparator对象,按生日日期的先后排序。
*/
package Test;
/*
MyDate类包含:
private成员变量 year,month,day;
并为每一个属性定义getter,setter方法;
*/
public class MyDate {
private int year;
private int month;
private int day;
public MyDate() {
}
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return "MyDate{" + "year=" + year + ", month=" + month + ", day=" + day + '}';
}
}
package Test;
import java.util.Comparator;
/*
定义一个Employee类。
该类包含: private成员变量name,age,birthday,
其中 birthday为MyDate 类的对象;,
并为每一个属性定义 getter, setter方法;
并重写 toString方法输出name, age, birthday
*/
public class Employee implements Comparable {
private String name;
private int age;
private MyDate birthday;
public Employee() {
}
public Employee(String name, int age, MyDate birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
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;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}';
}
@Override
public int compareTo(Object o) {
//1).使Employee实现 Comparable接口,并按name 排序
if(o instanceof Employee){
Employee e=(Employee)o;
return this.name.compareTo (e.name);
}else{
throw new RuntimeException ("输入的数据类型有错误!");
}
}
}
package Test;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
/*
创建该类的5个对象,并把这些对象放入TreeSet集合中
分别按以下两种方式对集合中的元素进行排序,并遍历输出:
1).使Employee实现 Comparable接口,并按name 排序
2).创建 TreeSet时传入Comparator对象,按生日日期的先后排序。
*/
public class TreeSet {
//1).使Employee实现 Comparable接口,并按name 排序
@Test
public void test(){
java.util.TreeSet set=new java.util.TreeSet ();
Employee e1=new Employee ("lihua",40,new MyDate (1980,1,1));
Employee e2=new Employee ("xiaoming",20,new MyDate (2000,12,1));
Employee e3=new Employee ("lisi",21,new MyDate (1999,4,1));
Employee e4=new Employee ("zhangsan",40,new MyDate (1980,1,13));
Employee e5=new Employee ("wangmazi",20,new MyDate (2000,11,1));
set.add (e1);
set.add (e2);
set.add (e3);
set.add (e4);
set.add (e5);
Iterator iterator = set.iterator ();
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
}
//2).创建 TreeSet时传入Comparator对象,按生日日期的先后排序。
@Test
public void test2(){
java.util.TreeSet set=new java.util.TreeSet (new Comparator () {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Employee && o2 instanceof Employee) {
Employee e1 = (Employee) o1;
Employee e2 = (Employee) o2;
//写法一、
if (e1.getBirthday ().getYear () != e2.getBirthday ().getYear ()) {
return Integer.compare (e1.getBirthday ().getYear (), e2.getBirthday ().getYear ());
} else if (e1.getBirthday ().getMonth () != e1.getBirthday ().getMonth ()) {
return Integer.compare (e1.getBirthday ().getMonth (), e2.getBirthday ().getMonth ());
} else if (e1.getBirthday ().getDay () != e2.getBirthday ().getDay ()) {
return Integer.compare (e1.getBirthday ().getDay (), e2.getBirthday ().getDay ());
}
//
//写法二:
// MyDate myDate1 = e1.getBirthday ();
// MyDate myDate2 = e2.getBirthday ();
// int year = myDate1.getYear () - myDate2.getYear ();
// int month = myDate1.getMonth () - myDate2.getMonth ();
// int day = myDate1.getDay () - myDate2.getDay ();
// if(year!=0){
// return year;
// }else if(month!=0){
// return month;
// }else if(day!=0){
// return day;
// }
}
return 0;
}
});
Employee e1=new Employee ("lihua",40,new MyDate (1980,1,1));
Employee e2=new Employee ("xiaoming",20,new MyDate (2000,12,1));
Employee e3=new Employee ("lisi",21,new MyDate (1999,4,1));
Employee e4=new Employee ("zhangsan",40,new MyDate (1980,1,13));
Employee e5=new Employee ("wangmazi",20,new MyDate (2000,11,1));
set.add (e1);
set.add (e2);
set.add (e3);
set.add (e4);
set.add (e5);
Iterator iterator = set.iterator ();
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
}
}
6、Map接口
1.Map实现类的结构
/*
一、Map实现类的结构:
/----Map:双列数据,存储key-value对的数据---类似于高中的函数: y =f(x)
/----HashMap:作为Nap的主要实现类;线程不安全的,效率高;存储nuLl的key和vaLue
/----LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。
原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。
对于频繁的遍历操作,此类执行效率高于HashMap 。
/----TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序
底层使用红黑树
/----Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value
/ ----Properties:常用来处理配置文件。key和value都是String类型
HashMap的底层:数组+链表(jdk7及之前)
数组+链表+红黑树(jdk 8)
*/
2.Map结构的理解
/*
二、Map结构的理解:
Map中的key:无序的、不可重复的,使用Set存储所有的key————> key所在的类要重写equals()和hashcode() (以HashMap为例)
Map中的value:无序的、可重复的,使用collection存储---——>value所在的类要重写equals()
所有的value一个键值对: key-value构成了一个entry对象。
Map中的entry:无序的、不可重复的,使用Set存储所有的entry
*/
***3.HashMap的底层实现原理:jdk7为例
/*
三、HashMap的底层实现原理?jdk7为例说明:
HashMap map = new HashMap(): //在实例化以后,底层创建了长度是16的一维数组Entry[]table.
...可能已经执行过多次put. . .
map.put(key1, value1);
首先,调用key1所在类的nashCode()计算xey1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
如果此位置上的数据为空,此时的key1-value1添加成功。----情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以键表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2
如果key1的哈希值和已经存在的某一个数据( key2-vaLue2)的哈希值相同,继续比较:调用key1所在类的equals(key2)
如果equals()返回faLse:此时key1-vaLue1添加成功。----情况3
如果equals()返回true:使用value1替换vaLue2 。
补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
扩容:在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。
默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。
*/
***4.HashMap的底层实现原理中jdk8对比jdk7
/*
四、HashMap的底层实现原理中jdk8相较于jdk7在底层实现方面的不同:
1. new HashMap():底层没有创建一个长度为16的数组2. jdk8底层的数组是:Node[],而非Entry[]
3.首次调用put()方法时,底层创建长度为16的数组
4. jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度>64时,
此时此索引位置上的所有数据改为使用红黑树存储。I
DEFAULT_INITIAL_ CAPACITY : HashMap的默认容量,16
DEFAULT_LOAD_FACTOR: HashMap的默认加载因子:0.75
threshold:扩容的临界值,=容量*填充因子:16 * 0.75 =>12
TREEIFY_ THRESHOLD: Bucket中链表长度大于该默认值,转化为红黑树:8
MIN_ TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
*/
5.LinkedHashMap的底层实现原理(了解)
/*
五、LinkedHashMap的底层实现原理(了解)
源码中:
static class Entry<K,V>extends HashMap.Node<K,V> {
Entry<K,V> before,after;//能够记录添加的元素的先后顺序
Entry (int hash,K key, v value,Node<K,V> next) {
super( hash,key, value, next);
}
}
*/
6.Map中定义的方法
1.添加、删除、修改操作:
/*
添加、删除、修改操作:
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
void putALL(Map m):将m中的所有key-value对存放到当前map 中
Object remove(Object key):移除指定key 的key-value对,并返回value
void clear :清空当前map 中的所有数据
*/
@Test
public void test1(){
// 添加、删除、修改操作:
HashMap map=new HashMap ();
// Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
//添加
map.put ("AA",123);
map.put ("BB",456);
map.put ("CC",789);
//修改
map.put ("BB",999);
System.out.println (map);
// Object remove(Object key):移除指定key 的key-value对,并返回value
Object aa = map.remove ("AA");
System.out.println (aa);
System.out.println (map);
// void putALL(Map m):将m中的所有key-value对存放到当前map 中
HashMap map1=new HashMap ();
map1.put ("DD",789);
map.putAll (map1);
System.out.println (map);
// void clear :清空当前map 中的所有数据
map.clear ();
System.out.println (map);
}
2.元素查询的操作:
/*
元素查询的操作:
object get(Object key):获取指定key对应的value
booLean containsKey(object key):是否包含指定的key
boolean containsValue(Object value):是否包含指定的value
int size():返回map 中key-value对的个数
booLean isEmpty():判断当前map是否为空
boolean equals(Object obj):判断当前map和参数对象obj是否相等
*/
@Test
public void test2(){
// 元素查询的操作:
HashMap map=new HashMap ();
map.put ("AA",123);
map.put ("BB",456);
map.put ("CC",789);
// object get(Object key):获取指定key对应的value
Object aa = map.get ("AA");
System.out.println (aa);
// booLean containsKey(object key):是否包含指定的key
boolean bb = map.containsKey ("BB");
System.out.println (bb);
// boolean containsValue(Object value):是否包含指定的value
boolean b = map.containsValue (123);
System.out.println (b);
// int size():返回map 中key-value对的个数
int size = map.size ();
System.out.println (size);
// booLean isEmpty():判断当前map是否为空
boolean empty = map.isEmpty ();
System.out.println (empty);
// boolean equals(Object obj):判断当前map和参数对象obj是否相等
}
3.元视图操作的方法:
/*
元视图操作的方法:
set keySet():返回所有key构成的set集合
collection values():返回所有vaLue构成的Collection集合
set entrySet():返回所有key-vaLue对构成的Set集合
*/
@Test
public void test3(){
// 元视图操作的方法:
HashMap map=new HashMap ();
map.put ("AA",123);
map.put ("BB",456);
map.put ("CC",789);
// set keySet():返回所有key构成的set集合
Set set = map.keySet ();
Iterator iterator = set.iterator ();
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
System.out.println ("************");
// collection values():返回所有vaLue构成的Collection集合
Collection collection = map.values ();
for (Object o:collection
) {
System.out.println (o);
}
System.out.println ("***************");
// set entrySet():返回所有key-vaLue对构成的Set集合
Set entrySet = map.entrySet ();
Iterator iterator1 = entrySet.iterator ();
while (iterator1.hasNext ()){
Object o = iterator1.next ();
//entrySet集合中的所有元素都是entry类型
java.util.Map.Entry entry=(java.util.Map.Entry)o;
System.out.println (entry.getKey ()+"="+entry.getValue ());
}
}
4.总结:常用方法+面试题
/*
总结:常用方法:
添加: put (Object key , object value)
删除:remove(Object key)
修改:put (Object key , object value)
查询: get(object key)
长度: size()
遍历:keySet() / values() / entrySet(
*/
/*
面试题:
1. HashMap的底层实现原理?
2. HashMap和Hashtable的异同?
3. CurrentHashMap与Hashtable的异同?(暂时不讲)
*/
7.TreeMap两种添加方式的使用
//TreeMap两种添加方式的使用
//向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
// 因为要按照key进行排序:自然排序、定制排序
//自然排序
@Test
public void test1() {
TreeMap map = new TreeMap ();
User u1 = new User ("Amy", 11);
User u2 = new User ("Jerry", 15);
User u3 = new User ("Tom", 13);
map.put (u1, 99);
map.put (u2, 69);
map.put (u3, 89);
// set entrySet():返回所有key-vaLue对构成的Set集合
Set entrySet = map.entrySet ();
Iterator iterator1 = entrySet.iterator ();
while (iterator1.hasNext ()) {
Object o = iterator1.next ();
//entrySet集合中的所有元素都是entry类型
java.util.Map.Entry entry = (java.util.Map.Entry) o;
System.out.println (entry.getKey () + "=" + entry.getValue ());
}
}
//定制排序
@Test
public void test2() {
TreeMap map = new TreeMap (new Comparator () {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1=(User)o1;
User u2=(User)o2;
return Integer.compare (u1.getAge (),u2.getAge ());
}else{
throw new RuntimeException ("输入的数据类型错误!");
}
}
});
User u1 = new User ("Amy", 11);
User u2 = new User ("Jerry", 15);
User u3 = new User ("Tom", 13);
map.put (u1, 99);
map.put (u2, 69);
map.put (u3, 89);
// set entrySet():返回所有key-vaLue对构成的Set集合
Set entrySet = map.entrySet ();
Iterator iterator1 = entrySet.iterator ();
while (iterator1.hasNext ()) {
Object o = iterator1.next ();
//entrySet集合中的所有元素都是entry类型
java.util.Map.Entry entry = (java.util.Map.Entry) o;
System.out.println (entry.getKey () + "=" + entry.getValue ());
}
}
package production.collection.day01;
import java.util.Objects;
public class User implements Comparable{
private String name;
private int age;
public User() {
}
public User(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 String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return getAge () == user.getAge () && Objects.equals (getName (), user.getName ());
}
@Override
public int hashCode() {
return Objects.hash (getName (), getAge ());
}
//重写比较方法
@Override
public int compareTo(Object o) {
if(o instanceof User){
User u=(User)o;
//判断名字是否相等
int i = this.name.compareTo (u.name);
if(i!=0){
return i;
}else{
//如果姓名相同,则对年龄进行从小到大的排序
//错误写法:System.out.println (this.age.compareTo (u.age));
return Integer.compare (this.age,u.age);
}
}else{
throw new RuntimeException ("输入的数据类型错误!");
}
}
}
8.Properties处理属性文件
详细看JDBC总结
7、Collections工具类的使用
1.常用方法:
/*
collections: 操作Collection、Map的工具类
面试题:Collection和collections的区别?
常用方法:
——reverse(List):反转List中元素的顺序
shuffle(List):对 List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定List集合元素按升序排序
sort(List,Comparator):根据指定的Comparator产生的顺序对List 集合元素进行排序
swap(List, int,int):将指定list集合中的i处元素和j处元素进行交换
object max(collection):根据元素的自然顺序,返回给定集合中的最大元素
object max(collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大object min(collection)
object min(collection,comparator)
int frequency(Collection,object):返回指定集合中指定元素的出现次数
——void copy(List dest,List src):将src中的内容复制到dest中
boolean replaceAll(List list,object oldVal,object newVal):使用新值替换List对象里的值
——collections类中提供了多个synchronizedXxx()方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
*/
@Test
public void test(){
// void copy(List dest,List src):将src中的内容复制到dest中
List list = new ArrayList ();
list.add (123);
list.add(11);
list.add (99);
//错误写法:IndexOutOfBoundsException: Source does not fit in dest
// List dest =new ArrayList ();
// Collections.copy (dest,list);
//正确写法:
List<Object> dest = Arrays.asList (new Object[list.size ()]);
Collections.copy (dest,list);
System.out.println (dest);
}
@Test
public void test2(){
// collections类中提供了多个synchronizedXxx()方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
List list = new ArrayList ();
list.add (123);
list.add(11);
list.add (99);
List list1 = Collections.synchronizedList (list);
System.out.println (list1);//此时的list1是线程安全的
}
2.练习题:
//1.请从键盘随机输入10个整数保存到List中,并按倒序、从大到小的顺序显示出来
//⒉请把学生名与考试分数录入到集合中,并按分数显示前三名成绩学员的名字。
/*3、姓氏统计:一个文本文件中存储着北京所有高校在校生的姓名,格式每行一个名字,姓与名以空格分隔:
张 三
李 四
王 小五
现在想统计所有的姓氏在文件中出现的次数,请描述一下你的解决方案。
*/
练习1:
//1.请从键盘随机输入10个整数保存到List中,并按倒序、从大到小的顺序显示出来
@org.junit.Test
public void test1(){
ArrayList<Object> list = new ArrayList<> ();
for(int i=0;i<10;i++){
//获取a到b之间的随机数
//(int) (Math.random ()*(b-a+1)+a)
//获取一个[0,100]的随机数
int random = (int) (Math.random ()*(100)+1);
list.add(random);
}
System.out.println (list);
System.out.println ("*******************");
//Collections工具类中reverse(List):反转List中元素的顺序
Collections.reverse (list);
System.out.println (list);
System.out.println ("*******************");
//从大到小的顺序显示出来
//Collections工具类中sort(List,Comparator):根据指定的Comparator产生的顺序对List 集合元素进行排序
Collections.sort (list, new Comparator<Object> () {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Object && o2 instanceof Object){
Object x=(Object)o1;
Object y=(Object)o2;
Integer i=(Integer)x;
Integer j=(Integer)y;
return Integer.compare (i,j);
}
throw new RuntimeException ("数据类型有错误");
}
});
System.out.println (list);
}
练习2:
//⒉请把学生名与考试分数录入到集合中,并按分数显示前三名成绩学员的名字。
//方法一:
@org.junit.Test
public void test2(){
//注意这里,HashSet无序,不可排序。TreeSet可以自定义排序
Set set=new TreeSet ();
// List set=new LinkedList ();
Students s1=new Students ("zhangsan",60);
Students s2=new Students ("lisi",70);
Students s3=new Students ("wangmazi",30);
Students s4=new Students ("xiaoming",35);
Students s5=new Students ("xiaohong",80);
set.add (s1);
set.add (s2);
set.add (s3);
set.add (s4);
set.add (s5);
// System.out.println (set);
Iterator iterator = set.iterator ();
while(iterator.hasNext ()){
System.out.println (iterator.next ());
}
System.out.println ("*******************");
Iterator iterator2 = set.iterator ();
for (int i = 0; i <3 ; i++) {
System.out.println (iterator2.next ());
}
}
//方法二:
@org.junit.Test
public void test22(){
//注意这里,HashSet无序,不可排序。TreeSet可以自定义排序
List list=new LinkedList ();
Students s1=new Students ("zhangsan",60);
Students s2=new Students ("lisi",70);
Students s3=new Students ("wangmazi",30);
Students s4=new Students ("xiaoming",35);
Students s5=new Students ("xiaohong",80);
list.add (s1);
list.add (s2);
list.add (s3);
list.add (s4);
list.add (s5);
Collections.sort (list);
System.out.println (list);
System.out.println ("*******************");
//若用list sublist(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
List list1 = list.subList (0,3);
System.out.println (list1);
}
package day01;
public class Students implements Comparable{
private String name;
private int grade;
public Students() {
}
public Students(String name, int grade) {
this.name = name;
this.grade = grade;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Students{" + "name='" + name + '\'' + ", grade=" + grade + '}';
}
@Override
public int compareTo(Object o) {
if(o instanceof Students){
Students s=(Students)o;
return Integer.compare (this.grade,s.grade);
}
throw new RuntimeException ("数据类型有错误");
}
}
练习3:
/*3、姓氏统计:一个文本文件中存储着北京所有高校在校生的姓名,格式每行一个名字,姓与名以空格分隔:
张 三
李 四
王 小五
现在想统计所有的姓氏在文件中出现的次数,请描述一下你的解决方案。
*/
https://blog.csdn.net/qq_52360788/article/details/118771494