文章目录
一、集合的概念
集合的概念:对象的容器,定义了对多个对象进行操作的常用方法,可实现数组的功能。
和数组的区别:
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型。
位置:java.util.*;
二、Collection接口
- 特点:代表一组任意类型的对象,无序、无下标、不能重复。
- 创建集合:
Collection collection = new ArrayList();
常用方法:
方法 | 作用 |
---|---|
boolean add(Object obj) | 添加一个对象 |
boolean addAll(Collection c) | 将一个集合中的所有对象添加到此集合中 |
void clear() | 清空此集合中的所有对象 |
boolean contains(Object obj) | 检查此集合是否包含指定对象 |
boolean equals(Object o) | 比较此集合是否与指定对象相等 |
boolean isEmpty() | 判断此集合是否为空 |
int size() | 返回此集合中的元素个数 |
Object[] toArray() | 将此集合转换成数组(类型为Object) |
public static void main(String[] args) {
//Collection接口的使用
//创建集合 Collection不能直接实例化
Collection collection = new ArrayList();
//1 添加元素
collection.add("苹果");
collection.add("芒果");
collection.add("榴莲");
//添加对象
//Student student=new Student("aaa",20);
//collection.add(student);
System.out.println("元素个数:"+collection.size());//元素个数:3
System.out.println(collection);//相当于调用toString()方法 [苹果, 芒果, 榴莲]
//2 删除元素
//collection.remove("苹果");
//System.out.println("删除后的元素个数:"+collection.size());//删除后的元素个数:2
//collection.clear();//清空
//clear(); 只是清空集合存储的地址值!
//3 遍历 ★
//3.1 使用增强for
for (Object object:collection) {
System.out.println(object);
}
//3.2 使用迭代器(迭代器是专门用来遍历集合的一种方式)
Iterator it=collection.iterator();//Iterator是一个接口
//迭代器的三种方法:
//haNext(); 有没有下一个元素
//next(); 获取下一个元素 返回的是Object类型
//remove(); 删除当前元素
while(it.hasNext()){
String object = (String)it.next(); //强转
System.out.println(object);
//在迭代过程中不能使用collection的方法来改变集合的元素
//collection.remove(); 不能用collection其他方法 会报并发修改异常
//但可以使用it.remove(); 进行移除元素
}
//4 判断
System.out.println(collection.contains("苹果"));//true
System.out.println(collection.isEmpty());//false
}
三、List接口与实现类
List接口
- 特点:有序、有下标、元素可重复。
- 创建集合对象:
List list = new ArrayList<>( );
常用方法:
方法 | 作用 |
---|---|
void add(int index,Object obj) | 在index位置插入一个对象obj |
boolean addAll(int index,Collection c) | 将一个集合中的元素添加到此集合中的index位置 |
void clear() | 清空此集合中的所有对象 |
Object get(int index) | 返回集中中指定位置的元素 |
List subList(int fromIndex,int toIndex) | 返回fromIndex和toIndex之间的集合元素 |
注:List继承了Collection接口的所有方法,还包含了以上的方法。
public static void main(String[] args) {
//List子接口的使用
//创建集合对象
List list = new ArrayList<>( );
//1 添加元素
list.add("芒果");
list.add("榴莲");
list.add(0,"葡萄");//在第一个位置插入元素
//添加基本数据类型时,会对基本类型进行自动装箱!!!
//list.add(20);
System.out.println("元素个数:"+list.size());//元素个数:3
System.out.println(list.toString());//[葡萄, 芒果, 榴莲]
//2 删除元素
//list.remove("葡萄");
//list.remove(0);//删除第一个元素
//当删除数字与索引矛盾时 对数字强转
//list.remove((Object) 20) 或 list.remove(new Integer(20))
//System.out.println("元素个数:"+list.size());//元素个数:2
//System.out.println(list.toString());//[芒果, 榴莲]
//3 遍历
//3.1 使用for遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));//get() 返回的是Object类型
}
//3.2 使用增强for
for (Object object:list) {
System.out.println(object);
}
//3.3 使用迭代器
Iterator it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//3.4 使用列表迭代器 ★
//和迭代器iterator的区别:
//listIterator可以向前或向后遍历,还可以添加、删除和修改元素
ListIterator li=list.listIterator();
while(li.hasNext()){
System.out.println(li.nextIndex() + ":" + li.next()); //从前往后遍历
//nextIndex下一个元素的角标
}
while(li.hasPrevious()){
System.out.println(li.previousIndex() + ":" + li.previous()); //从后往前遍历
}
//4 判断
System.out.println(list.contains("葡萄"));//true
System.out.println(list.isEmpty());//false
//5 获取位置
System.out.println(list.indexOf("芒果"));//1
//6 返回子集合 sublist(x, y); 左闭右开
//list 20 30 40 50
//List subList = list.subList(1, 3); 返回索引 1、2
//subList 30 40
}
List实现类
- ArrayList 【重点】:
- 由数组结构实现,必须要连续空间,查询快、增删慢。
- jdk1.2版本,运行效率快、线程不安全。
- Vector:
- 数组结构实现,查询快、增删慢。
- jdk1.0版本,运行效率慢,线程安全。
- LinkedList:
- 由双向链表结构实现,无需连续空间,增删快,查询慢。
ArrayList
public static void main(String[] args) {
//ArrayList的使用
//创建集合
ArrayList arrayList = new ArrayList<>();
//1 添加元素
Student s1=new Student("aaa",12);
Student s2=new Student("bbb",14);
Student s3=new Student("ccc",10);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size());//元素个数:3
System.out.println(arrayList.toString());
//2 删除元素
//arrayList.remove(s1);
//System.out.println("元素个数:"+arrayList.size());//元素个数:2
//arrayList.remove(new Student("aaa",12));//若想实现此行代码,需要重写equals方法
//remove方法实际上会调用 equals(this==obj) 比较的是地址
//System.out.println("元素个数:"+arrayList.size());//元素个数:2
//arrayList.clear();//清空
//3 遍历元素 ★
//3.1 使用迭代器
Iterator it=arrayList.iterator();
while(it.hasNext()){
Student s=(Student)it.next();
System.out.println(s.toString());
}
//3.2 使用列表迭代器
ListIterator li=arrayList.listIterator();
while(li.hasNext()){//顺序
Student s=(Student)li.next();
System.out.println(s.toString());
}
while(li.hasPrevious()){//逆序
Student s=(Student)li.previous();
System.out.println(s.toString());
}
//4 判断
System.out.println(arrayList.contains(new Student("aaa",12)));//true 因为判断的规则已经被修改了
System.out.println(arrayList.isEmpty());//false
//5 查找
System.out.println(arrayList.indexOf(new Student("aaa",12)));//0
}
@Override
public boolean equals(Object obj){
//1 判断是不是同一个对象
if(this == obj){
return true;
}
//2 判断是否为空
if(obj == null){
return false;
}
//3 判断obj是否是Student类型
if(obj instanceof Student){
Student s = (Student)obj;
//4 比较属性
if(this.name.equals(s.getName()) && this.age == s.getAge()){
return true;
}
}
//5 不满足条件返回false
return false;
}
源码分析:
DEFAULT_CAPACITY = 10; //默认容量
//注意:如果没有向集合中添加任何元素时,容量0,添加一个后,容量为10
//每次扩容是原来的1.5倍
Object[] elementData//存放元素的数组
size//实际元素个数
add()//添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Vector
public static void main(String[] args) {
//Vector集合的使用
//创建集合
Vector vector = new Vector<>();
//1 添加元素
vector.add("芒果");
System.out.println("元素个数:"+vector.size());//元素个数:1
System.out.println(vector.toString());//[芒果]
//2 删除 和ArrayList的一样
//3 遍历
//可以使用for、增强for、迭代器遍历,用法参考和ArrayList的一样
//使用枚举器
Enumeration en = vector.elements();
while(en.hasMoreElements()){
String o = (String)en.nextElement();
System.out.println(o);
}
//4 判断和查找同理
//补充
vector.firstElement();//得到第一个元素
vector.lastElement();//得到最后一个元素
vector.elementAt(0);//获取第一个位置的元素 get()
}
LinkedList
public static void main(String[] args) {
//LinkedList集合的使用
//创建集合
LinkedList li = new LinkedList<>();
//用法和ArrayList一致!!
}
ArrayList与LinkedList的区别:
四、泛型
- Java 泛型是JDK1.5引入的一个新特性,其本质是参数化类型,即把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法。
- 语法:<T,…> T称为类型占位符,表示一种引用类型。
- 好处:
- 提高代码的重用性。
- 防止类型转换异常,提高代码的安全性。
泛型类
//泛型类
//语法:类名<T,E>
//T是类型占位符,表示一种引用类型,如果编写多个,需使用逗号隔开
public class MyGeneric<T>{
//T表示一种类型,使用泛型T
//1 创建变量
T t;
//2 泛型作为方法的参数
public void show(T t){
//T t=new t();//不能实例化!!
System.out.println(t);
}
//3 泛型作为方法的返回值
public T getT(){
return t;
}
}
public static void main(String[] args) {
//使用泛型类创建对象
// 注意: 1. 泛型只能使用引用类型
// 2. 不用泛型类型对象之间不能相互赋值!
MyGeneric<String> myGeneric = new MyGeneric<String>();
myGeneric.t = "hello";
myGeneric.show("hello world");
String string = myGeneric.getT();
MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();
myGeneric2.t = 100;
myGeneric2.show(200);
Integer integer = myGeneric2.getT();
}
泛型接口
//泛型接口
//语法:接口名<T>
public interface MyInterface<T> {
String name="aaa";
//T t;//注意:不能定义泛型静态常量!!
T server(T t);
}
//使用泛型接口 第一种方式
public class MyInterfaceImpl implements MyInterface<String>{
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
public class Test {
public static void main(String[] args) {
MyInterfaceImpl impl=new MyInterfaceImpl();
impl.server("aaa");
}
}
//使用泛型接口 第二种方式
public class MyInterfaceImpl<T> implements MyInterface<T>{
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
public class Test {
public static void main(String[] args) {
MyInterfaceImpl<Integer> impl=new MyInterfaceImpl<>();
impl.server(100);
}
}
泛型方法
//泛型方法
//语法:放在方法的返回值前面
// <T> 返回值类型
public class MyGenericMethod {
//泛型方法
public <T> T show(T t){
System.out.println("泛型方法" + t);
return t;
}
}
public class Test {
public static void main(String[] args) {
//调用泛型方法
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("字符串");// 自动类型为字符串
myGenericMethod.show(100);// integer类型
myGenericMethod.show(3.14);// double类型
}
}
泛型集合
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间应用不能相互赋值,泛型不存在多态。
public static void main(String[] args) {
ArrayList arrayList=new ArrayList();
//可以添加任何类型,但是在遍历时进行类型转换时很容易出现类型转换异常!
arrayList.add("aa");
arrayList.add(111);
//泛型集合 在编译时已经确认了类型
ArrayList<String> arrayList1=new ArrayList<>();
//只能添加String类型的!
arrayList1.add("aaa");
arrayList1.add("bbb");
}
五、Set接口与实现类
Set
特点:无序、无下标、元素不可重复。
方法:全部继承自Collection中的方法(没有提供其他的方法)。
Set实现类:
- HashSet 【重点】
- 基于HashCode实现元素不重复。
- 当存入元素的哈希码(HashCode)相同时,会调用equals进行判断,如果为true,则拒绝后者写入。
- TreeSet
- 基于排列顺序实现元素不重复。
- 实现了SortedSet接口,对集合元素自动排序。
- 元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过CompareTo方法确定是否为重复元素。
public static void main(String[] args) {
//Set接口的使用
//创建集合
Set<String> set=new HashSet<>();
//1 添加数据
set.add("cc");
set.add("aa");
set.add("小米");
set.add("bb");
System.out.println("元素个数:"+set.size());//元素个数:3
System.out.println(set.toString());//[cc, aa, bb, 小米]
//2 删除数据
//set.remove("cc");
//set.clear();
//3 遍历
//3.1 增强for
for (String string:set) {
System.out.println(string);
}
//3.2 使用迭代器
Iterator<String> it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4 判断
System.out.println(set.contains("aa"));//true
System.out.println(set.isEmpty());//false
}
HashSet
public static void main(String[] args) {
//HashSet接口的使用
//存储结果:哈希表(数组+链表+红黑树(jdk1.8之后))
//创建集合 增、删、遍历、判断与collection的用法一致!!
//HashSet<String> hashSet=new HashSet<String>();//在jdk1.8之后可以不用写了
HashSet<String> hashSet=new HashSet<>();
//1 添加数据
hashSet.add("苹果");
hashSet.add("芒果");
hashSet.add("榴莲");
System.out.println("数据个数:"+hashSet.size());//元素个数:3
System.out.println(hashSet.toString());//[苹果, 榴莲, 芒果]
//2 删除数据
//hashSet.remove("榴莲");
//System.out.println("数据个数:"+hashSet.size());//元素个数:2
//hashSet.clear();
//System.out.println("数据个数:"+hashSet.size());//元素个数:0
//3 遍历操作
//3.1 增强for
for (String string:hashSet) {
System.out.println(string);
}
//3.2 使用迭代器
Iterator<String> it=hashSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4 判断
System.out.println(hashSet.contains("苹果"));//true
System.out.println(hashSet.isEmpty());//false
}
存储过程(重复依据):
- 根据hashCode计算保存的位置,如果此位置为空,则直接保存,如果不为空,则执行第二步。
(1)利用31这个质数(只能被1和自身整数),可以减少散列冲突。 (2)可以提高执行效率 31 * i = (i << 5) - i 转为移位操作。
- 再执行equals方法,如果equals为true,则认为是重复,反之形成链表。
public static void main(String[] args) {
//HashSet接口的使用
//存储结果:哈希表(数组+链表+红黑树(jdk1.8之后))
//创建集合
//HashSet<String> hashSet=new HashSet<String>();//在jdk1.8之后可以不用写了
HashSet<Student> hashSet=new HashSet<>();
Student s1=new Student("aaa",11);
Student s2=new Student("bbb",14);
Student s3=new Student("ccc",17);
//1 添加数据
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
//hashSet.add(s3);//重复,无法添加
//hashSet.add(new Student("aaa",11));//可以添加
//重写hashCode和equals后,上诉代码无法被添加
System.out.println("数据个数:"+hashSet.size());//元素个数:3
System.out.println(hashSet.toString());
//2 删除操作
//hashSet.remove(new Student("aaa",11));//没有重写hashCode和equals之前,这样的写法无法删除s1
}
@Override
public boolean equals(Object obj){
//1 判断是不是同一个对象
if(this == obj){
return true;
}
//2 判断是否为空
if(obj == null){
return false;
}
//3 判断obj是否是Student类型
if(obj instanceof Student){
Student s = (Student)obj;
//4 比较属性
if(this.name.equals(s.getName()) && this.age == s.getAge()){
return true;
}
}
//5 不满足条件返回false
return false;
}
@Override
public int hashCode() {
int n1=this.name.hashCode();
int n2=this.age+31;
return n1+n2;
}
TreeSet
public static void main(String[] args) {
//TreeSet的使用
//存储结构:红黑树
//创建集合
TreeSet<String> treeSet = new TreeSet<>();
//1 添加数据
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("hello");
//treeSet.add("xyz");//不再添加
System.out.println("数据个数:"+treeSet.size());//数据个数:3
System.out.println(treeSet.toString());//[abc, hello, xyz] 自动排序
//2 删除数据
//treeSet.remove("abc");
//treeSet.clear();
//3 遍历操作
//3.1 增强for
for (String string:treeSet) {
System.out.println(string);
}
//3.2 迭代器
Iterator<String> it=treeSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4 判断
System.out.println(treeSet.contains("abc"));//true
System.out.println(treeSet.isEmpty());//false
}
补充:TreeSet集合的使用
- Comparator 实现定制比较(比较器)
- Comparable 可比较的
Comparable
public class Student implements Comparable<Student>{
//先按姓名比,再按年龄比
@Override
public int compareTo(Student o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.getAge()-o.getAge();
return n1 == 0 ? n2 : n1;
}
}
public static void main(String[] args) {
//TreeSet的使用
//存储结构:红黑树
//要求:元素对象的类型必须实现Comparable接口
//compareTo()方法的返回值为0,认为是重复元素
//创建集合
TreeSet<Student> treeSet = new TreeSet<>();
Student s1=new Student("aaa",13);
Student s2=new Student("bbb",15);
Student s3=new Student("ccc",17);
Student s4=new Student("ccc",18);
//1 添加数据
treeSet.add(s1);
treeSet.add(s2);
treeSet.add(s3);
treeSet.add(s4);
System.out.println("数据个数:"+treeSet.size());//数据个数:3
System.out.println(treeSet.toString());
//[Student{name='aaa', age=13}, Student{name='bbb', age=15}, Student{name='ccc', age=17}, Student{name='ccc', age=18}]
//2 删除数据
//treeSet.remove(new Student("aaa",13));//可以删除s1
//System.out.println(treeSet.contains(new Student("aaa",13)));//true
//是根据compareTo()方法来比较的
}
Comparator
public static void main(String[] args) {
//TreeSet的使用
//存储结构:红黑树
//Comparator:实现定制比较(比较器)
//创建集合,并指定比较规则,这样Student可以不用实现Comparable接口
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n1 = o1.getAge()-o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1 == 0 ? n2 : n1;
}
});
Student s1=new Student("aaa",13);
Student s2=new Student("bbb",15);
Student s3=new Student("ccc",17);
Student s4=new Student("ccc",18);
//1 添加数据
treeSet.add(s1);
treeSet.add(s2);
treeSet.add(s3);
treeSet.add(s4);
System.out.println(treeSet.toString());
}
案例:
public static void main(String[] args) {
//要求:使用TreeSet集合实现字符串按照长度进行排序
//helloworld zhang lisi wangwu xian ba
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1=o1.length()-o2.length();
int n2=o1.compareTo(o2);
return n1==0?n2:n1;
}
});
//添加数据
treeSet.add("helloworld");
treeSet.add("zhang");
treeSet.add("lisi");
treeSet.add("wangwu");
treeSet.add("xian");
treeSet.add("ba");
System.out.println(treeSet.toString());
//[ba, lisi, xian, zhang, wangwu, helloworld]
}
六、Map接口与实现类
Map
Map接口的特点:
- 存储一对数据(Key-Value),无序、无下标,键不可重复,值可以重复。
方法 | 作用 |
---|---|
V put(K key,V value) | 将对象存入到集合中,关联键值,Key 重复会覆盖掉原值 |
Object get(Object key) | 根据键获取对应的值 |
Set< K> keySet() | 返回所有Key |
Collection< V> values() | 返回包含所有值的Collection集合 |
Set<Map.Entry<K,V>> entrySet() | 键值匹配的Set集合 |
public static void main(String[] args) {
//Map接口的使用
//创建Map集合
Map<String, String> map = new HashMap<>();
//1 添加元素
map.put("cn", "中国");
map.put("uk", "英国");
map.put("usa","美国");
System.out.println("元素个数:"+map.size());//元素个数:3
System.out.println(map.toString());//{usa=美国, uk=英国, cn=中国}
map.put("cn", "zhongguo"); // 会替换第一个的值
System.out.println(map.toString());//{usa=美国, uk=英国, cn=zhongguo}
//2 删除
//map.remove("uk");//根据Key删除
//map.clear();
//3 遍历
//3.1 使用KeySet()
//Set<String> keyset = map.keySet(); // 所有Key的set集合
for(String key : map.keySet()){
System.out.println(key + "---" + map.get(key));
}
//3.2 使用entrySet()
//Set<Map.Entry<String, String>> entries = map.entrySet();
//Entry<String, String>包含一个键值对
for(Map.Entry<String, String> entry : map.entrySet()){
System.out.println(entry.getKey() + "---" + entry.getValue());
}
//4 判断
System.out.println(map.containsKey("cn"));//true
System.out.println(map.containsValue("法国"));//false
}
Map实现类
- HashMap【重点】
- JDK1.2版本,线程不安全,运行效率快;允许用null作为Key或Value。
- Hashtable
- JDK1.0版本,线程安全,运行效率慢;不允许用null作为Key或Value。
- Properties
- Hashtable 子类,要求Key和Value都是String;通常用于资源或配置文件的读写。
- TreeMap
- 实现了SortedMap接口(是Map的子接口),可以对Key自动排序。
HashMap
public static void main(String[] args) {
//HashMap集合的使用
//存储结构:哈希表=数组+链表+红黑树
//使用key的hashcode和equals作为重复依据
//创建集合
HashMap<Student,String> hashMap=new HashMap<>();
Student s1=new Student("aaa",11);
Student s2=new Student("bbb",14);
Student s3=new Student("ccc",17);
//1 添加数据
hashMap.put(s1,"北京");
hashMap.put(s2,"上海");
hashMap.put(s3,"杭州");
System.out.println("数据个数:"+hashMap.size());//数据个数:3
System.out.println(hashMap.toString());
//{Student{name='ccc', stuNo=17}=杭州, Student{name='bbb', stuNo=14}=上海, Student{name='aaa', stuNo=11}=北京}
hashMap.put(new Student("ccc",17),"唐山");//要想这个加不进集合,就要重写hashcode和equals
//System.out.println("数据个数:"+hashMap.size());//数据个数:4
System.out.println("数据个数:"+hashMap.size());//数据个数:3 重写后就无法添加了!
//2 删除数据
//hashMap.remove(s1);
//hashMap.clear();
//3 遍历
//3.1 使用KeySet()
for(Student key : hashMap.keySet()){
System.out.println(key + "---" + hashMap.get(key));
}
//3.2 使用entrySet()
for(Map.Entry<Student, String> entry : hashMap.entrySet()){
System.out.println(entry.getKey() + "---" + entry.getValue());
}
//4 判断
System.out.println(hashMap.containsKey(s1));//true
System.out.println(new Student("aaa",11));//因为重写hashcode和equals true
System.out.println(hashMap.containsValue("武汉"));//false
}
public class Student {
@Override
public boolean equals(Object obj){
//1 判断是不是同一个对象
if(this == obj){
return true;
}
//2 判断是否为空
if(obj == null){
return false;
}
//3 判断obj是否是Student类型
if(obj instanceof Student){
Student s = (Student)obj;
//4 比较属性
if(this.name.equals(s.getName()) && this.stuNo == s.getStuNo()){
return true;
}
}
//5 不满足条件返回false
return false;
}
@Override
public int hashCode() {
int n1=this.name.hashCode();
int n2=this.stuNo+31;
return n1+n2;
}
}
源码分析总结:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//hashMap初始容量大小
static final int MAXIMUM_CAPACITY = 1 << 30;//hashMap的数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子
static final int TREEIFY_THRESHOLD = 8;//jdk1.8 当链表长度大于8时,调整为红黑树
static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8 当链表长度小于6时,调整为链表
static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8 当链表长度大于8时,并且集合元素个数大于等于64时,调整为红黑树
transient Node<K,V>[] table;//哈希表中的数组
transient int size;//元素个数
- HashMap刚创建时,table是null,是为了节省空间。当添加第一个元素时,table容量调整为16。
- 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的2倍,目的是减少调整元素的个数。
- jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整为红黑树,目的是提高效率。
- jdk1.8 当链表长度 <6 时,调整成链表。
- 在jdk1.8 以前,链表时头插入,之后为尾插入。
注意:HashSet 内部用的就是HashMap。
TreeMap
存储结构:红黑树;可以对key自动排序。
public static void main(String[] args) {
//TreeMap的使用
TreeMap<Student,String> treeMap=new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n2=o1.getStuNo()-o2.getStuNo();
return n2;
}
});
Student s1=new Student("aaa",11);
Student s2=new Student("bbb",14);
Student s3=new Student("ccc",17);
//1 添加数据
treeMap.put(s1,"南宁");
treeMap.put(s2,"上海");
treeMap.put(s3,"杭州");
System.out.println("数据个数:"+treeMap.size());//数据个数:3
System.out.println(treeMap.toString());
//{Student{name='aaa', stuNo=11}=南宁, Student{name='bbb', stuNo=14}=上海, Student{name='ccc', stuNo=17}=杭州}
treeMap.put(new Student("ccc",17),"武汉");
System.out.println(treeMap.toString());
//{Student{name='aaa', stuNo=11}=南宁, Student{name='bbb', stuNo=14}=上海, Student{name='ccc', stuNo=17}=武汉}
//2 删除数据
//treeMap.remove(s1);
//treeMap.clear();
//treeMap.remove(new Student("ccc",17));//可以删除s3
//3 遍历
//3.1 使用KeySet()
for(Student key : treeMap.keySet()){
System.out.println(key + "===" + treeMap.get(key));
}
//3.2 使用entrySet()
for(Map.Entry<Student, String> entry : treeMap.entrySet()){
System.out.println(entry.getKey() + "===" + entry.getValue());
}
//4 判断
System.out.println(treeMap.containsKey(s1));//true
System.out.println(new Student("aaa",11));//true
System.out.println(treeMap.containsValue("重庆"));//false
}
注意:TreeSet 内部用的就是TreeMap!!
七、Collections工具类
概念:集合工具类,定义了除了存取以外的集合常用方法。
方法 | 作用 |
---|---|
public static void reverse(List<?> list) | 反转集合中元素的顺序 |
public static void shuffle(List<?> list) | 随机重置集合元素的顺序 |
public static void sort(List< T> list) | 升序排序(元素类型必须实现Comparable接口) |
public static void main(String[] args) {
//Collections工具类的使用
List<Integer> list=new ArrayList<>();
list.add(20);
list.add(5);
list.add(12);
list.add(30);
list.add(6);
//sort排序
System.out.println("排序之前"+list.toString());//排序之前[20, 5, 12, 30, 6]
Collections.sort(list);
System.out.println("排序之后"+list.toString());//排序之后[5, 6, 12, 20, 30]
//二分查找binarySearch 必须要先排序
//若找到了,值大于0;反之则小于0
System.out.println(Collections.binarySearch(list,12));//2
System.out.println(Collections.binarySearch(list,14));//-4
//copy复制 前提是两个数组大小相等
List<Integer> dest=new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
dest.add(0);
}
Collections.copy(dest,list);
System.out.println(dest.toString());//[5, 6, 12, 20, 30]
//反转reverse
Collections.reverse(list);
System.out.println("反转之后:"+list.toString());//反转之后:[30, 20, 12, 6, 5]
//shuffle打乱
Collections.shuffle(list);
System.out.println("打乱之后:"+list.toString());//打乱之后:[20, 12, 6, 30, 5]
//补充
//list转成数组
Integer[] arr = list.toArray(new Integer[10]);
System.out.println(arr.length);//10
System.out.println(Arrays.toString(arr));//[20, 12, 6, 30, 5, null, null, null, null, null]
//数组转成集合
//此时为受限集合,不能进行添加和删除操作!!
String[] name = {"张三","李四","王五"};
List<String> list2 = Arrays.asList(name);
System.out.println(list2.toString());//[张三, 李四, 王五]
//把基本类型数组转为集合时,需要修改为包装类
Integer[] nums = {100, 200, 300, 400, 500};
List<Integer> list3 = Arrays.asList(nums);
System.out.println(list3.toString());//[100, 200, 300, 400, 500]
}