java集合

java集合

1.java集合框架概述
(1)概述

集合、数组都是对多个数据进行存错操作的结构,简称java容器。此时的存储主要是内存层面的存储,不涉及到持久化的存储(.txt .jpg .avi 数据库中)

(2)数组在存储多个数据集方面的特点

①一旦初始化以后长度就确定了

②一旦定义好,其元素的类型也就确定了,我们也就只能操作指定类型的数据了,定义成Object[] o;类型可以使类型不再单一

(3)数组在存储多个数据方面的缺点

①一旦初始化以后长度就确定了,不可以再修改

②数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,效率低

③获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用

④数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,数组不能满足

(4)单列集合:Collection
1.说明

Collection接口:单列集合,用来存储一个一个的对象,他有两个子接口(List(动态数组、有序可重复):ArrayLsit、LinkedList、Vector,Set(无序、确定、不可重复):HashSet、LinkedHashSet、TreeSet)

(5)双列集合:Map
1.说明

Map接口:双列集合,用来存储一对一对(key-value一个key不能对应多个value,一个value可以对应多个key)的数据,每个元素都包含一对键值,Map接口的主要实现类有HashMap、TreeMap、LinkedMap、Properties,存储无序、不可重复的数据

(6)集合的赋值与输出遍历
//1。集合可以直接赋值
//2.直接输出可以一次输出集合中的全部元素,遍历输出每次输出一个元素
Set set1 = new HashSet();
set1.add(123);
set1.add(456);
set1.add(678);
Set set2 = new HashSet();
set2 = set1;
System.out.println(set2);
Iterator iterator = set2.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
2.Collcetion接口
(1)Collection常用方法

注:向Colletion接口的实现类的对象(coll)中添加数据对象(obj)时,要求obj所在类要重写equals()方法

1.boolean add(Object e):将元素e添加到集合coll中

2.boolean addAll(Collection c):将指定集合中的元素添加到集合中

3.toString():变量名:输出该集合中的元素

4.bollean isEmpty():判断当前集合是否为空(判断size是否为0)

5.boolean contains(Object o):判断该集合中是否包含某个元素,我们在判断时会调用obj所在类的equals()方法

6.bollean containsALL(Collection c):判断形参集合中的所有元素是否全部存在于当前集合中

7.boolean remove(Object o):删除集合中的某个元素

8.boolean removeAll(Collection c):从当前集合中移除形参集合中的全部元素,也调用了equal方法

9.bollean retainAll(Collection c):将原集合与形参集合的交集存入原集合中

10.boolean equals(Object o):原集合和形参集合是否完全一样,因为在创建对象时使用的是ArrayListArrayList是有序的,因此顺序也要一样

11.int hashCode():返回当前对象的哈希值

12.Object[] toArray():集合转换为数组

13.Arrays.asList(o):数组转换为集合,返回List类型

14.Iterator:使用Iterator(迭代器)接口--集合元素的遍历,hashNext()判断下一个位置是否有元素,next()指针下移,取出元素。集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

15.void clear():清空集合元素

16.int size():获取添加的元素的个数
public class test {
    @Test
    public void test() {
        //向Colletion接口的实现类的对象(coll)中添加数据对象(obj)时,要求obj所在类要重写equals()方法
        Collection coll = new ArrayList();
        Person p1 = new Person("JS", 20);
        //1.boolean add(Object e):将元素e添加到集合coll中
        coll.add("AA");
        coll.add("BB");
        coll.add(123);//自动装箱
        System.out.println("是否移除123:" + coll.remove(123));
        coll.add(new Date());
        coll.add(p1);
        Collection coll1 = new ArrayList();
        coll1.add("CC");
        coll1.add(456);
        coll1.add(new String("Tom"));
        coll1.add(new Person("Jerry", 20));
        //2.boolean addAll(Collection c):将指定集合中的元素添加到集合中
        coll.addAll(coll1);
        //3.toString()、变量名:输出该集合中的元素
        System.out.println(coll);
        //4.bollean isEmpty():判断当前集合是否为空(判断size是否为0)
        System.out.println("是否为空:" + coll.isEmpty());//f
        //5.boolean contains(Object o):判断该集合中是否包含某个元素,我们在判断时会调用obj所在类的equals()方法
        System.out.println("是否包含123:" + coll.contains(123));//t
        System.out.println("是否包含字符串Tom:" + coll.contains(new String("Tom")));//比内容:t
        System.out.println("是否包含p1:" + coll.contains(p1));//t
        System.out.println("是否包含Jetty, 20:" + coll.contains(new Person("Jerry", 20))); //使用==来比地址:f,重写Person中的equal方法可以让它变成true,第几次找到则equal执行几次(从添加在equal中的输出语句可以看出来)
        //6.bollean containsALL(Collection c):判断形参集合中的所有元素是否全部存在于当前集合中
        Collection coll2 = Arrays.asList(123, 345);//Arrats工具类中有asList方法,给coll2设置数据,原有数据被清除
        System.out.println("判断形参集合中的所有元素是否全部存在于当前集合中:" + coll.containsAll(coll1));//t
        System.out.println("判断形参集合中的所有元素是否全部存在于当前集合中:" + coll.containsAll(coll2));//f
        //7.boolean remove(Object o):删除集合中得某个元素
        coll.remove(123);//会调用equal操作,因此也要重写对象的equal方法
        System.out.println("移除重写对象的Jerry,20:" + coll.remove(new Person("Jerry", 20)));//重写后可以移除对象,因为重写过equal方法了,比内容,若没有重写则移除不了
        //8.boolean removeAll(Collection c):从当前集合中移除形参集合中的全部元素,也掉了equal方法
        System.out.println(coll.removeAll(coll1));
        System.out.println(coll);
        //9.bollean retainAll(Collection c):将原集合与形参集合的交集存入原集合中
        System.out.println(coll.retainAll(coll2));
        System.out.println(coll);
        //10.boolean equals(Object o):原集合和形参集合是否完全一样,因为在创建对象时使用的是ArrayList,ArrayList是有序的,因此顺序也要一样
        Collection coll3 = coll;
        System.out.println(coll.equals(coll3));//t
        //11.int hashCode():返回当前对象的哈希值
        System.out.println("返回当前对象的哈希值:" + coll.hashCode());//1
        //12.Object[] toArray():集合转换为数组
        Object[] objects = coll.toArray();
        for (int i = 0; i < objects.length; i++) {
            System.out.println(objects[i]);
        }
        //13.Arrays.asList(数组类型或new新的数组):数组转换为集合,返回List类型
        List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
        System.out.println(list);
        //这种写法认为是一个元素[[I@66cd51c3],size为1
        List<int[]> ints = Arrays.asList(new int[]{123, 456});
        System.out.println(ints);
        //如果想让他为123,456则要用下面这样的写法,泛型可以去掉,size为2
        List integers = Arrays.asList(new Integer[]{123, 456});
        List<Integer> integers1 = Arrays.asList(new Integer[]{123, 456});
        List<Integer> integers2 = Arrays.asList(123, 456);
        System.out.println(integers);
        List<Object> list = Arrays.asList(objects);
        System.out.println(list);
        //14.iteaator():返回Iterator接口的实例,用于遍历集合元素,放在IteratorTest.java中测试
        Collection collection = new ArrayList();
        collection.add("AA");
        collection.add("BB");
        collection.add("CC");
        Iterator iterator = collection.iterator();
        //方式一:
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
        //方式二:
//        for (int i = 0; i < collection.size(); i++) {
//            System.out.println(iterator.next());
//        }
        //方式三:推荐hashnext()+next:hashnext()是否还有下一个元素,hashNext指针没有下移,调next()时指针下移了
        while (iterator.hasNext()) {
            Object o = iterator.next();//一开始在第一个元素的上一个元素的位置,next()指针下移,取出当前元素
            System.out.println(iterator.next());//输出当前元素
        }
        //15.void clear():清空集合元素
        coll.clear();
        //16.int size():获取添加的元素的个数
        System.out.println("长度:" + coll.size());
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(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 boolean equals(Object o) {
        System.out.println("equal方法");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }
}
(2)Iterator接口
1.说明

Iterator:使用Iterator(迭代器)接口–集合元素的遍历,hashNext()判断下一个位置是否有元素,next()指针下移,取出元素。集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

Iterator接口仅用来遍历Collcetion,不可遍历Map

Collection collection = new ArrayList();
        collection.add("AA");
        collection.add("BB");
        collection.add("CC");
        Iterator iterator = collection.iterator();
        //方式一:
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
        //方式二:
//        for (int i = 0; i < collection.size(); i++) {
//            System.out.println(iterator.next());
//        }
        //方式三:推荐hashnext()+next:hashnext()是否还有下一个元素,hashNext指针没有下移,调next()时指针下移了
        while (iterator.hasNext()) {
            Object o = iterator.next();//一开始在第一个元素的上一个元素的位置,next()指针下移,取出当前元素
            System.out.println(iterator.next());//输出当前元素
        }
2.关于Iterator的两种错误遍历方式
 @Test
    public void test4() {
        Collection collection = new ArrayList();
        collection.add("AA");
        collection.add("BB");
        collection.add("CC");
        Iterator iterator = collection.iterator();
        //错误,这样在判断时指针已经移到下一个了,输出是会跳着输出
        while ((iterator.next()) != null) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test5() {
        Collection collection = new ArrayList();
        collection.add("AA");
        collection.add("BB");
        collection.add("CC");
        //会无限输出第一个,即AA。集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
        while (collection.iterator().hasNext()) {
            System.out.println(collection.iterator().next());
        }
    }
3.Iterator接口中的remove()方法

迭代器(Iterator)内部定义了remove()方法,可以在遍历的时候删除集合中的元素,此方法不同于集合Collection直接调用remove()方法,这是两个方法。

注:如果在调用remove方法之前未调用next方法、连续两次调用remove都会报IllegalStateException。

Collection collection = new ArrayList();
collection.add("AA");
collection.add("BB");
collection.add("CC");
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
    //调了一次next方法后可以调remove,否则会报异常,因为没有让指针后移指针会指向第一个元素前面的位置
    Object o = iterator.next();
    if ("AA".equals(o)) {
        iterator.remove();
    }
}
//再遍历需要再获取一个iterator,因为之前的那个指针已经指到最后了
Iterator iterators = collection.iterator();
while (iterators.hasNext()) {
    System.out.println(iterators.next());
}
4.foreach循环–遍历集合、数组
Collection collection = new ArrayList();
collection.add("AA");
collection.add("BB");
collection.add("CC");
//for(集合(数组)中元素的类型  局部变量:集合对象/数组对象){}
for (Object o : collection) {//把collection的每一个元素给o,内部能然调用迭代器
    System.out.println(o);
}
int[] a = new int[]{1, 2, 3};
for (int i : a) {
    System.out.println(i);
}

foreach循环笔试题

String[] s = new String[]{"MM", "MM", "MM"};
for (int i = 0; i < s.length; i++) {
    s[i] = "GG";
}
for (int i = 0; i < s.length; i++) {
    System.out.println(s[i]);//GG
}
for (String ss:s) {
    ss="MM";//ss为MM但是s中不变仍未GG
}
for (int i = 0; i < s.length; i++) {
    System.out.println(s[i]);//GG
}
(3)List接口
1.概述

①List集合中的元素有序且可重复,集合中的每个元素都有其对应的顺序索引,又称动态数组。

②List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据 序号存取容器中的元素。

③JDK的API中List接口的实现类常用的有:ArrayList、LinkedList和Vector。

2.ArrayList、LinkedList和Vector异同

相同点:①三个类都实现了List接口,存储数据的特点都为有序且可重复。

​ ②ArrayList、Vector:底层使用Object[] elementData存储(数组存储)。

不同点:①ArrayList:作为List接口的主要实现类(最常用):线程不安全,执行效率高。

​ LinkList:对于使用频繁的插入、删除操作,使用此类效率比ArrayList高,因为底层使用双向链表存储,

​ Vector:作为List接口的古老实现类:线程安全的,效率低。

(4)ArrayList集合
1.JDK7中ArrayList源码分析

①ArrayList arraylist=new ArrayLiast();–创建了一个长度是10的Object[]数组elementData

②arraylist.add(123);//elementDate[0]=new Integet(123);

​ …

​ arraylist.add(11);//如果此次的添加导入底层elementData数组容量不够,则扩容。默认情况下扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中

结论:建议开发中使用带参的构造器:ArrayList list=new ArrayList(int capacity–容量);

2.JDK8中ArrayList源码变化

①ArrayList arraylist=new ArrayLiast();//底层Object[] elementData初始化为{},并没有创建长度为10的数组

②list.add(123);//第一次调用add()时,底层才创建了长度为10的数组,并将数据123添加到elementData[0]

③后续的添加以及扩容操作与JDK7相同

注:JDK7中的ArrayList的创建类似于单例设计模式的饿汉式,而JDK8中的ArrayList对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。

3.ArrayList接口的常用方法
1.bollean isEmpty():判断当前集合是否为空(判断size是否为0)
2.boolean contains(Object o):判断该集合中是否包含某个元素,我们在判断时会调用obj所在类的equals()方法
3.bollean containsALL(Collection c):判断形参集合中的所有元素是否全部存在于当前集合中
4.boolean remove(Object o):删除集合中得某个元素
5.boolean removeAll(Collection c):从当前集合中移除形参集合中的全部元素,也调用了equal方法
6.bollean retainAll(Collection c):将原集合与形参集合的交集存入原集合中
7.boolean equals(Object o):原集合和形参集合是否完全一样,因为在创建对象时使用的是ArrayListArrayList是有序的,因此顺序也要一样
8.int hashCode():返回当前对象的哈希值
9.Object[] toArray():集合转换为数组
10.Arrays.asList(o):数组转换为集合,返回List类型
   List list1 = Arrays.asList(new Object[list.size()]);//创建一个长度为list.size长度的Object数组,且每个元素都为null,并将该数组转换为集合,因此该集合长度为list.size。list1为size为list.size长度的集合,每个元素都为null
11.void clear():清空集合元素
除了Collection的方法外,ArrayList还可以用
1.void add(int index,Object o)--将o添加到index处,如果不写index则默认添加到最后面,如果该位置有元素,则添加到此处原来元素和后面元素后移
2.boolean addAll(int index,Collection c)--从将c中的所有元素添加到list,从index开始。add也可以用添加c,但是会把c当作一个元素,但是addAll方法c中有几个元素就当作几个元素,Collcetion可以是CollectionList3.Object remove(int index)--移除指定index位置的元素,并返回此元素
4.Object set(int index,Object o)--将index位置元素设置位o
5.List toString()/list--输出list集合中的元素
6.Object get(int index)--获取指定位置上的元素
7.int indexOf(Object o)--判断当前对象在当前集合中首次出现的索引位置(0开始),有返回位置,没有返回-1
8.int lastIndexOf(Object o)判断当前对象在当前集合中最后一次出现的索引位置(0开始),有返回位置,没有返回-1
9.int size()--返回集合长度
10.List subList(int fromIndex,int toIndex)--返回从fromIndex到toIndex位置的子集合,左闭右开,不影响原来的lsit
11.遍历
    方式一:迭代器
    Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
	方式二:foreach
	for (Object o : list) {
        System.out.println(o);
    }
	方式三:普通for循环
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }

总结:增add、删remove(index或obk)、改set、查toString get、插add(index,o)、长度size、遍历Iterator foreach 普通循环
ArrayList list = new ArrayList(12);//12是底层数组的长度,并不是该集合的size,size只有在添加元素之后才会增加
ArrayList list = new ArrayList();
        //1.void add(int index,Object o)--将o添加到index处,如果不写index则默认添加到最后面,如果该位置有元素,则添加到此处原来元素和后面元素后移
        list.add(123);
        list.add(456);
        list.add(new Person("Tom", 12));
        list.add(1, 111);
        System.out.println(list);
        //2.boolean addAll(int index,Collection c)
        // --从将c中的所有元素添加到list,从index开始。add也可以用添加c,但是会把c当作一个元素,但是addAll方法c中有几个元素就当作几个元素,Collcetion可以是Collection、List等
        List list1 = Arrays.asList(1, 2, 3, 456);
        list.addAll(list1);
        list.add(456);
        ArrayList a = new ArrayList();
        a.add("a");
        list.addAll(a);
        System.out.println(list);
        //3.int size()--返回集合长度
        System.out.println("返回集合长度" + list.size());
        //4.Object get(int index)--获取指定位置上的元素
        System.out.println("获取指定位置上的元素:" + list.get(2));
        //5.int indexOf(Object o)--判断当前对象在当前集合中首次出现的索引位置(从0开始),有返回位置,没有返回-1
        System.out.println("456第一次出现的位置:" + list.indexOf(456));//2
        System.out.println("4561第一次出现的位置:" + list.indexOf(4561));//-1
        //6.int lastIndexOf(Object o)判断当前对象在当前集合中最后一次出现的索引位置(从0开始),有返回位置,没有返回-1
        System.out.println("456最后一次出现的位置:" + list.lastIndexOf(456));//8
        //7.Object remove(int index)--移除指定index位置的元素,并返回此元素
        Object o = list.remove(0);
        System.out.println(o);
        System.out.println(list);
        //8.Object set(int index,Object o)--将index位置元素设置位o
        list.set(1, '1');
        System.out.println(list);
        //9.List subList(int fromIndex,int toIndex)--返回从fromIndex到toIndex位置的子集合,左闭右开,不影响原来的lsit
        List l2 = list.subList(1, 4);
        System.out.println(l2);
        System.out.println(list.subList(1, 3));
4.面试题

区分remove(int index)与remove(Object o)的区别

@Test
public void testListRemove() {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
updateList(list);
System.out.println(list);
}
private static void updateList(List list) {
list.remove(2);//删除index为2的元素,输出12
list.remove(new Integet(2));//因为如果按元素删除的话形参类型为Objcet类型而不是int类型,因此要对int装箱为Integer后删除的是值为2的元素,输出13
}
(5)LinkedList集合
1.LinkedList源码分析

底层以链表的方式存储

2.LinkedList常用方法
1.void add(int index,Object obj)--在index处添加指定元素
2.void addFirst(Object obj)--在开头添加指定元素
3.void addLast(Object obj)--在末尾添加指定元素
4.Object getFirst()--获得第一个元素
5.Object getLast()--获得最后一个元素
6.List toString()--打印集合中的元素
7.Object remove(int index)--移除指定位置元素
8.Object removeFirst()--移除第一个元素
9.Object removeLast()--移除最后一个元素
(6)Set接口
1.Set接口:存储无序的、不可重复的数据

①set接口中没有额外定义新的方法,使用的都是Collection中声明的方法

②要求:向Set中添加的数据,其所在的类一定要重写hashCode()方法和equals()方法;重写的hashCode()与equal()要尽量保持一致性(相等的对象要有相同的哈希值)

③重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值,一般自动生成

2.set接口分类:

①HashSet:作为Set接口的主要实现类,线程不安全,可以存储null值(底层:数组+链表)

​ LinkedHashSet:HashSet的一个子类,遍历其内部数据时,可以按照添加的顺序遍历

③TreeSet:可以按照添加对象的指定属性进行排序

3.理解无序性与不可重复性

无序性:不等于随机性。以HashSet为例说明,存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。

不可重复性:保证添加的元素按照equals()判断时不能返回True(相同返回True)。即相同元素只能添加一个

4.Eclipse/IDEA工具里hashCode()的重写
Eclipse/IDEA工具里hashCode()的重写
以Eclipse/IDEA为例,在自定义类中可以调用工具自动重写equals和hashCode。
问题:为什么用Eclipse/IDEA复写hashCode方法,有31这个数字?
选择系数的时候要选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
并且31只占用5bits,相乘造成数据溢出的概率较小。
31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化。(提高算法效率)
31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终出来的结果只能被素数本身和被乘数还有1来整除!(减少冲突)
(7)HashSet集合
1.Set中添加元素的过程:以HashSet为例

①我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为相应的索引位置),判断数组此位置上有没有元素,如果数组此位置上没有元素则元素a添加成功;

②若此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值,如果哈希值不同则a添加成功;

③若哈希值相同进而需要调用元素a所在类的equals()方法,若equal返回true则a与b一样则添加a失败,否则a与b不一样元素a添加成功。

注:对于2、3添加成功的情况而言,元素a与已经存在指定索引位置上的数据以链表方式存储。jdk7:元素a放在数组中,指向原来的元素。jdk8:原来的元素在数组中,指向元素a。即七上八下

2.要求

①set接口中没有额外定义新的方法,使用的都是Collection中声明的方法

②要求:向Set中添加的数据,其所在的类一定要重写hashCode()方法和equals()方法;冲洗的hashCode()与equal()要尽量保持一致性(相等的对象要有相同的哈希值)

③重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值,一般自动生成

public class java03 {
    @Test
    public void test() {
        Set set = new HashSet();
        //Set set = new LinkedHashSet();
        set.add(456);
        set.add(123);
        set.add(123);
        set.add("aa");
        set.add("cc");
        set.add(new Person("Tom", 12));
        set.add(new User("Tom", 111));
        set.add(new User("Tom", 111));
        set.add(129);
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(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 boolean equals(Object o) {
        System.out.println("equal方法");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

class User {
    private String name;
    private int age;

    public User() {
    }

    public User(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}
(8)LinkedHashSet集合
1.说明

LinkedHashSet作为HashSet的子类,在添加数据的同时每个数据还维护了两个引用,记录此数据的前一个和后一个数据。这样做对于频繁的遍历操作LinkedHashSet效率高于HashSet,因此在频繁使用遍历时可以选用此类

public class java03 {
    @Test
    public void test2() {
        Set set = new LinkedHashSet();
        set.add(new User("Tom", 123));
        set.add(123);
        set.add("aaa");
        set.add("123");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(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 boolean equals(Object o) {
        System.out.println("equal方法");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

class User {
    private String name;
    private int age;

    public User() {
    }

    public User(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}
(9)TreeSet集合
1.说明

①向TreeSet中添加的数据要求是相同类的对象

②对于自定义类必须规定排序方式

2.两种排序方式–自然排序与定制排序

①在自然排序中TreeSet通过CompareTo返回是否为0来判断(0同非0不同)来判断元素是不是一样的并不是通过equals,若名字相同的情况下想让该元素加进来,要在CompareTo方法中引用二级排序

②在定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals()方法

public class java04 {
    @Test
    public void test() {
        TreeSet treeSet = new TreeSet();
//        失败:不可以添加不同类的对象
//        treeSet.add(123);
//        treeSet.add(456);
//        treeSet.add("aa");
//        treeSet.add(new Person("Tom", 123));
//        正确:添加全部为整形的数据
//        treeSet.add(123);
//        treeSet.add(1456);
//        treeSet.add(789);
        treeSet.add(new User("Tom", 123));
        treeSet.add(new User("Jey", 456));
        treeSet.add(new User("Marry", 156723));
        treeSet.add(new User("Mark", 112323));
        //TreeSet通过CompareTo来判断元素是不是一样的并不是通过equals,若名字相同的情况下想让该元素加进来,要在CompareTo方法中引用二级排序
        treeSet.add(new User("Mark", 1123231));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test1() {
        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("Tom", 123));
        set.add(new User("Jey", 456));
        set.add(new User("Jeys", 456));
        set.add(new User("Marry", 156723));
        set.add(new User("Mark", 112323));
        set.add(new User("Mark", 1123231));
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

class User implements Comparable {
    private String name;
    private int age;

    public User() {
    }

    public User(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //按照姓名从小到大排序
    @Override
    public int compareTo(Object o) {
        if (o instanceof User) {
            User user = (User) o;
//            return this.name.compareTo(user.name);
            int compareOne = this.name.compareTo(user.name);
            if (compareOne != 0) {
                return compareOne;
            } else {
                //年龄从小到大排序
                return Integer.compare(this.age, user.age);
            }
        } else {
            throw new RuntimeException("输入的类型不匹配");
        }
    }
}
3.练习
定义一个 Employee 类。
该类包含:private 成员变量 name,age,birthday,其中 birthday 为
MyDate 类的对象;
并为每一个属性定义 getter, setter 方法;
并重写 toString 方法输出 name, age, birthday
MyDate 类包含:
private 成员变量 year,month,day;并为每一个属性定义 getter, setter 
方法;
创建该类的 5 个对象,并把这些对象放入 TreeSet 集合中(下一章:
TreeSet 需使用泛型来定义)
分别按以下两种方式对集合中的元素进行排序,并遍历输出:
1). 使 Employee 实现 Comparable 接口,并按 name 排序
2). 创建 TreeSet 时传入 Comparator 对象,按生日日期的先后排序

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 employee = (Employee) o;
            return this.name.compareTo(((Employee) o).name);
        } else {
            throw new RuntimeException("类型不一致");
        }
    }
}
public class MyDate implements Comparable<MyDate> {
    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) {
        if (o instanceof MyDate) {
            MyDate m = (MyDate) o;
            int subYear = this.getYear() - m.getYear();
            if (subYear != 0) {
                return subYear;
            }
            int subMonday = this.getMonth() - m.getMonth();
            if (subMonday != 0) {
                return subMonday;
            }
            return this.getDay() - m.getDay();
        } else {
            throw new RuntimeException("类型不一致");
        }
    }
}
public class test {
    @Test
    public void test() {
        TreeSet set = new TreeSet();
        //类中的属性是类,在利用构造器赋值时要创建类种类的对象
        Employee e1 = new Employee("Tom", 21, new MyDate(2000, 07, 11));
        Employee e2 = new Employee("Tom4", 22, new MyDate(2000, 05, 14));
        Employee e3 = new Employee("Tom3", 24, new MyDate(2000, 06, 01));
        Employee e4 = new Employee("Tom5", 23, new MyDate(2000, 11, 21));
        Employee e5 = new Employee("Tom2", 22, new MyDate(2000, 12, 12));
        //也可以利用匿名的方式来添加对象
        set.add(e5);
        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        for (Object o : set) {
            System.out.println(o);
        }
    }

    @Test
    public void test1() {
        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();
//                    MyDate类比较大小也可以单独写在MyDate中,MyDate要实现CompareTo方法,对应的b1、b2分别为this与o
//                    int subYear = b1.getYear() - b2.getYear();
//                    int subMonday = b1.getMonth() - b2.getMonth();
//                    int subDay = b1.getDay() - b2.getDay();
//                    if (subYear != 0) {
//                        return subYear;
//                    } else if (subMonday != 0) {
//                        return subMonday;
//                    } else {
//                        return subDay;
//                    }
                    //方法二:在MyDate类中继承Comparable类并重写CompareTo方法,在测试类中重写的compare方法中直接调用MyDate中的CompareTo方法
                    return b1.compareTo(b2);
                } else {
                    throw new RuntimeException("类型不一致");
                }
            }
        });
        Employee e1 = new Employee("Tom", 21, new MyDate(2000, 07, 11));
        Employee e2 = new Employee("Tom4", 22, new MyDate(2000, 05, 14));
        Employee e3 = new Employee("Tom3", 24, new MyDate(2000, 05, 01));
        Employee e4 = new Employee("Tom5", 23, new MyDate(2000, 11, 21));
        Employee e5 = new Employee("Tom2", 22, new MyDate(2000, 12, 12));
        Employee e6 = new Employee("Tom6", 22, new MyDate(2000, 12, 12));
        set.add(e5);
        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e6);
        for (Object o : set) {
            System.out.println(o);
        }
    }
}

2.因此可以用Hashset来过滤

//在List内去除重复数字值,要求尽量简单。注:Integer只需重写equal即可,如果添加的元素为自定义类,还需要重写HashCode方法
public class java06 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Integer(1));
        list.add(new Integer(2));
        list.add(new Integer(2));
        list.add(new Integer(3));
        list.add(new Integer(4));
        List list1 = duplicateList(list);
        for (Object o : list1) {
            System.out.println(o);
        }
    }

    public static List duplicateList(List list) {
        HashSet set = new HashSet();
        set.addAll(list);
        return new ArrayList(set);
    }
}
HashSet set = new HashSet();
Person p1 = new Person(1001, "AA");
Person p2 = new Person(1002, "BB");
set.add(p1);
set.add(p2);
System.out.println(set);//两个元素--[Person{id=1002, name='BB'}, Person{id=1001, name='AA'}]

p1.name = "CC";//改为CC,但是仍在AA的位置,因为该位置是按一开始的AA的哈希值计算的因此改为CC后存放的位置仍为AA哈希值的位置
set.remove(p1);//set中的remove先计算哈希值,然后找到该元素的地址,但是由于将AA改为CC仍存放在AA的位置,因此在remove找CC时可能找的是按CC计算的位置而不是CC所在的按AA存放的位置,因此AA位置上的CC仍然存在不会被删除
System.out.println(set);//两个元素BB CC--[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]

set.add(new Person(1001, "CC"));//添加CC放入,CC对应哈希值的位置
System.out.println(set);//俩CC--[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]
set.add(new Person(1001, "AA"));//哈希值一样,但是equal时不一样因此可以加进去
System.out.println(set);//[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
3.Map接口
(1)说明
1.结构

①Map:双列数据,存储"键值对"数据

②HashMap:作为Map的主要实现类(最常用),线程不安全,效率高,可以存储null的key和value

​ LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历,因为在原有得HashMap得底层结构基础上1,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap

③TreeMap:存储有序的键值对,保证按照添加的key-value对进行排序(按照Key的自然排序或定制排序来排),实现排序遍历,底层使用红黑树

④Hashtable:作为古老的实现类,线程安全,效率低,不可以存储null的key和value

​ Properties:常用来处理配置文件,key和value都是String类型

Map map = new HashMap();
map.put(null, null);//不报错
Map m = new Hashtable();
m.put(null, null);//报错

HashMap的底层:数组+链表(JDK7及之前)

​ 数组+链表+红黑树(JDK8)

2.面试题:

1.HashMap的底层实现原理

JDK7:数组+链表
HashMap map=new HashMap();//在实例化后,底层创建了长度是16的一维数组Entry[] table
...可能已经执行过多次put...
map.put(key1,value1);
//①调用key1所在类的HashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置,如果此位置上的数据为空,此时Entry添加成功;
//②如果此位置上的数据不为空(一个或多个以链表形式存放的数据)则比较当前key与已经存在的一个或多个数据的哈希值,若都不相同则Entry添加成功
//③若与某一个已经存在数据key2-value2的哈希值相同,则调用key1所在类的equal(key2)方法,返回false添加成功,若为true则value1替换相同key的value2值
//关于②与③:此时key1-value1和原来的数据以链表的方式存储,形式与Set相同7上8下
//扩容问题:扩容为原来的2倍,并将原来集合中的数据复制过来
JDK8:数组+链表+红黑树
1.new HashMap();//底层没有创建一个长度为16的数组,底层数组不是Entry[]类型而是Node[]类型,在首次调用put()方法时底层创建长度为16的数组。
//当数组的某一个索引位置上的元素以链表形式存在的数据个数大于8且当前数组长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储

2.HashMap和Hashtable的异同

3.CurrentHashMap与Hashtable的异同

4.将map中的value添加到list中:获取map中的value值存入Collection,再使用遍历+list.add(value);

3.Map结构的理解

Map中的key:无序、不可重复,使用Set存储所有的key —>使用HashMap时key所在的类要重写eqyals()和hashCode()方法,TreeMap要实现比较的方法

Map中的value:无序、可重复,使用Collection存储所有的value —>value所在的类要重写equals()

一个键值对构成了一个Entry对象,Map中的entry:无序、不可重复,使用Set存储所有的Enrty

4.使用:

最常用HashMap

按输入顺序输出LinkedHashMap

自定义顺序输出TreeMap

文件Properties

(2)Map中定义的方法
一:增删改
1.Object put(Object key,Object value)--将指定键值对添加到集合中,如果哈希值一样则为修改操作
2.void putAll(Map map)--将指定的集合添加到原有的集合中,添加规则与put一样
3.Object remove(Object key)--按照指定的key移除键值对,返回要移除键值对的value值,如果没有要移除的key值,则返回null
4.void clear()--清空当前map中的所有数据,map还在但是里面没有东西了
二:元素查询的相关方法
5.int size()--获取当前value中键值对的个数
6.Object get(Object key)--获取指定key对应的value,如果key不存在则为null
7.boolean containsKey(Object key)--是否包含指定的key,包含返回true否则返回false
8.boolean containsValue(Object value)--是否包含指定的value,包含返回true否则返回false。通过哈希值+equals来找,如果有两个相同的value则找到第一个就不i会再找了
9.boolean isEmpty()--判断当前map是否为空(看size是否为0)
10.boolean equals(Object obj)--判断当前map和参数对象obj是否相等,obj可以是任意类型,如果想让返回值为true则obj必须也为map且里面存储的值与原map一样
三:遍历(元视图的操作方法)
11.Set keySet()--遍历所有key,返回的是Set类型,Set可以利用迭代器、foreach等来遍历
12.Collcetion values()--返回所有的value集合,返回一个集合,可以利用迭代器、forerch来遍历
13.Set entrySet()--返回所有key-value对,返回的是Set类型,Set可以利用迭代器来遍历
总结:增:put(Object key,Object value)void putAll(Map map)
     删:Object remove(Object key)void clear()
     改:put(Object key,Object value)
     查:Object get(Object key)
     长度:int size()
     遍历:Set keySet()Collcetion values()Set entrySet()
Map map = new HashMap();
Map map1 = new HashMap();
一:增删改
1.Object put(Object key,Object value)--将指定键值对添加到集合中,如果哈希值一样则为修改操作
2.void putAll(Map map)--将指定的集合添加到原有的集合中,添加规则与put一样
map.put("AA", 123);
map.put(45, 123);
map.put("CC", 123);
map.put("DD", 123);
//已有DD则变为更改操作
map.put("DD", 456);
System.out.println(map);//{AA=123, CC=123, DD=456, 45=123}DD只有一个,值为456
map1.put("AA", 222);
map1.put("aa", 12);
map.putAll(map1);
System.out.println(map);//{AA=222, CC=123, DD=456, aa=12, 45=123}
3.Object remove(Object key)--按照指定的key移除键值对,返回要移除键值对的value值,如果没有要移除的key值,则返回null
Object value = map.remove("AA");
System.out.println(value + "," + map);//222,{CC=123, DD=456, aa=12, 45=123}
4.void clear()--清空当前map中的所有数据,map还在但是里面没有东西了
map.clear();
5.int size()--获取当前value中键值对的个数
System.out.println(map.size());
6.Object get(Object key)--获取指定key对应的value,如果key不存在则为null
System.out.println(map.get("AA") + "," + map.get("aa"));
7.boolean containsKey(Object key)--是否包含指定的key,包含返回true否则返回false
boolean bb = map.containsKey("BB");
System.out.println(bb);
8.boolean containsValue(Object value)--是否包含指定的value,包含返回true否则返回false。通过哈希值+equals来找,如果有两个相同的value则找到第一个就不i会再找了
boolean b = map.containsValue(33);
System.out.println(b);
9.boolean isEmpty()--判断当前map是否为空
System.out.println(map.isEmpty());
10.boolean equals(Object obj)--判断当前map和参数对象obj是否相等,obj可以是任意类型,如果想让返回值为true则obj必须也为map且里面存储的值与原map一样
System.out.println(map.equals(map1));
11.Set keySet()--返回所有key构成的Set集合,返回的是Set类型,Set可以利用迭代器来遍历
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
12.Colltion values()--返回所有的value集合,返回一个集合,可以利用迭代器、forerch来遍历
Collection values = map.values();
for (Object o : values) {
        System.out.println(o);
    }
13.Set entrySet()--返回所有key-value对,返回的是Set类型,Set可以利用迭代器来遍历,可以利用Entry下的getKey()getvalue()来获得key与value
//一般遍历都是用来获取key-value的值
//方式一:迭代器+强转为Map.Entry+entry.getKey()、entry.getValue()
Set set = map.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
        Object obj = iterator.next();
        Map.Entry entry = (Map.Entry) obj;//可以强转为Map类中的Entry类型或Map.Entry entry = (Map.Entry) (iterator.next());
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
//方式二:keySet+map.get(key)
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
        Object key = iterator.next();
        Object value = map.get(key);
        System.out.println(key + ":" + value);
     }
//方式三:map.values()+迭代器
Collcetion c=map.values();
Iterator iterator=c.iterator();
while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
//方式四:直接输出
Set set = map.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
        Object o = iterator.next();
        System.out.println(o);
    }
(3)TreeMap集合

自然排序、定制排序,只可以按照Key来排序

Map map = new HashMap();
        map.put("AA", 11);
        map.put("BB", 22);
        map.put("CC", 33);
        map.put("DD", 33);
        Map map1 = new HashMap();
        map1.put("AA", 11);
        map1.put("BB", 22);
        map1.put("CC", 33);
        map1.put("DD", 33);
        //5.Object get(Object key)--获取指定key对应的value,如果key不存在则为null
        System.out.println(map.get("AA") + "," + map.get("aa"));
        //6.boolean containsKey(Object key)--是否包含指定的key,包含返回true否则返回false
        boolean bb = map.containsKey("BB");
        System.out.println(bb);
        //7.boolean containsValue(Object value)--是否包含指定的value,包含返回true否则返回false。利用equals来找,如果有两个相同的value则找到第一个就不i会再找了
        boolean b = map.containsValue(33);
        System.out.println(b);
        System.out.println(map.isEmpty());
        System.out.println(map.equals(map1));
        Set set = map.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object o = iterator.next();
            Map.Entry entry = (Map.Entry) o;
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }

    @org.junit.Test
    public void test3() {
        TreeMap map = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof User && o2 instanceof User) {
                    User user1 = (User) o1;
                    User user2 = (User) o2;
                    return Integer.compare(user1.getAge(), user2.getAge());
                } else {
                    throw new RuntimeException("输入的类型不一致");
                }
            }
        });
        User u1 = new User("1Tom", 23);
        User u2 = new User("3Jey", 24);
        User u3 = new User("2JK", 13);
        User u4 = new User("4UZI", 23);
        //其他类也可以当作key
        map.put(u1, 98);
        map.put(u2, 77);
        map.put(u3, 88);
        map.put(u4, 54);
        Set set = map.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object o = iterator.next();
            Map.Entry entry = (Map.Entry) o;
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }

class User implements Comparable {
    private String name;
    private int age;

    public User() {
    }

    public User(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    //按照姓名从小到大排序
    @Override
    public int compareTo(Object o) {
        if (o instanceof User) {
            User user = (User) o;
//            return this.name.compareTo(user.name);
            int compareOne = this.name.compareTo(user.name);
            if (compareOne != 0) {
                return compareOne;
            } else {
                //年龄从小到大排序
                return Integer.compare(this.age, user.age);
            }
        } else {
            throw new RuntimeException("输入的类型不匹配");
        }
    }
}
(4)Properties类
1.说明

①Properties 类是 Hashtable 的子类,该对象用于处理属性文件

②由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型

③存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法

2.举例

使用Propertie来读取配置文件

创建jdbd.properties文件,在资源包处创建只需要输入名字,在新建文件处创建需要加上.properties后缀
//dbd.properties文件如下,如果有中文可能会输出乱码--设置--编辑器--文件编码--勾上勾--重新创建properties文件或重新输入值
name=Tom
password=adb1
//main中,使用这样的写法,配置文件默认在当前模块下的src下,而不再在当前模块下,而用单元测试方法test的文件默认路径为当前模块下
public class PropertiesTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            Properties properties = new Properties();
            fis = new FileInputStream("jdbd.properties");
            properties.load(fis);
            String name = properties.getProperty("name");
            String password = properties.getProperty("password");
            System.out.println("name=" + name + ",password=" + password);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//方式二:配置文件默认在当前模块下的src下
@Test
    public void test2() throws Exception {
        Properties properties = new Properties();
        ClassLoader classLoader = java02.class.getClassLoader();
        //getResourceAsStream()方法--以流的方式获取资源,拿到一个输入流
        InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");
        properties.load(resourceAsStream);
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        System.out.println(username + ":" + password);
    }
4.Collections工具类
(1)说明

①Collections 是一个操作Collection(Set、List)和 Map等集合的工具类

②Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作, 还提供了对集合对象设置不可变、对集合对象实现同步控制等方法

③Collection和Collections的区别

(2)常用方法
一、排序操作:(均为static方法),使用Collections.方法(集合)--集合本身被修改了
1.reverse(List):反转 List 中元素的顺序
2.shuffle(List):对 List 集合元素进行随机排序
3.sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
4.sort(ListComparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
5.swap(list,i, j):将指定 list 集合中的 i 处元素和 j 处元素进行交
二、查找、替换
1.Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素,要求:集合中元素类型一致,不一致需要使用2重写比较方法
2.Object max(CollectionComparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
3.Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素,要求:集合中元素类型一致,不一致需要使用2重写比较方法
4.Object min(CollectionComparator):根据 Comparator 指定的顺序,返回给定集合中的最小元素
5.int frequency(CollectionObject):返回指定集合中指定元素的出现次数
6.void copy(List list1,List list):将list中的内容复制到list1中,要求list1的长度必须比lsit大,因此要使用
  List list1 = Arrays.asList(new Object[list.size()]);来创建集合
  Collections.copy(list1, list);
7.boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List 对象的所有旧值
三、Collections类中提供了多个 synchronizedXxx()方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
 //返回的list2即为线程安全的list
List list2 = Collections.synchronizedList(list);

举例:
List list = new ArrayList();
    list.add(123.1);
    list.add(456.1);
    list.add(789.1);
    list.add(789.1);
    Collections.reverse(list);
    Collections.shuffle(list);
    Collections.sort(list);
    Collections.swap(list, 2, 1);
    System.out.println("集合中的最大值:" + Collections.max(list));
    System.out.println("789.1出现的频率:" + Collections.frequency(list, 789.1));
    List list1 = Arrays.asList(new Object[list.size()]);//创建一个长度为list.size长度的Object数组,且每个元素都为null ,并将该数组转换为集合,因此该集合长度为list.size。list1为size为list.size长度的集合,每个元素都为null
    Collections.copy(list1, list);
    Collections.replaceAll(list, 789.1, 123.1);
    //返回的list2即为线程安全的list
    List list2 = Collections.synchronizedList(list);
5.Arrays工具类

(1)常用方法

1.Arrays.sort(arr);--将arr数组中的元素按照从小到大的顺序存放
2.int Arrays.binarySearch(arr,i);--利用二分查找从arr中找到元素i第一次出现的的索引,在此之前要用sort对数组进行排序
3.int[] Arrays.copyOfRange(arr,i,j);--在不改变原来数组的情况下将arr中i到j(左闭右开)的元素复制,使用新的数组接收,j可以超出arr的长度,若超出长度则新的数组用0来填充
4.Arrays.fill(arr,i);--用i替换arr中所有元素
5.Arrays.toString(arr);--将arr转变为字符串用String接收
6.Arrays.asList("value1","value2",...);返回一个受指定数组支持的固定大小的列表,对返回列表的更改会“直接写”到数组。
  List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
6.练习
//1.请从键盘随机输入10个整数保存到List中,并按倒序、从大到小的顺序显示出来
//2.请把学生名与考试分数录入到集合中,并按分数显示前三名成绩学员的名字。

public class java08 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Set<Student> set = new TreeSet();
        String name;
        double score;
        for (int i = 0; i < 10; i++) {
            name = scanner.next();
            score = scanner.nextDouble();
            if (score > 0 && score <= 100) {
                set.add(new Student(name, score));
            } else {
                throw new RuntimeException("输入的数据不正确");
            }
        }
        int count = 1;
        for (Student s : set) {
            if (count > 3) {
                break;
            } else {
                System.out.println(s.getName() + ":" + s.getScore());
                count++;
            }
        }
        Iterator iterator = set.iterator();
        while (count < 3) {
            Map.Entry entry = (Map.Entry) iterator.next();
            System.out.println(entry.getKey() + ":" + entry.getValue());
            count++;
        }
    }
}

class Student implements Comparable {
    private String name;
    private double score;

    public Student() {
    }

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public int compareTo(Object o) {
        if (o instanceof Student) {
            Student student = (Student) o;
            if (this.score - student.score > 0) {
                return 1;
            } else if (this.score - student.score < 0) {
                return -1;
            } else {
                return this.name.compareTo(student.name);
            }
        } else {
            throw new RuntimeException("类型不一致");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值