集合
一.Collection接口
1.1 Collection的常用方法
public class CollectionTest01 {
public static void main(String[] args) {
//Collection 是所有 集合的父接口 ,是 Iterable 的子接口
//学习各种集合之前先了解Collection的常用方法
//Collection是接口,完全抽象的不能new对象
//Collection collection =new Collection();//'Collection' is abstract; cannot be instantiated
//多态
//创建了一个ArrayList的集合对象
Collection arrayList =new ArrayList();
//boolean add(Object e) 向集合中添加元素
//集合中不能直接存储基本类型结构,也不能存储java对象,只是存储java对象的内存地址
arrayList.add(123);//自动装箱,变成了Integer对象
arrayList.add(true);//自动装箱
arrayList.add("????");//String对象
arrayList.add(new m());//m对象
arrayList.add(new Object());//Object 对象
//int size() 获取集合中元素个数
//不是集合长度,是集合内部元素的个数
System.out.println("arrayList里面有" + arrayList.size() + "个元素");//arrayList里面有5个元素
//boolean contains(Object o) 集合是否包含某元素
System.out.println("arrayList里面有123? " +arrayList.contains(123));//arrayList里面有123? true
System.out.println("arrayList里面有456? " +arrayList.contains(456));//arrayList里面有456? false
//boolean remove(Object o) 从集合类删除某个元素
//先删除123
arrayList.remove(123);
System.out.println("arrayList里面有" + arrayList.size() + "个元素");//arrayList里面有4个元素
System.out.println("arrayList里面有123? " +arrayList.contains(123));//arrayList里面有123? false
//Object[] toArray() 把集合转化成数组
Object[] objects = arrayList.toArray();
//遍历
for (Object o : objects){
System.out.print(o + " ");//true ???? caopeng.bolgTest.m@668bc3d5 java.lang.Object@3cda1055
}
System.out.println();
//boolean isEmpty() 判断集合中的元素是否为0
System.out.println("arrayList里面的元素个数是否为零 " + arrayList.isEmpty());//arrayList里面的元素个数是否为零 false
//void clear() 移除集合中所有元素
arrayList.clear();
System.out.println("arrayList里面的元素个数是否为零 " + arrayList.isEmpty());//arrayList里面的元素个数是否为零 true
}
}
class m{
}
1.2 Collection的迭代
//关于集合的遍历/迭代专题
public class CollectionTest02 {
public static void main(String[] args) {
//注意:以下讲解的遍历方式/迭代方式,所有Collection通用的一种方式
//在Map集合不可用,在所有的Collection以及子类中使用
//创建集合对象
Collection arrayList =new ArrayList();//ArrayList是有序可重复,放进去和取出来是一样的顺序
//添加集合元素
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
arrayList.add("4");
arrayList.add("5");
arrayList.add(new Object());
arrayList.add("abc");
//遍历/迭代集合
Iterator iterator = arrayList.iterator();
/*
以下两个方法是迭代器Iterator中的方法:
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
Object next() 返回迭代的下一个元素。
*/
while (iterator.hasNext()){
Object o = iterator.next();
System.out.println(o);
/*1
2
3
4
5
java.lang.Object@2d209079
abc
*/
}
/*//如果一直循环
//java.util.NoSuchElementException
while(true){
Object o = iterator.next();
System.out.println(o);
}*/
//再来试一下Set的迭代
Collection hashSet= new HashSet();//HashSet 无序不可重复,存进去这个顺序,取出来就不一定这个顺序了
hashSet.add(10);
hashSet.add(20);
hashSet.add(30);
hashSet.add(30);
hashSet.add(40);
hashSet.add(20);
hashSet.add(10);
//迭代
Iterator iterator1 = hashSet.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
/*
20
40
10
30
*/
}
}
}
1.3 Collection方法中contains方法深入
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
/*深入Collection的contains方法
* * boolean contains(Object o) 集合是否包含某元素
* 底层调用了equals方法
* 放在集合里面的类型要重写equals方法
*/
public class CollectionTest03 {
public static void main(String[] args) {
Collection arrayList = new ArrayList();
String str1 = "abc";
String str2 = "def";
arrayList.add(str1);
arrayList.add(str2);
//集合中元素的个数
System.out.println(arrayList.size());//2
String str3 =new String("abc");
//很明显 str3和 str1 的内存地址肯定不同
//所以contains底层调用了equals方法
System.out.println(arrayList.contains(str3));//true
//创建两个学生对象
Student student1 = new Student("钢铁侠");
Student student2 = new Student("钢铁侠");
//清空集合
arrayList.clear();
arrayList.add(student1);
//重写equals方法之前
//System.out.println(arrayList.contains(student2));//false
//student1 和 student2名字一样,我们可以认为是一个学生,所以这里达不到我们的要求
//我们就要在Student类里面重写equals方法
System.out.println(arrayList.contains(student2));//true
//remove()
arrayList.remove(student2);
//删除arrayList中的student2,但是student1没了,表示remove()方法底层调用的也是equals()方法
System.out.println(arrayList.size());//0
}
}
//Student类
class Student{
private String name;
//构造方法
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
}
1.4 Collection方法中remove()方法深入
public class CollectionTest04 {
public static void main(String[] args) {
Collection arrayList = new ArrayList();
//如果集合机构发生了改变,但是不重新获取新的迭代器就会:
//java.util.ConcurrentModificationException
//Iterator iterator = arrayList.iterator();
arrayList.add("abc");
arrayList.add("def");
//获取迭代器
Iterator iterator = arrayList.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//在迭代元素的过程中,不能调用集合对象的remove()方法
Collection arrayList1 =new ArrayList();
arrayList1.add(123);
arrayList1.add(456);
arrayList1.add(789);
/*//迭代
Iterator iterator1 = arrayList1.iterator();
while(iterator1.hasNext()){
System.out.println(iterator1.next());
//ConcurrentModificationException
//arrayList1.remove(123);
}*/
//解决办法:
Iterator iterator1 = arrayList1.iterator();
while (iterator1.hasNext()){
Object object = iterator1.next();
//iterator1.remove(456);//直接通过集合删除元素,没有通知迭代器(导致迭代器的快照和元集合状态不同)
iterator1.remove();//删除的一定是当前元素
System.out.println(object);
}
System.out.println(arrayList1.size());//0 删除干净了
}
}
二.泛型
泛型的优点:
* 第一:集合中存储的元素更加统一
* 第二:从集合中取出的元素是泛型指定的类型,不需要进行大量的“向下转型”
*
* 缺点:
* 导致集合中存储的元素缺乏多样性
*
* 实际开发中,其实主要是同一种类型
*
* 但是如果是子类的特有方法,还是要向下转型
2.1 泛型的基础语法
public class GenericTest01 {
public static void main(String[] args) {
Animal animal =new Animal();
Bird bird =new Bird();
Cat cat =new Cat();
//使用了泛型,那么 arrayList 这个集合只能放 Animal 类的元素
Collection<Animal> arrayList = new ArrayList<Animal>();
arrayList.add(animal);
arrayList.add(bird);
arrayList.add(cat);
//arrayList.add("123");报错
//迭代
//记住这里也要泛型,表示迭代器迭代的是Animal类型
Iterator<Animal> iterator = arrayList.iterator();
while(iterator.hasNext()){
iterator.next().move();
}
/*Animal is moving
Bird is moving
Cat is moving
*/
}
}
class Animal{
public void move(){
System.out.println("Animal is moving");
}
}
class Cat extends Animal{
@Override
public void move() {
System.out.println("Cat is moving");
}
public void catMouse(){
System.out.println("猫抓老鼠!!!");
}
}
class Bird extends Animal{
@Override
public void move() {
System.out.println("Bird is moving");
}
public void fly(){
System.out.println("鸟儿在飞翔!!!");
}
}
2.2泛型的自动类型推断机制(钻石表达式)
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class GenericTest02 {
public static void main(String[] args) {
//ArrayList<这里的类型会只动推断>,JDK8之后才允许
//自动类型推断
Collection<Animal> arrayList = new ArrayList<>();
arrayList.add(new Animal());
arrayList.add(new Cat());
arrayList.add(new Bird());
//迭代
Iterator<Animal> iterator =arrayList.iterator();
while(iterator.hasNext()){
iterator.next().move();
}
/*Animal is moving
Cat is moving
Bird is moving
*/
}
}
2.3 自定义泛型
/*
* 自定义泛型
* < > 里面是一个标识符
* java中经常出现是
* <E>和<T>
E是Element首字母
T是Typ首字母
* */
public class GenericTest03 <E>{
public void dosome(E abc){
System.out.println("dosome ...");
}
public static void main(String[] args) {
GenericTest03<String> genericTest03 =new GenericTest03<>();
genericTest03.dosome("???");
//genericTest03.dosome(123);只能是String类型
GenericTest03<Integer> genericTest031 = new GenericTest03<>();
genericTest031.dosome(123);
}
}
三.增强For循环
//JDK5.0之后推出了一个新特性:增强for循环,或者叫for each
//缺点:没下标,在需要使用下标的时候不建议使用增强for循环
public class ForEachTest01 {
public static void main(String[] args) {
//创建数组
int[] array = {1,2,3,4,5};
//创建集合
Collection arrayList =new ArrayList();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
//遍历数组
for (int i:array){
System.out.print(i + " ");
}
System.out.println();
//遍历集合
for (Object o : arrayList){
System.out.print(o + " ");
}
}
}
四.List接口
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
/*
* 测试list接口常用方法
* 1.list集合存储元素特点:有序可重复
* 有序:list集合元素有下标
* 从零开始以一递增
* 可重复:存储了一个1还可以再存储一个1
* 2.list既是Collection接口的子接口,那么肯定有list接口自己的特有的方法
* 以下只列出list接口常见特有的方法:
* void add(int index, Object element) 在列表的指定位置插入指定元素(可选操作)。
* Object get(int index) 返回列表中指定位置的元素
* int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
* int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
* Object remove(int index) 移除列表中指定位置的元素(可选操作)
* Object set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。
* */
public class ListTest {
public static void main(String[] args) {
//创建集合对象
List linkedList= new LinkedList();
List vector= new Vector();
List arrayList = new ArrayList();
//添加元素
arrayList.add("A");//默认添加到最后一项
arrayList.add("B");//默认添加到最后一项
arrayList.add("D");//默认添加到最后一项
//void add(int index, Object element) 在列表的指定位置插入指定元素(可选操作)。
arrayList.add(2,"C"); // 添加到指定位置
//Object get(int index) 返回列表中指定位置的元素
System.out.println(arrayList.get(3));//D
/*
* int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
* int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
* */
arrayList.add("D");
arrayList.add("C");
arrayList.add("B");
arrayList.add("A");
System.out.println(arrayList.indexOf("A"));//0
System.out.println(arrayList.indexOf("F"));//-1
System.out.println(arrayList.lastIndexOf("A"));//7
System.out.println(arrayList.lastIndexOf("F"));//-1
//Object remove(int index) 移除列表中指定位置的元素(可选操作)
arrayList.remove(0);
//Collection 还有remove(Object o)方法,删除元素
System.out.println(arrayList.get(0));//B A被删除了
//Object set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。
for (Object o : arrayList){
System.out.print(o + " ");//B C D D C B A
}
arrayList.set(0,"A");
System.out.println();
for (Object o : arrayList){
System.out.print(o + " ");//A C D D C B A
}
}
}
五.ArrayList集合
public class ArrayListTest01 {
public static void main(String[] args) {
//构造方法
//默认容量是10
ArrayList arrayList1 =new ArrayList();
////指定初始化容量
ArrayList arrayList2 =new ArrayList(100);
//public ArrayList(Collection c)
// 构造一个包含指定 collection 的元素的列表
// 这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
//创建一个HashSet集合
Collection hashSet= new HashSet();
hashSet.add(1);
hashSet.add(2);
hashSet.add(3);
ArrayList arrayList =new ArrayList(hashSet);
//遍历
for (int i = 0; i <arrayList.size() ; i++) {
System.out.print(arrayList.get(i) + " ");//1 2 3
}
}
}
六.LinkedList集合
6.1 模拟单向链表
//模拟单链表
//链表的基本单元的Node
//对于单向链表来说:Node中存储了当前节点的数据,以及下一节点的内存地址
public class Node {
//存储的数据
Object element;
//下一节点的内存地址
Node next;
//构造方法
public Node() {
}
public Node(Object element, Node next) {
this.element = element;
this.next = next;
}
}
//单向链表类
public class Link {
//头节点
Node heard = null;
//size
int size = 0;
public int size(){
return this.size;
}
//向链表末尾中添加元素
public void add(Object o){
//判断是否是头文件
if (heard == null){
heard = new Node(o,null);
}else{
//头不是空
//找出当时的末尾节点
Node currentNode = findCurrentNode(heard);
currentNode = new Node(o,null);
}
size ++;
}
/**
*
* @param node 起始节点
* @return 末尾节点
*/
public Node findCurrentNode(Node node) {
//递归
if (node.next == null){
return node;
}else {
return findCurrentNode(node.next);
}
}
}
public class LinkTest {
public static void main(String[] args) {
Link myLink = new Link();
myLink.add(1);
myLink.add(2);
myLink.add(3);
myLink.add(4);
myLink.add(5);
//元素个数
System.out.println(myLink.size);
}
}
6.2 LinkedList
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/*
* 链表的优点:
* 由于链表上的元素在空间上的内存地址不连续
* 因为随机增删的时候不会有大量的元素位移,因此随机增删效率较高
* 在以后的开发中,如果遇到随机增删集合中的元素业务较多时,建议使用LinkedList
* */
public class LinkedListTest {
public static void main(String[] args) {
//创建一个LinkedList对象
List linkedList= new LinkedList();
//添加元素
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(4);
linkedList.add(5);
//遍历
//for each
for(Object o:linkedList){
System.out.print(o + " ");
}
System.out.println();
//迭代器迭代
Iterator iterator = linkedList.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
System.out.println();
////LinkedList集合底层也是有下标的
//注意:ArrayList之所以检索效率高,不单是因为有下标,主要是底层是数组的原因
//LikedList集合照样有下标,但是检索/查找效率某个元素效率比较低,因为只能从头节点开始一个一个遍历
//下标循环
for (int i = 0; i <linkedList.size() ; i++) {
System.out.print(linkedList.get(i) + " ");
}
//LinkedList集合有初始化吗?没有
//最初这个链表中没有任何元素,first和last引用都是null
//不管是LikedList还是ArrayList,以后写代码不需要关系具体是哪个
//因为我们要面向接口编程,调用的方法都是接口中的方法
//List list2 = new ArrayList();//这样写表示调用了数组
List list2 = new LinkedList();//这样写表示底层调用了双向链表
list2.add("123");
list2.add("456");
list2.add("789");
for (int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
七.Vector集合
import java.util.*;
/*
* Vector:
* 1.底层也是一个数组
* 2.初始化容量:10
* 3.扩容之后是原来的二倍
* ArrayList是原来的1.5倍
* 4.Vector的方法都带 synchronized 关键字,线程安全,效率较低
* 6.怎么将一个线程不安全的ArrayList转换成线程安全的Vector?
* 使用集合工具类:
* Java.util.Collections
*
* java.util.Collection是集合接口
* java.util.Collections是集合工具类
* */
public class VectorTest{
public static void main(String[] args) {
//多态
Collection vector= new Vector();
//添加元素
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
//遍历/迭代
Iterator iterator =vector.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
//Vector 是线程安全的
//ArrayList不是线程安全的
//怎么将ArrayList变成线程安全的呢?
List arrayList = new ArrayList();
//集合工具类
Collections.synchronizedList(arrayList);
//现在 arrayList 是线程安全的了
}
}
八.Set接口
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
//Set是Collection的子接口,不能new set对象
//'Set' is abstract; cannot be instantiated
//Set set =new Set();
Set hashSet= new HashSet();
}
}
九.HashSet集合
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*
* HashSet集合:
* 无序不可重复
* */
public class HashSetTest {
public static void main(String[] args) {
Set<Integer> hashSet = new HashSet<>();
hashSet.add(3);
hashSet.add(1);
hashSet.add(2);
hashSet.add(5);
hashSet.add(8);
hashSet.add(4);
hashSet.add(3);
hashSet.add(1);
hashSet.add(3);
//遍历
Iterator iterator= hashSet.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " " );
}
}
}
十.TreeSet集合
10.1 TreeSet集合的基础语法
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
/*
* TreeSet集合存储元素特点:
* 1.无序不可重复,但是存储的元素可以自动按照大小排序
* 称为:可排序集合
* 2.无序:这里的无序是指存进去的顺序和取出来的顺序不同,且没有下标
* 3.TreeSet底层实际上是一个TreeMap
* 4.TreeMap底层是一个二叉树
* 5.放到TreeSet集合里的元素,等同于放到TreeMap集合的key里面
* 6.TreeSet集合中的元素:无序不可重复,但是按着元素的大小排序
* 称为:可排序集合*/
public class TreeSetTest01 {
public static void main(String[] args) {
Set treeSet= new TreeSet<>();
treeSet.add(10);
treeSet.add(5);
treeSet.add(20);
treeSet.add(1);
//迭代
Iterator iterator =treeSet.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");//1 5 10 20 排序了
}
System.out.println();
treeSet.clear();
treeSet.add("A");
treeSet.add("Z");
treeSet.add("B");
treeSet.add("F");
treeSet.add("D");
treeSet.add("H");
for (Object o :treeSet){
System.out.print(o + " ");//A B D F H Z 小到大的排序
}
}
}
10.2 自定义类在TreeSet里怎么排序
第一种方法:
`import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest03 {
public static void main(String[] args) {
//创建顾客对象
Customer customer1 =new Customer(1);
Customer customer2 =new Customer(2);
Customer customer3 =new Customer(3);
Customer customer4 =new Customer(4);
Customer customer5 =new Customer(5);
//创建TreeSet对象
TreeSet<Customer> treeSet =new TreeSet<>();
//添加元素
treeSet.add(customer1);
treeSet.add(customer2);
treeSet.add(customer3);
treeSet.add(customer4);
treeSet.add(customer5);
//迭代
Iterator<Customer> iterator = treeSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
/*Customer{age=1}
Customer{age=2}
Customer{age=3}
Customer{age=4}
Customer{age=5}
*/
}
}
//放在TreeSet集合中的元素要实现java.lang.Comparable接口
//并且实现compareTo方法,equals可以不重写
//这里要泛型,要不然下面会报错
class Customer implements Comparable<Customer>{
int age;
public Customer(){
}
public Customer(int age){
this.age = age;
}
//需要在这个方法中编写比较的逻辑
//k.compareTo(t.key)
//拿着参数k和集合的每一个key比较,返回值可能是大于零,可能是小于零,可能是等于零
//比较规则还是由程序员来定
@Override
public int compareTo(Customer c) {
/*if (this.age == c.age){
return 0;
}else if (this.age >c.age){
return 1;
}else if (this.age < c.age){
return 1;
}*/
return this.age -c.age;
}
//重写toString方法
@Override
public String toString() {
return "Customer{" +
"age=" + age +
'}';
}
}
`
import java.util.TreeSet;
public class TreeSetTest04 {
public static void main(String[] args) {
//创建Vip对象
Vip vip1 =new Vip(10,"A");
Vip vip2 =new Vip(20,"A");
Vip vip3 =new Vip(10,"Z");
Vip vip4 =new Vip(30,"Z");
Vip vip5 =new Vip(15,"D");
//创建集合对象
TreeSet<Vip> treeSet =new TreeSet<>();
//添加元素
treeSet.add(vip1);
treeSet.add(vip2);
treeSet.add(vip3);
treeSet.add(vip4);
treeSet.add(vip5);
//遍历
for (Vip vip : treeSet){
System.out.println(vip);
}
/*Vip{age=10, name='A'}
Vip{age=10, name='Z'}
Vip{age=15, name='D'}
Vip{age=20, name='A'}
Vip{age=30, name='Z'}
*/
}
}
//先按照年龄升序,如果年龄一样在按着姓名升序
class Vip implements Comparable<Vip>{
private int age;
private String name;
//构造方法
public Vip() {
}
public Vip(int age, String name) {
this.age = age;
this.name = name;
}
//实现 compareTo 方法
@Override
public int compareTo(Vip o) {
if (this.age == o.age){
//String类实现了 compareTo 方法
return this.name.compareTo(o.name);
}else {
return this.age - o.age;
}
}
@Override
public String toString() {
return "Vip{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
第二种方法:
import java.util.Comparator;
import java.util.TreeSet;
//TreeSet集合元素可排序的第二种方式:使用比较器的方式
/*放到TreeSet或者TreeMap集合key部分的元素想要做到排序,有两种方式:
* 第一种:放在集合中的元素实现 java.lang.Comparable接口
* 第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
* Comparable和Comparator怎么选择?
* 如果比较规则一直不变的话,或者比较规则只有一个:Comparable
* 如果比较规则经常改变的话,或者比较规则有多个 :Comparator*/
public class TreeSetTest05 {
public static void main(String[] args) {
//给构造方法传一个比较器
//TreeSet<AnimalTest> testTreeSet = new TreeSet<>(new AnimalTestComparator());
//或者用匿名内部类
TreeSet<AnimalTest> testTreeSet = new TreeSet<>(new Comparator<AnimalTest>() {
@Override
public int compare(AnimalTest o1, AnimalTest o2) {
return o1.getNo() - o2.getNo();
}
});
//创建AnimalTest对象
AnimalTest animalTest1 =new AnimalTest(10);
AnimalTest animalTest2 =new AnimalTest(5);
AnimalTest animalTest3 =new AnimalTest(15);
AnimalTest animalTest4 =new AnimalTest(1);
AnimalTest animalTest5 =new AnimalTest(20);
//添加元素
testTreeSet.add(animalTest1);
testTreeSet.add(animalTest2);
testTreeSet.add(animalTest3);
testTreeSet.add(animalTest4);
testTreeSet.add(animalTest5);
for (AnimalTest a:testTreeSet){
System.out.println(a);
}
/*AnimalTest{no=1}
AnimalTest{no=5}
AnimalTest{no=10}
AnimalTest{no=15}
AnimalTest{no=20}
*/
}
}
class AnimalTest{
private int no;
public AnimalTest() {
}
public AnimalTest(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
@Override
public String toString() {
return "AnimalTest{" +
"no=" + no +
'}';
}
}
/*
//单独编写一个比较器
//比较器实现java.util.Comparator接口。(Comparable是java.lang包下的)
class AnimalTestComparator implements Comparator<AnimalTest>{
@Override
//比较方法
public int compare(AnimalTest o1, AnimalTest o2) {
return o1.getNo() - o2.getNo();
}
}*/
十一.Map接口
11.1 Map集合的常用方法
/*
* java.util.Map接口中常用的方法:
* 1.Map和Collection没有继承关系
* 2.Map集合以key和value的方式存储数据:键值对
* key和value都是引用数据类型
* key和value都是存储对象的内存地址
* key起主导作用,value是key的一个附属品
* 3.Map集合中常用方法
V put(K key, V value) 向Map集合中添加键值对
V get(Object key) 通过key获取value
void clear() 清空Map集合
boolean containsKey(Object key) 判断Map集合中是否包含某个key
boolean containsValue(Object value) 判断Map集合中是否包含某个Value
boolean isEmpty() 判断Map结合中的元素个数是否为零
Set<K> keySet() 获取Map集合中所有的key(所有的键是一个set集合)
V remove(Object key) 通过key删除Value
int size() 获取Map集合中键值对的个数
Collection<V> values() 获取Map集合中所有的value,返回一个Collection
Set<Map.Entry<K,V>> entrySet() 将Map集合转化成Set集合
*
*/
public class MapTest01 {
public static void main(String[] args) {
//Map 也是一个接口
//'Map' is abstract; cannot be instantiated
//Map map =new Map();
//泛型,创建集合对象
Map<Integer,String> hashMap= new HashMap<>();
//向集合中添加元素
//V put(K key, V value) 向Map集合中添加键值对
hashMap.put(1,"钢铁侠");//1 在这自动装箱了
hashMap.put(2,"雷神");
hashMap.put(3,"美队");
hashMap.put(4,"绿巨人");
//boolean containsKey(Object key) 判断Map集合中是否包含某个key
System.out.println(hashMap.containsKey(1));//true
System.out.println(hashMap.containsKey(10));//false
//boolean containsValue(Object value) 判断Map集合中是否包含某个Value
System.out.println(hashMap.containsValue("钢铁侠"));//true
System.out.println(hashMap.containsValue("蜘蛛侠"));//false
//Set<K> keySet() 获取Map集合中所有的key(所有的键是一个set集合)
Set set = hashMap.keySet();
System.out.println(set.size());//4
//遍历这个set集合
for (Object o : set) {
System.out.println(set);
/*[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
*/
}
//Collection<V> values() 获取Map集合中所有的value,返回一个Collection
Collection c = hashMap.values();
//遍历集合
Iterator iterator =c.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
/*钢铁侠
雷神
美队
绿巨人
*/
//Set<Map.Entry<K,V>> entrySet() 将Map集合转化成Set集合
Set set1 = hashMap.entrySet();
System.out.println(set.size());//4
//遍历这个set集合
for (Object o : set) {
System.out.println(set1);
}
/*[1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
[1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
[1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
[1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
*/
// V get(Object key) 通过key获取value
System.out.println(hashMap.get(1));//钢铁侠
System.out.println(hashMap.get(2));//雷神
//int size() 获取Map集合中键值对的个数
System.out.println(hashMap.size());//4
//V remove(Object key) 通过key删除Value
hashMap.remove(1);
System.out.println(hashMap.size());//3
System.out.println(hashMap.containsKey(1));//false
//boolean isEmpty() 判断Map结合中的元素个数是否为零
System.out.println(hashMap.isEmpty());//false
//void clear() 清空Map集合
hashMap.clear();
System.out.println(hashMap.isEmpty());//true
}
}
11.2 Map集合的遍历
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
Map集合的遍历(非常重要)
*/
public class MapTest02 {
public static void main(String[] args) {
Map<Integer,String> hashMap = new HashMap<>();
hashMap.put(1,"钢铁侠");//1 在这自动装箱了
hashMap.put(2,"雷神");
hashMap.put(3,"美队");
hashMap.put(4,"绿巨人");
//第一种方式:获取所有的key,遍历key,来遍历所有的value
//先获取所有的key,所有的key是一个Set集合
Set<Integer> hashSet= hashMap.keySet();
//可以用迭代器
Iterator iterator = hashSet.iterator();
while(iterator.hasNext()){
Object o = iterator.next();
String s =hashMap.get(o);
System.out.println(s);
}
System.out.println("================================");
//还可以用for each 循环
for(Object o : hashSet){
System.out.println(hashMap.get(o));
}
System.out.println("================================");
//第二种方式
//Set<Map.Entry<K,V>> entrySet() 将Map集合转化成Set集合
//Set集合中元素的类型是: Map.Entry
Set<Map.Entry<Integer,String>> set = hashMap.entrySet();
//遍历Set集合,每一次取出一个Node
//可以用迭代器迭代
Iterator<Map.Entry<Integer,String>> iterator1 = set.iterator();
while(iterator1.hasNext()){
Map.Entry<Integer,String> entry = iterator1.next();
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " = " + value);
}
System.out.println("================================");
for (Map.Entry<Integer,String> node : set){
System.out.println(node.getKey() + " = " + node.getValue());
}
}
}
十二.HashMap集合
12.1 HashMap中get和put方法
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
* HashMap集合:
* 1.HashMap集合底层是哈希表/散列表的数据结构
* 2.哈希表是一个数组和单向链表的结合体
* 数组:在查询方面效率很高
* 单向链表:在随机增删方面效率很高
* 哈希表将以上两种数据结构融合在一起了,充分发挥了他们各自的优点
* 3.HashMap底层代码:
* public class HashMap{
*
* //HashMap底层实际上是一个数组(一维数组)
* transient Node<K,V>[] table;
*
* //静态内部类HashMap.Node
* static class Node<K,V> implements Map.Entry<K,V>{
final int hash;//哈希值(哈希值是key的hashCode()方法执行的结果,hash值通过哈希函数/算法,可以转化成数组的数组的下标)
final K key; //Map集合的key
V value; //Map集合的value
Node<K,V> next;//下一个节点的内存地址
* }
*
*
* 哈希表/散列表:一维数组,这个数组里面的每一个元素是一个单向列表(数组和链表的结合体)
*
* 4.最主要掌握:
* map.put(key,value)
* value = map.get(k)
* 这两个方法的原理
*
* 5.HashMap集合的key部分特点:
* 无序不可重复
* 无序? 因为不一定挂在哪个单向链上
* 不可重复?equals方法来保证HasMap集合的key不可重复
* 如归key重复了,value会被覆盖
*
* 放在HashSet的元素实际上是放到了HashMap的集合key部分中了
* 所以HashSet也要重写equals和HashCode
* 6.HashMap使用不当时无法发挥性能
* 假设将所有的HashCode()方法返回固定值,那么就会导致底层哈希表变成纯单向链表
* 称为 散列分布不均匀
* * 假设将所有的HashCode()方法返回不同值,那么就会导致底层哈希表变成一维数组
也是 散列分布不均匀
散列分布均匀 需要重写HashCode()有技巧
7.重点:
放在HashMap集合中key部分的元素,以及放在HashSet中的元素,需要重写HashCode和equal方法
8.HashMap集合的默认容量是16,默认加载因子是0.75
* 这个默认加载因子是当HashSet集合底层数组容量达到75%时开始扩容
* 重点:HashMap集合初始化容量必须是2的倍数,这是官方推荐的
* 这是因为达到散列分布均匀,为了提高HashMap集合的存取效率所必须的
*/
public class HashMapTest01 {
public static void main(String[] args) {
//测试HashMap集合key部分元素特点
//Integer是key,它的HashCode和equals方法都已经重写了
Map<Integer,String> hashMap= new HashMap<>();
hashMap.put(1,"钢铁侠");//1 在这自动装箱了
hashMap.put(2,"雷神");
hashMap.put(3,"美队");
hashMap.put(3,"绿巨人");
System.out.println(hashMap.size());//3
//遍历
Set<Map.Entry<Integer,String>> set = hashMap.entrySet();
Iterator<Map.Entry<Integer,String>> iterator = set.iterator();
while(iterator.hasNext()){
Map.Entry<Integer,String> entry = iterator.next();
System.out.println(entry.getKey() + " = " + entry.getValue());
}
//可知,原来的美队被覆盖了
/*1 = 钢铁侠
2 = 雷神
3 = 绿巨人
*/
}
}
12.2 自定义类在HashMap中get和put
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
/*1. 向Map集合中 存和取 都是先调用key的HashCode方法,然后再调用equals方法
* equals方法可能调用,可能不调用
* 拿put(k,v)举例,什么时候不调用equals
* k.HashCode()方法返回哈希值,
* 哈希值是经过哈希算法得出数组下标
* 数组下标位置上如果是null,就不会调用equals
*
* 拿get(k)举例,什么时候不调用equals
* 哈希值是经过哈希算法得出数组下标
* 数组下标位置上如果是null,就不会调用equals
*
* 2. 注意:如果一个类的equals方法重写了,那么hashCode()必须重写
* 并且equals方法返回如果是true,呢么hashcode返回值必须一样
* equals方法返回true表示两个对象相同,在同一个单向链表上
* 对于同一个单向链表的节点来说,他们的哈希值都相同
* 使用hashCode的返回值也要是true
*
* 3.hashCode和equals直接用idea生成
*
*结论:
* 放在HashMap集合key部分和HashSet集合中的元素,要同时重写hashCode和equals方法
* */
public class HashMapTest02 {
public static void main(String[] args) {
People people1 =new People("钢铁侠",123);
People people2 =new People("钢铁侠",123);
//重写equals方法和hashCode方法之前
System.out.println(people1.equals(people2));//false
System.out.println(people1.hashCode());//1809787067
System.out.println(people2.hashCode());//1802598046
//重写equals,没重写hashCode
System.out.println(people1.equals(people2));//true
//HashSet存储在HashMap的key部分
HashSet<People> hashSet = new HashSet<>();
hashSet.add(people1);
hashSet.add(people2);
//按理来说,这两个对象equals返回true,应该是重复了,而HashSet集合无序不可重复
//应该只有一个元素
System.out.println(hashSet.size());//2
//这是因为这两个元素的 hash值不同,所以存储在数组的位置不同
//因此我们要重写hashCode方法
System.out.println(people1.hashCode());//1170776379
System.out.println(people2.hashCode());//1170776379
System.out.println(hashSet.size());//1
}
}
class People{
//属性
private String name;
private int no;
//构造方法
public People() {
}
public People(String name, int no) {
this.name = name;
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return no == people.no &&
Objects.equals(name, people.name);
}
@Override
public int hashCode() {
return Objects.hash(name, no);
}
}
十三.Hashtable集合
Hashtable是线程安全的,底层也是哈希表
十四.Properties集合
import java.util.Properties;
/*
* 目前只需要掌握Properties属性类的相关方法
* Properties是一个Map集合,继承HashTable,Properties的key和value都是String类型的
* Properties被称为属性类对象
* Properties是线程安全的
* */
public class PropertiesTest {
public static void main(String[] args) {
Properties properties =new Properties();
//Properties需要掌握两个方法,一个存一个取
properties.setProperty("123","钢铁侠");
properties.setProperty("456","蜘蛛侠");
System.out.println(properties.getProperty("123"));//钢铁侠
System.out.println(properties.getProperty("456"));//蜘蛛侠
}
}
十五.TreeMap集合
TreeMap底层是二叉树
TreeMap集合的key可以自动按照大小顺序排序。
总结(所有的实现类):
ArrayList:底层是数组。
LinkedList:底层是双向链表。
Vector:底层是数组,线程安全的,效率较低,使用较少。
HashSet:底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了。
TreeSet:底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了。
HashMap:底层是哈希表。
Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。
Properties:是线程安全的,并且key和value只能存储字符串String。
TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。
List集合存储元素的特点:
有序可重复
有序:存进去的顺序和取出的顺序相同,每一个元素都有下标。
可重复:存进去1,可以再存储一个1.
Set(Map)集合存储元素的特点:
无序不可重复
无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。
SortedSet(SortedMap)集合存储元素特点:
首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。
无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。
可排序:可以按照大小顺序排列。
Map集合的key,就是一个Set集合。
往Set集合中放数据,实际上放到了Map集合的key部分。
转载:https://blog.csdn.net/Destiny_159/article/details/105467943