虽然昨天周六休息了了,但早上还是去了图书馆学习了下,只不过当时效率不太高,产出不多。今天专注学习时间大于5个小时。学习效率还是蛮高的,把Set接口学了以及复习了一部分之前的知识。还学了一部分的Map接口,开了个头,接下来的一周,可能学习时间不太够,但我还是会寄出来些时间,确保每天专注学习时间大于3小时,加油OVO。
Day17
新发现一个快捷键,双击Shift ,就可以查找所有了。
Set接口
HashSet和LinkedHashSet
package com.sorrymaker.CollectionTest;
import org.junit.Test;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* 1.set接口的框架
* /---Collection接口
* /--Set接口:存储无序的,不可重复的数据 ---> 高中讲的“集合”
* /--HashSet:作为Set接口的主要实现类,线程不安全,可以存储null值
* /--LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历、
* 对于频繁的的遍历操作,LinkedHashSet效率高于HashSet
* /--TreeSet:可以按照添加对象的指定属性,进行排序。
*
* 1.Set接口没有额外定义的方法,都是Collection的方法。
* 2.要求:向Set中添加的数据,其所在类一定给要重写hashCode()和equals()
* 要求:重写的hashCode()和equals()尽可能保持一致性。
*/
public class SetTest {
/*
一、Set:无序的,不可重复的。
HashSet为例
1.无序性:不等于随机性,存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的Hash值决定的。
2.不可重复性:保证添加的元素按照equals()判断时,不能返回true,即:相同的元素只能添加一个。
二、添加元素的过程:以HashSet为例:
向HashSet中添加元素a,首先调用元素a所在的hashCode()方法,计算元素a的哈希值,
此时哈希值接着通过某种计算在HashSet底层数组中的存放位置(即为索引位置),判断
数组此位置是否已经有元素;
如果此位置上没有其他元素,则元素a添加成功 ----->情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
如果hash值不同,则元素a添加成功 ------>情况2
如果hash值相同,进而需要调用元素a所在类的equals()方法:
equals()返回True,元素a添加失败。
equals()返回false,则元素a添加成功 ----->情况2
HashSet底层:数组+链表的结构。
*/
@Test
public void test1(){
//LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录了此数据前一个和后一个数据
//对于频繁的的遍历操作,LinkedHashSet效率高于HashSet
Set set =new LinkedHashSet();
set.add(456);
set.add(123);
set.add("AA");
set.add("cc");
set.add(123);//Set不可重复性,所以不会输出两个一样的对象。
set.add(new Person("tom",20));
set.add(new Person("ton",20));//地址值不一样,所以都能输出
Iterator iterator =set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
TreeSet
package com.sorrymaker.CollectionTest;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
/*
1.向TreeSet中添加的数据,要求是相同类的对象。
2.两种排序方式:自然排序(实现Comparable接口)和定制排序。
3.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals();
4.在定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals();
*/
@Test
public void test1(){
TreeSet set = new TreeSet();
//失败,不能添加不同类的对象
// set.add(123);
// set.add(456);
// set.add(new Person("小明",21));
// set.add(456);
//举例一:可以排序,按照从小到大。
// set.add(123);
// set.add(456);
// set.add(789);
// set.add(-2);
//举例二:自定义的排序
set.add(new User("AA",21));
set.add(new User("CC",22));
set.add(new User("QS",23));
set.add(new User("LJS",19));
set.add(new User("LOL",2));
set.add(new User("LOL",12));
Iterator iterator =set.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 set =new TreeSet(com);//有参数,就按照定制的排序了。
set.add(new User("AA",21));
set.add(new User("CC",22));
set.add(new User("QS",23));
set.add(new User("LJS",19));
set.add(new User("LOL",2));
set.add(new User("QQ",2));
set.add(new User("LOL",12));
Iterator iterator =set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
今日五题:
-
集合Collection 中存储的如果是自定义的对象,需要自定义类重写那个方法?为什么?
重写equals()方法。 contains()/remove()/retainsAll()
List:equals()方法
Set(HashSet和LinkedHashSet为例):重写equals()和hashCode()。
(TreeSet为例):Comparable:compareTo(Object obj)
Comparator:compare(Object o1,Object o2)(相同的元素不输出)
-
ArrayList,LinkedList,Vector 三者的相同点不同点:
List Map Set
相同点:
ArrayList :作为List接口的主要实现类。线程不安全,效率高。开发中经常用。扩容的时候是1.5倍,底层是Object[] elementData存储,查找效率高,插入效率低,O*n
LinkedList:效率高。底层存储是以双向链表存储,查找效率低O的n次方,插入效率高。
Vector:古老的,效率低,扩容的是2倍。底层使用Object[] elementData存储,线程安全。
-
List的接口的常用方法有那些(增。删。改。查。插入。长度。遍历)
-
add(Object obj)
-
remove(int index)/remove(Object obj)
-
set(int index,Object obj)
-
get(int index)
-
add(int index , Object obj)
-
size()-----返回的是元素的个数。
-
使用迭代器
iterator;foreach;普通的for循环。
-
-
如何使用Iterator ,foreach,遍历list,举例说明:
public void test2(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("Aa");
//方式一,使用迭代器Iterator遍历
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));
}
}
-
Set的存储数据的特点是说明?常见的实现类有什么?说明以下特点。
特点:Set:无序的,不可重复的。
常见的实现类:HashSet
LinkedHashSet
TreeSet
今日代码
自然排序和定制排序
EmplyeeTest
package com.sorrymaker.TreeSetTest;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class EmployeeTest {
//2.按生日日期的先后顺序排序
@Test
public void test2() {
TreeSet set = new 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;
MyDate b1 = e1.getBirthday();
MyDate b2 = e2.getBirthday();
//方式一:
// //比较年
// int minusYear = b1.getYear() - b2.getYear();
// if (minusYear != 0) {
// return minusYear;
// }
// //比较月
// int minusMonth = b1.getMonth() - b2.getMonth();
// if (minusMonth != 0) {
// return minusMonth;
// }
// //比较日
// return b1.getDay()- b2.getDay();
// }
//方式二:
return b1.compareTo(b2);
}
throw new RuntimeException("数据不一致,");
}
});
Employee e1 = new Employee("lianghuisen", 21, new MyDate(2000, 07, 25));
Employee e2 = new Employee("xiaofeizhu", 21, new MyDate(2000, 05, 25));
Employee e3 = new Employee("naocan", 19, new MyDate(2002, 02, 23));
Employee e4 = new Employee("ruozhi", 20, new MyDate(2001, 05, 23));
Employee e5 = new Employee("choushabi", 22, new MyDate(1999, 05, 23));
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());
}
}
//1.自然排序
@Test
public void test1(){
TreeSet set =new TreeSet();
Employee e1 =new Employee("lianghuisen",21, new MyDate(2000,07,25));
Employee e2 =new Employee("xiaofeizhu",21, new MyDate(2000,05,25));
Employee e3 =new Employee("naocan",19, new MyDate(2002,02,23));
Employee e4 =new Employee("ruozhi",20, new MyDate(2001,05,23));
Employee e5 =new Employee("choushabi",22, new MyDate(1999,05,23));
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());
}
}
}
MyDate
package com.sorrymaker.TreeSetTest;
public class MyDate implements Comparable {
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 +
'}';
}
@Override
public int compareTo(Object o) {
MyDate d = (MyDate) o;
//比较年
int minusYear = this.getYear() - d.getYear();
if (minusYear != 0) {
return minusYear;
}
//比较月
int minusMonth = this.getMonth() - d.getMonth();
if (minusMonth != 0) {
return minusMonth;
}
//比较日
return this.getDay() - d.getDay();
}
}
Employee
package com.sorrymaker.TreeSetTest;
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) {
if(o instanceof Employee){
Employee e =(Employee) o;
return this.name.compareTo(e.name);//按从小到大排序
}else {
throw new RuntimeException("数据错误");
}
}
}
课后两道小题
1.在List内去除重复数字值,要求尽量简单。
2.哈希值,在从写了hashCode()和equals()方法的前提下。
package com.sorrymaker.CollectionTest;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class dayTest {
//在List内去除重复数字值,要求尽量简单。
public static List duplicateList(List list){
HashSet set =new HashSet();
set.addAll(list);
return new ArrayList(set);
}
@Test
public void test(){
List list =new ArrayList();
list.add(new Integer(1));
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(2));
list.add(new Integer(5));
List list1 = duplicateList(list);
for(Object integer:list1){
System.out.println(integer);
}
}
@Test
public void test1(){
//因为有person类了,所以我建个Atm类
HashSet set =new HashSet();
Atm atm1 =new Atm("小红",21);
Atm atm2 =new Atm("lv",11);
set.add(atm1);
set.add(atm2);
System.out.println(set);//[Atm{name='小红', age=21}, Atm{name='lv', age=11}]
atm1.name ="panda";
//hashCode的值改变了,按照原本的hashCode值找不到,所以没删除。
set.remove(atm1);//按照哈希值删除,又因为已经改变了,所以没删除到。
System.out.println(set);//[Atm{name='lv', age=11}, Atm{name='panda', age=21}]
set.add(new Atm("panda",21));
//这个是拿原本的"小红","11"的hash值算,发现没有,所以就可以添加这个元素。
System.out.println(set);//[Atm{name='lv', age=11}, Atm{name='panda', age=21}, Atm{name='panda', age=21}]
set.add(new Atm("小红",21));
//虽然hash值一样,但是equals不一样,这里equals的是panda,所以不一样,就还是可以存储进去。
System.out.println(set);//[Atm{name='lv', age=11}, Atm{name='panda', age=21}, Atm{name='panda', age=21}, Atm{name='小红', age=21}]
}
}
Day17 Map接口
Map接口继承树
package com.sorrymaker.Map;
import org.junit.Test;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* 一、Map的实现类的结构:
* /----Map:双列数据,存储key-value键值对的数据 -类似于y =f(x)
* /---HashMap:作为Map的主要实现类;线程不安全的,效率高。允许存储null的key和value
* /---LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。
* 原因:在原有的HashMap底层结构的基础上,添加了一对指针,指向了前一个和后一个元素。
* 对于频繁的遍历操作,此类执行效率高于HashMap。
* /---TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。按照key来自然排序和定制排序。
* 底层使用红黑树。
* /---Hashtable:作为古老的实现类;线程安全,效率低。不允许存储null的key和value。
* /---Properties:常用来处理配置文件,key和value都是String类型。
*
*
* HaspMap的底层:数组加链表(jdk7之前)
* 数组加链表加红黑树 (jdk8)
*
* 面试题:
* 1.HashMap的底层实现原理:
* 2.HashMap 和Hashtable的异同。
* 3.CurrentHashMap 与Hashtable的异同。
*
* 二、Map的理解
* Map中的key:无序的,不可重复的,使用Set存储所有的Key。--->key所在的类要重写equals()和hashCode()(以hashMap为例)。
* Map中的value:无序的,可重复的,使用Collection 存储了所有的value--->value所在的类要重写equals()
* 一个键值对:key—value构成了一个Entry对象。
* Map中的entry:无序的,不可重复的,使用所有Set存储所有entry。
*
* @author 喜
*/
public class MapTest {
@Test
public void test(){
Map map =new HashMap();
map =new Hashtable();
map.put(null,null);
}
}