集合
1.数组和ArrayList的区别
(1)数组 : 长度固定,有默认值,可以存放基本数据类型,也可以存放引用数据类型
int[] -> 0
double[] -> 0.0
String[] -> null
Person[] -> null
(2)ArrayList : 长度变化,没有默认值,引用数据类型
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
ArrayList<数据类型> persons = new ArrayList<数据类型>();
ArrayList<Person> persons = new ArrayList<>();
2.集合的继承体系
3.Collection集合的常用功能
(1).boolean add(E e): 添加元素
(2).boolean remove(Object o): 删除元素
(3).int size(): 查看集合大小
(4).void clear(): 清空集合
4.迭代器使用
(1)为什么要迭代器
因为Set接口这边的体系没有索引的.没有索引就不能使用for循环+get(索引)的方式来获取元素,所以集合搞了一种通用的获取元素方式
(2)迭代器 : 集合通用的获取元素的方式(Iterator)
(3)迭代器的常用方法
hasNext(): 如果有下一个元素返回true
next(): 取出下一个元素
5.迭代器迭代原理
6.增强for循环遍历数组
(1)增强for遍历数组底层使用普通for
(2)增强for循环遍历集合底层是迭代器
public class Demo07 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("唐伯虎");
list.add("祝枝山");
list.add("文征明");
list.add("周文宾");
// 增强for
for (String str : list) {
System.out.println(str);
}
// 增强for循环遍历集合底层是迭代器
String str;
// 走一次
for (Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(str)) {
str = (String)iterator.next();
} // for循环中如果只有一句代码可以省略{}, 不建议
// 迭代器
// Iterator<String> itr = list.iterator();
// while (itr.hasNext()) {
// System.out.println(itr.next());
// }
// 普通for
// for (int i = 0; i < list.size(); i++) {
// System.out.println(list.get(i));
// }
}
}
7.LinkedList的基本使用
(1).add添加
(2).add添加到指定的索引
(3).修改指定索引的元素
(4).遍历
(5).删除指定索引
(6).清空LinkedList
8.数组结构
int[] arr = new int[] {11, 22, 33, 44};
数组结构特点: 数组保存在堆中,是连续存放的,查询速度快,增加和删除慢
9.链表结构
链表结构特点: 在堆中不连续存储,查询速度慢,添加和删除速度快
10.ArrayList和LinkedList底层实现
(1)ArrayList底层使用
ArrayList底层使用的是数组,查询快,增删慢 (QQ好友)
如果不确定就用ArrayList
(2)LinkedList底层使用
LinkedList底层使用的是链表: 查询慢,增删快(打麻将)
11.因此,LinkedList特有方法
(1).void addFirst(E e): 添加到最前面
(2).void addLast(E e): 添加到最后面
(3).E getFirst(): 获取第一个元素
(4).E getLast(): 获取最后一个元素
(5).E removeFirst(): 删除第一个元素
(6).E removeLast(): 删除最后一个元素
public class Demo06 {
public static void main(String[] args) {
// 和头尾相关的方法
LinkedList<String> linked = new LinkedList<>();
linked.add("马云");
linked.add("马化腾");
linked.add("马景涛");
// 1.void addFirst(E e): 添加到最前面
linked.addFirst("马超");
// 2.void addLast(E e): 添加到最后面
linked.addLast("马赛克");
// 3.E getFirst(): 获取第一个元素
System.out.println(linked.getFirst());
// 4.E getLast(): 获取最后一个元素
System.out.println(linked.getLast());
// 5.E removeFirst(): 删除第一个元素
linked.removeFirst();
// 6.E removeLast(): 删除最后一个元素
linked.removeLast();
System.out.println(linked);
}
}
12.Set接口特点
(1)没有索引,没有顺序,元素不可重复
(2)类HashSet和LinkedHashSet都是接口Set的实现,两者都不能保存重复的数据。主要区别是HashSet不保证集合中元素的顺序,即不能保证迭代的顺序与插入的顺序一致
13.HashSet
(1)对于HashSet而言,它是基于HashMap来实现的,底层采用HashMap来保存元素
(2)
(3) isEmpty(),判断HashSet()集合是否为空,为空返回 true,否则返回false。
(4) contains(),判断某个元素是否存在于HashSet()中,存在返回true,否则返回false
(5)当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
14.LinkedHashSet
(1)没有索引,有顺序,元素不可重复
(2)LinkedHashSet是具有可预知迭代顺序的Set接口的哈希表和链接列表实现。此实现与HashSet的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序
(3)LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
15.HashSet存储自定义类型
(1)HashSet判断元素唯一的原理:看传入对象的hashCode和equal方法
16.Object的hashCode方法
(1).Object的hashCode方法默认
hashCode就是对象地址的10进制
(2).String的hashCode
String重写了hashCode方法让hashoCode和内容相关
(3).我们自定义的类如果要放到HashSet中怎么办?
也要重写hashCode方法
17.Object的equals方法
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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;
}
// p1.equals(p1)
// p1.equals(null)
// p1.equals(new Dog())
@Override
public boolean equals(Object obj) {
if (this == obj)
return true; // 地址值相同,肯定是同一对象返回true
if (obj == null)
return false; // 传入null,肯定不是同一对象,返回false
if (getClass() != obj.getClass())
return false; // 如果是不同的类型,返回false
Person other = (Person) obj;
if (age != other.age)
return false; // 年龄不相同,返回false
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false; // 姓名不相同,返回false
return true; // 姓名年龄相同,返回true
}
// @Override
// public String toString() {
// return "Person [name=" + name + ", age=" + age + "]";
// }
}
18.哈希表结构的特点
只要看到类名上带有Hash.说明它底层使用哈希表结构.HashSet底层使用的是哈希表结构
19.哈希表的存储元素过程(HashSet判断元素唯一的原理)
总结:只有存入对象的hashCode相同,equals返回true才不会存储
19.HashSet存储自定义对象
public class Demo13 {
public static void main(String[] args) {
HashSet<Student> set = new HashSet<>();
// 创建学生
Student s1 = new Student("流川枫", 18, 60);
Student s2 = new Student("樱木花道", 17, 61);
Student s3 = new Student("赤木刚宪", 18, 100);
Student s4 = new Student("晴子", 16, 100);
Student s5 = new Student("晴子", 16, 100);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
/*
我们知道元素要放到HashSet中,add里面1判断hashCode是否相同
s4和s5都是new出来的对象,s4和s5的地址值不一样,我们Studeng类没有重写hashCode方法,
就用的是Object的hashCode方法,Object的hashCode和对象的内存地址一样
s4和s5hashCode不一样,直接存储了
将姓名,年龄和分数相同的人看做同一人,不存储
所以我们hashCode和姓名,年龄和分数相关
*/
for (Student s : set) {
System.out.println(s);
}
}
}
public class Student {
private String name;
private int age;
private double socre;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age, double socre) {
super();
this.name = name;
this.age = age;
this.socre = socre;
}
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 double getSocre() {
return socre;
}
public void setSocre(double socre) {
this.socre = socre;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", socre=" + socre + "]";
}
// alt + shift + s -> hashCode and equals
// hashCode如果相同,需要比较equals方法,如果一个链表中挂的元素太多,equals会被调用很多次,效率就很低了
// 所以尽量保证hashCode不相同,直接存储速度快
// hashCode和内容相关
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(socre);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
// return 1;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
System.out.println(this.name + " 和 " + other.name);
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(socre) != Double.doubleToLongBits(other.socre))
return false;
return true;
}
}
====================================================
1.Collections集合工具类
(1)Collections工具类中的方法都是方便操作Collection集合的
(2)常用方法:
*max: 取出最大值
*reverse: 将集合中的元素反转
*shuffle: 随机打乱集合中的元素
*sort: 排序
*binarySearch: 二分/折半查找
2.Arrays数组工具类
(1)Arrays中的方法用来操作数组的
(2)常用方法:
*binarySearch: 二分查找
*sort: 排序
*toString: 将数组中元素的内容转成字符串返回
3.集合转数组
(1)为什么要集合转数组:有时候我们想给别人的数据很多,但是不让别人增加或删除,将集合转成数组.就无法增删
(2)Object[] toArray(): 返回Object类型的数组
(3) < T > T[] toArray(T[] a): 转成指定类型的数组
===============================================
1.Map接口
2.Map接口的特点
(1)将键映射到值的对象
(2)键不能重复,值可以重复
(3) 一个键对应一个值
3.Map的实现类
(1)HashMap: 基于哈希表的 Map 接口的实现, 并允许使用 null 值和 null 键,存储和取出没有顺序
(2)LinkedHashMap: 基于哈希表的 Map 接口的实现, 并允许使用 null 值和 null 键,存储和取出有顺序
4.Map接口中的常用方法
(1)V put(K key, V value) : 如果键不存在,添加元素,添加键和值, 返回值是null,如果键已经存在,修改元素,将后面的值替换前的值, 返回值前面被替换的值
(2)V get(Object key) : 通过key获取到value, 没有找到就返回null
(3)V remove(Object key) : 根据键删除这一对值
(4)int size() : 获取Map集合中元素的大小
(5)void clear() : 清空Map集合
3.Map获取所有的键和所有的值
(1)Map获取所有的键(常用) : Set< K > keySet()
(2)Map获取所有的值(不常用) : Collection< V > values()
4.Map集合遍历-键找值方式
(1)使用keySet
5.Map集合遍历-Entry键值对对象
(1)Entry是Map接口内部的一个接口,实际上我们看成普通的接口就可以,Entry中包含一个键和一个值,相当于结婚证
(2)
public class Demo10 {
public static void main(String[] args) {
// Entry中包含一个键和一个值
HashMap<String, String> hm = new HashMap<>();
hm.put("黄晓明", "Baby");
hm.put("梁朝伟", "刘嘉玲");
hm.put("刘恺威", "杨幂");
hm.put("老干爹", "老干妈");
// 1.拿到所有的Entry
Set<Entry<String, String>> entrySet = hm.entrySet();
// 2.遍历所有Entry,拿到每个Entry
for (Entry<String, String> entry : entrySet) {
// 3.通过Entry就可以拿到键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " == " + value);
}
}
}
-
Hashtable和HashMap的区别
(1).HashMap(常用)
*HashMap: null可以作为键和值
*HashMap: 线程不同步,不安全,速度快(2).Hashtable(面试会问)
*Hashtable: null不能作为键和值
*Hashtable: 线程同步,安全,速度慢
上一篇: (二十六) ArrayList