1.练习回顾
①定义商品类: 商品名字,价格;
②通过输入的方式创建5个商品;
③将商品添加到Set集合中,要求信息相同的商品不能重复添加;
④使用迭代器遍历商品信息。
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Set set = new HashSet();
while(set.size()<5){
System.out.println("请输入商品名称和商品价格:");
Goods goods = new Goods(scanner.next(),scanner.nextDouble());
if (set.contains(goods)){
System.out.println("商品重复,请重新输入!");
continue;
}
set.add(goods);
}
Iterator it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
商品类:
public class Goods {
private String name;
double price;
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Goods goods = (Goods) o;
return Double.compare(goods.price, price) == 0 && Objects.equals(name, goods.name);
}
@Override
public int hashCode() {
return this.name.hashCode() +Double.hashCode(this.price);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
2. TreeSet
TreeSet 基于TreeMap 实现;TreeSet可以实现有序集合,但是有序性需要通过比较器实现。
2.1 TreeSet特点
①有序;
②不重复;
③添加、删除、判断元素存在性的效率比较高;
④线程不安全。
2.2 TreeSet对元素进行排序的方式
① 如果是基本数据类型和String类型,无需其他操作,可以直接进行排序;
②对象类型元素排序,需要实现Comparable接口,并覆盖其compareTo方法;
③自己定义实现了Comparator接口的排序类,并将其传给TreeSet,实现自定义的排序规则。
实例①:
//基本数据类型,同类型才可以比较进而排序
public class Test {
public static void main(String[] args) {
Set set = new TreeSet();
set.add("bc");
set.add("ac");
set.add("ab");
Iterator it =set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
实例②:
//实现Comparable接口
public class Student implements Comparable{
private String name;
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//比较对象大小
@Override
public int compareTo(Object o) {
//先判断类型是否一致
if(!(o instanceof Student)){
return 1;
}
Student s = (Student) o;
if(this.age>s.age){
return 1;
}else if(this.age<s.age){
return -1;
}else {
//年龄相等时,按姓名排序
return this.name.compareTo(s.name);
}
}
}
实例③:
//自定义的比较器,用于特定对象的比较
public class MyComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Car && o2 instanceof Car){
Car c1 = (Car) o1;
Car c2 = (Car) o2;
if(c1.price>c2.price){
return 1;
}else if(c1.price<c1.price){
return -1;
}else {
return c1.brand.compareTo(c2.brand);
}
}
return -1;
}
}
3. LinkedHashSet
LinkHashSet是一种有序的Set集合,其元素的存入和取出顺序是相同的。
public class Test {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add("c");
set.add("d");
set.add("a");
set.add("a");
set.add(10);
set.add(9);
System.out.println(set);
}
}
4. Map接口及其实现类
Map接口特点:
①以键值对方式存储数据(Collection是单值集合);
②键不能重复,键重复时,后面的数据会覆盖前面的数据;
③HashMap的键和值可以存储nll,HashTable不能存储null值;
④键值对数据无序。
返回类型 | 方法 | 描述 |
Object | get(Object key) | 根据key取得value |
object | put(Object k,Object v) | 向集合中加入元素 |
void | clear() | 清除Map集合 |
boolean | isEmpty() | 判断集合是否为空 |
boolean | containsKey(Object object) | 判断指定的key是否存在 |
boolean | containsValue(Object value) | 判断指定的value是否存在 |
Set | keySet() | Map中所有的key的集合 |
object | remove(Object key) | 根据key删除对应的value |
Collection | values() | 取出全部的value |
int | size() | 获得集合的长度 |
4.1 HashMap实现类
HashMap实现了Map接口,拥有Map接口的基本特点;HashMap线程不安全,效率高;底层是由哈希表、链表和红黑树构成的。
public class Test {
public static void main(String[] args) {
//16:初始容量
Map map = new HashMap(16);
//put:存储数据
map.put("name","小成");
map.put("age","20");
map.put("people",new People("小成",20));
map.put("wen",18);
//键重复时,后面的数据覆盖前面的
map.put("wen",20);
map.put(20,"wen");
//判断是否为空
System.out.println(map.isEmpty());
System.out.println(map);
//实际存储的元素个数
System.out.println(map.size());
//根据键获取值
System.out.println(map.get("people"));
//判断是否包含某个键
System.out.println(map.containsKey(20));
//返回map中键的集合,一个Set集合
System.out.println(map.keySet());
//返回map中值的集合,一个Collection集合
System.out.println(map.values());
}
}
遍历集合:
//①:遍历键的集合
Set set = map.keySet();
for (Object obj:set) {
System.out.println(obj +" "+map.get(obj));
}
//②:遍历键值对集合
Set entrySet = map.entrySet();
for (Object o:entrySet) {
//Map.Entry:Map接口的子接口,表示一个键值对对象
Map.Entry kv = (Map.Entry) o;
System.out.println(kv.getKey()+"==="+kv.getValue());
}
4.2 HashMap底层原理
4.2.1 map.put(key,value)实现原理
①首先将k、v封装到Node对象中(节点);
②底层会调用k的hashCode()方法得出hash值;
③通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上,如果说下标对应位置上有链表,则会用这个k和链表上每个节点的k进行equals比较,如果所有的equals方法返回的都是false,则这个新的节点将被添加到链表的末尾,如果其中有一个equals返回true,则这个节点的value将会被覆盖。
4.2.2 map.get(key) 实现原理
①先调用k的hashCode()方法计算哈希值,并通过哈希算法转换成数组的下标;
②通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上,如果这个位置上没有存储数据,则返回null;如果这个位置上有单向链表,则会将这个参数k和单链表上的每一个节点的k进行equals比较,如果都返回了false,则get方法返回null;如果有一个为true则该节点的value就是我们要找的value,并通过get方法返回这value。
4.2.3 map的扩容原理
①当数组元素个数大于阈值(长度*0.75)时,数组扩容;
②当某个节点的链表超过8,并且数组长度小于64,此时不将链表转为树,而是进行扩容;
③当某个节点链表长度大于8,并且数组长度大于64,此时将链表转为红黑树。
4.3 Hashtable
Hashtable也实现了Map接口,它的特点有:
①以键值对方式存储数据;
②键不能重复;
③数据无序;
④键和值都不能存储null;
⑤线程安全,效率低。
4.4 泛型集合
泛型:对要管理的数据进行类型限定,方便数据的处理;
在往集合中存储数据的时候缺乏类型检查,不安全。
泛型:类型检查,省略了装箱和拆箱,效率高类型安全。
语法:
List<T>:E类型约束;
Set<T>:E类型约束;
Map<K,V>:K,V类型约束
①
public class Test {
public static void main(String[] args) {
List<People> list= new ArrayList<People>();
//添加非People类型的数据直接报错
//list.add("aaa");
list.add(new People("张三",18));
list.add(new People("李四",19));
//遍历
for (int i = 0; i < list.size(); i++) {
People p = list.get(i);
p.introduce();
}
for (People p:list) {
p.introduce();
}
}
}
public class People {
private String name;
private int age;
public People() {
}
public People(String name, int age) {
this.name = name;
this.age = age;
}
//自我介绍
public void introduce(){
System.out.println(this.name+" "+this.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 "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
②
public class Test2 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("aaa");
set.add("bbb");
for (String s:set) {
System.out.println(s);
}
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
}
}
③
public class Test3 {
public static void main(String[] args) {
Map<String,People> map = new HashMap<>();
map.put("张三",new People("张三",18));
map.put("李四",new People("李四",19));
Set<String> set = map.keySet();
for (String s:set) {
System.out.println(s+" "+map.get(s));
}
}
}