Java API(十四):泛型、Collection集合、List集合、Set集合


Java API

包括泛型机制简介、泛型的应用、增强型for循环语句、Collection常用方法、集合存放元素的引用(地址)、集合支持泛型、迭代器、ArrayList和LinkedList、数组转换为List集合、List集合转换为数组、List集合排序、List集合常用方法(add、size、set、get、contains、remove、clear、isEmpty、addAll、removeAll、retainAll、subList)、List常用算法(Comparable接口、Collections.sort方法、Comparator接口)、HashSet、Set集合遍历、HashSet和hashCode、hashCode方法。


一、泛型

1、泛型机制简介

(1)Java SE 1.5引入的特性,泛型又称为参数化类型

(2)将当前类的属性的类型,方法参数的类型以及方法返回值的类型的定义权移交给使用者

(3)使用者在创建当前类的同时将泛型的实际类型传入

public class Point<T> { //T为泛型参数
    private T x;
    private T y;

    public Point(T x,T y){
        super();
        this.x = x;
        this.y = y;
    }
    public void setX(T x) {
        this.x = x;
    }

    public void setY(T y) {
        this.y = y;
    }

    public T getX() {
        return x;
    }

    public T getY() {
        return y;
    }

    @Override
    public String toString() {
        return "x="+x+",y="+y;
    }
}

2、泛型的应用

(1)泛型的原型是Object,定义了泛型只是编译器在做一些验证工作

(2)当我们对泛型类型设置值时,会检查是否满足类型要求,当我们获取一个泛型类型的值时,会自动进行类型转换

public class TestPoint01 {
    public static void main(String[] args) {
        /*
        指定泛型的实际类型位Integer,但实际上,创建的Point对象中,x、y属性是Object类型,这里只是应当将它当做Integer看待
         */
        Point<Integer> p1 = new Point<Integer>(0,0);

        /*
        由于参数是T,这里会验证实参是否为Integer,若不是,则编译失败!
        可以传入基本类型,因为还会自动装箱
         */
        p1.setX(1);
        //p1.setX(Integer.valueOf(1)); //自动装箱

        /*
        获取时,也会自动进行造型,这里无需显示的进行类型转换
         */
        int x1 = p1.getX();
        //int x1 = (Integer)p1.getX(); //自动造型
        //int x1 = ((Integer)p1.getX()).intValue(); //自动造型

        /*
        若不指定泛型,则使用默认的Object类型
         */
        Point p2 = p1;
        p2.setX("一");
        String x2 = (String)p2.getX();
        System.out.println("x2:"+x2); //x2:一

        //类造型异常!
        x1 = p1.getX(); //x1为int型,而p1.getX()获取的是“一”
        System.out.println("x1:"+x1); //ClassCastException
    }
}

3、增强型for循环语句

1)JDK5.0之后推出一个新的特性:增强for循环,又叫做新循环、for each

2)新循环是经典迭代的“简化版”,新循环不能代替传统循环,作用仅仅是用来遍历集合或数组的

public class ForArrayDemo {
    public static void main(String[] args) {
        String[] array = {"one","two","three"};
        for(int i=0;i<array.length;i++){
            String str = array[i];
            System.out.print(i+":"+str+"   "); //0:one   1:two   2:three
        }
        System.out.println();
        for(String str:array){
            System.out.print(str+"   "); //one   two   three
        }
    }
}

for(String str:array)可以理解为每次循环从数组array中取出一个元素赋值给循环变量str

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class ForCollectionDemo {
    public static void main(String[] args) {
        Collection c = new ArrayList(); //集合中都是Object类型数据
        c.add("one");
        c.add("#");
        c.add("tuo");
        c.add("#");
        c.add("three");
        System.out.println(c); //[one, #, tuo, #, three]

        /*
        新循环并非新的语法,新循环是编译器认可,而不是虚拟机认可
        使用新循环遍历集合时,编译器会将它改为迭代器方式遍历
        所以在使用新循环遍历集合时,不能通过集合的方式增删元素
         */
        for(Object o:c){
        //   Iterator it = c.iterator();
        //   while (it.hasNext()){
        //   Object o = it.next();
            String str = (String) o;
            System.out.print(str+"   "); //one   #   Exception in thread "main" java.util.ConcurrentModificationException
            if("#".equals(str)){ //当判断出#和str的值相等时,执行remove会报错ConcurrentModificationException
                c.remove(str);
            }
        }
    }
}

二、Collection集合

(1)java.util.Collection集合,用于存储一组元素。提供了维护集合的相关操作

(2)其派生了两个子接口:

  • List:可重复集

  • Set:不可重复集

(3)元素是否重复是依靠元素自身equals方法比较的结果而定的

1、Collection常用方法

方法功能
int size()返回包含对象的个数
boolean isEmpty返回是否为空
boolean contains(Object o)判断是否包含指定对象
void clear()清空集合
boolean add(E e)向集合中添加对象
boolean remove(Object o)从集合中删除对象
booleac addAll(Collection<? extends E>c)将另一个集合中的所有元素添加到集合中
boolean removeAll(Collection<?>c)删除集合中与另外一个集合中相同的全部元素
Iterator<E> iterator()返回该集合的对应迭代器

2、集合存放元素的引用(地址)

import java.util.ArrayList;
import java.util.Collection;

/**
 * 集合存放元素存放的是元素的引用(地址)
 */
public class Test {
    public static void main(String[] args) {
        Collection c = new ArrayList(); //栈中创建c
        Point o = new Point(1,2); //栈中创建o,存在指向堆中元素的地址
        System.out.println(o); //结果为(1,2)
        c.add(o); //将o添加到c中,栈中c存放的地址指向堆中元素,o为指向的地址信息,所以,c指向的堆元素存放的其实是o的地址信息
        System.out.println(c); //结果为[(1,2)]

        o.setX(2);
        System.out.println(o); //结果为(2,2)
        System.out.println(c); //结果为[(2,2)]
    }
}

在这里插入图片描述

3、集合支持泛型

集合支持泛型,而泛型是用来约束集合中元素的类型

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionDemo01 {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        //只能添加String类型的元素
        c.add("one");
        c.add("two");
        c.add("three");
        c.add("four");

        //遍历集合元素
        for(String str:c){
            System.out.print(str+"   "); //one   two   three   four
        }
        System.out.println();

        /*
        迭代器也应当指定泛型,而泛型的实际类型应当与它遍历的集合的泛型类型一致
         */
        Iterator<String> it = c.iterator();
        while (it.hasNext()){ //获取元素时不需要再造型了
            String str = it.next();
            System.out.print(str+"   "); //one   two   three   four
        }
    }
}

4、迭代器

(1)Collection提供了统一的遍历集合元素的方式:迭代器模式

(2)Iterator iterator()获取用于遍历当前集合的迭代器

(3)java.util.Iterator是一个接口,规定了用于遍历集合元素的相关方法,不同的集合提供了相应的实现类,无需记住那些实现类的名字,只将他们当做Iterator即可

(4)遍历集合遵循:问,取,删的步骤,其中删除不是必须操作

(5)Iterator定义了三个方法:

方法功能
boolean hasNext()判断指针后面是否有元素
E next()获取集合中下一个元素
void remove()判断是否包含指定对象
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class IteratorDemo {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("one");
        c.add("#");
        c.add("teo");
        c.add("#");
        c.add("three");
        c.add("#");
        c.add("four");

        //获取用于遍历当前集合的迭代器
        Iterator it = c.iterator();
        /*
        boolean hasNext() 问的过程,该方法是判断集合中是否还有元素可以取出
        E next() 取的过程,获取集合中下一个元素
         */
        while (it.hasNext()){
            String str = (String) it.next(); //需确保集合中存放的元素类型是否一致
            if("#".equals(str)){ //当str存在控制null时,#比null,返回的false,如果写成equals(str)."#",当str存在null时,null比“#”会报空指针异常(写法:自变量equals变量)
                /*
                在使用迭代器遍历集合时,不要使用集合的方法增删元素,否则会引发异常ConcurrentModificationException
                 */
                //c.remove(str);
                /**
                 * 迭代器提供了remove方法,用来删除next方法取出的元素
                 * 取一次删一次,删的是取的这个元素
                 */
                it.remove();
            }
            System.out.print(str+"   "); //one   #   teo   #   three   #   four
        }
    }
}

对于List集合而言,可以通过基于下标的get()方法进行遍历; 而Iterator方法是针对Collection接口设计,所以实现了Collection接口的类都可以使用Iterator实现迭代遍历

三、List集合

(1)java.util.List可重复集,并且有序。特点是可以根据下标操作元素

(2)List接口是Collection的子接口,用于定义线性表数据结构

(3)List可以理解为存放对象的数组,只不过其元素个数可以动态的增加或减少

1、ArrayList和LinkedList

(1)List接口的两个常见实现类:ArrayList、LinkedList,分别用动态数组和链表的方式实现List接口

(2)ArrayList:使用数字实现,查询更快,适用于随机访问

(3)LinkedList:使用链表实现,增删更快(收尾增删效果明显)

在这里插入图片描述

2、数组转换为List集合

(1)使用数组的工具类Arrays的静态方法asList

(2)只能转换为List集合,原因是:Set不能存放重复元素。所以若转换为Set集合可能出现丢失元素的情况

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ArrayToCollectionDemo {
    public static void main(String[] args) {
        String[] array = {"one","two","three","four"};

        List<String> list = Arrays.asList(array);
        System.out.println(list); //[one, two, three, four]

        /*
        向集合中添加一个元素
        实际上下面的代码会抛出异常
        原因在于该集合是由数组转换过来的,那么该集合就表示原来的数组,所以对集合的操作就是对数组的操作
        那么添加元素会导致原数组扩容,那么就不能表示原来的数组了。所以不允许向该集合添加新元素
         */
        //list.add("five"); //UnsupportedOperationException
        //System.out.println(list);

        //修改集合元素,数组元素也会改变
        list.set(1,"2");
        System.out.println(list); //[one, 2, three, four]
        for (String str : array){
            System.out.print(str+"   "); //one   2   three   four
        }
        System.out.println();

        /*
        若希望增删元素,需要另外创建一个集合
         */
        List<String> list1 = new ArrayList<String>();
        list1.addAll(list);
        list1.add("five");
        System.out.println(list1); //[one, 2, three, four, five]
        /*
        所有的集合都提供了一个带有Collection类型参数的构造方法
        该类构造方法称为:复制构造器
        作用是在创建当前集合的同时,集合中包含给定集合中的所有元素
         */
        List<String> list2 = new ArrayList<String>(list);
        list2.add("five01");
        System.out.println(list2); //[one, 2, three, four, five01]
    }
}

3、List集合转换为数组

import java.util.ArrayList;
import java.util.Collection;

/**
 * 集合转换为数组
 */
public class CollectionToArrayDemo {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        c.add("one");
        c.add("two");
        c.add("three");
        c.add("four");
        System.out.println(c); //[one, two, three, four]

        /*
        集合提供了一个方法toArray,可以将当前集合转换为数组
         */
        //Object[] array = c.toArray();
        String[] array01 = c.toArray(new String[c.size()]);
        System.out.println("len:"+array01.length); //len:4
        for (String str:c){
            System.out.print(str+"   "); //one   two   three   four
        }
        System.out.println();

        /*
        若给定的数组可用(数组可以存放集合所有元素)是,则使用该数组
        若不可用,会自动创建一个与给定数组同类型的数组
         */
        String[] array02 = c.toArray(new String[1]);
        System.out.println("len:"+array02.length); //len:4
        for (String str:c){
            System.out.print(str+"  "); //one  two  three  four
        }
    }
}

4、List集合排序

(1)排序集合使用的是集合的工具类Collections的静态方法sort

(2)排序仅能对List集合进行。因为Set部分实现类是无序的

import java.util.*;

public class SortListDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();

        Random random = new Random();
        for(int i=0;i<10;i++){
            list.add(random.nextInt(10)); //生成0~99的随机数
        }
        System.out.println(list); //[8, 2, 1, 6, 4, 7, 5, 8, 8, 4]

        /*
        对集合进行自然排序,从小到大
         */
        Collections.sort(list);
        System.out.println(list); //[1, 2, 4, 4, 5, 6, 7, 8, 8, 8]
    }
}

5、List集合常用方法

List接口的实现类,实现了Collection中定义的方法

(1)、add

1)void add(E e)方法将对象(的引用)添加到集合中

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        System.out.println(list); //[one, two, three, four]
    }
}

2)void add(int index,E e)方法将给定元素插入到指定位置

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        list.add(2,"三");
        System.out.println(list); //[one, two, 三, three, four]
    }
}

(2)、size

size方法返回当前集合中存放对象的数量

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        System.out.println(list.size()); //4
    }
}

(3)、set

1)E set(int index,E e)将指定元素设置到指定位置上,返回值为原位置得元素

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        String str = list.set(1,"二");
        System.out.println(str); //two
        System.out.println(list); //[one, 二, three, four]
    }
}

2)使用set方法可以实现list中第i个和第j个元素进行交换

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        list.set(1, list.set(2, list.get(1)));
        System.out.println(list); //[one, 二, three, four]
    }
}

(4)、get

1)E get(int index)方法获取给定下标对应的元素

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        System.out.println(list.get(3)); //four
    }
}

2)循环遍历List集合

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        for(int i=0;i<list.size();i++){
            System.out.print(list.get(i)+" "); //one two three four
        }
    }
}

(5)、contains

boolean contains(E e)方法判断当前集合是否包含给定元素

import day02.ObjectDemo;

import java.util.ArrayList;
import java.util.Collection;

/**
 * boolean contains(E e)
 * 判断当前集合是否包含给定元素
 */
public class ContainsDemo {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(new Point(1,2));
        c.add(new Point(2,3));
        c.add(new Point(3,4));
        System.out.println(c); //返回ObjectDemo类中重写的toString方法,如果ObjectDemo类中没重写toString,返回的则是包名@。。。

        Point p = new Point(1,2);
        //c.add(p);
        /*
        集合判断是否包含指定元素是依靠元素的equals比较的结果
        只要集合中有元素与给定元素比较为true,则认为包含
        Point类中重写了equals方法,判断的是内容。如果Point类中没重写了equals方法,则按Object类提供的equals方法进行判断,判断的是指向的地址
         */
        boolean b = c.contains(p);
        System.out.println("是否包含:"+b); //是否包含:true
    }
}

boolean addAll(Collection c)将给定集合中的所有元素添加到当前集合中

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

/**
 *
 */
public class CollectionDemo {
    public static void main(String[] args) {
        Collection c1 = new ArrayList();
        c1.add("java");
        c1.add("c++");
        c1.add(".net");
        c1.add("ios");
        System.out.println(c1); //[java, c++, .net, ios]

        Collection c2 = new HashSet(); //无序,不可重复
        c2.add("ios");
        c2.add("android");
        c2.add("linux");
        c2.add("ios"); //返回false
        System.out.println(c2); //[android, linux, ios]

        /**
         * 取并集
         * boolean addAll(Collection c)
         * 将给定集合中的所有元素添加到当前集合中
         * 添加后只要当前集合元素数量发生了变化,则返回true
         */
        boolean flag01 = c1.addAll(c2);
        System.out.println(c1); //[java, c++, .net, ios, android, linux, ios]
        System.out.println(flag01); //true
        boolean flag02 = c2.addAll(c1);
        System.out.println(c2); //[c++, java, android, linux, .net, ios]
        System.out.println(flag02); //true

        Collection c3 = new ArrayList();
        c3.add("java");
        c3.add("android");
        //c3.add("windows");
        /**
         * boolean containsAll(Collection c)
         * 判断当前集合是否包含给定集合中的所有元素
         */
        boolean contains = c1.containsAll(c3);
        System.out.println("是否全包含:"+contains); //是否全包含:true

        /**
         *从c1集合中删除两个集合中共有的元素
         */
        c1.removeAll(c3);
        System.out.println(c1); //[c++, .net, ios, linux, ios]
    }
}

(6)、remove

E remove(int index)方法从集合中删除指定位置得的元素,并将其返回

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        String str = list.remove(2); //存在返回值,返回的就是删掉的下标对应的值
        System.out.println(str); //three
        System.out.println(list); //[one, two, four]
    }
}

boolean remove(E e)从集合中删除指定元素。删除成功返回true;只删除集合中第一个与给定元素equals比较为true的元素

public class Point<T> { //T为泛型参数
    private T x;
    private T y;

    public Point(T x, T y) {
        super();
        this.x = x;
        this.y = y;
    }

    public void setX(T x) {
        this.x = x;
    }

    public void setY(T y) {
        this.y = y;
    }

    public T getX() {
        return x;
    }

    public T getY() {
        return y;
    }

    @Override
    public String toString() {
        return "x=" + x + ",y=" + y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Point<?> point = (Point<?>) o;
        return Objects.equals(x, point.x) && Objects.equals(y, point.y);
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}
public class Test {
    public static void main(String[] ages) throws ParseException {
        Collection c = new ArrayList();
        c.add(new Point(1,2));
        c.add(new Point(2,3));
        c.add(new Point(3,4));
        c.add(new Point(1,2));
        System.out.println(c);

        Point o = new Point(1,2);
        c.remove(o); //[x=1,y=2, x=2,y=3, x=3,y=4, x=1,y=2]
        System.out.println("删除成功!"); //ObjectDem类重写了equals,所以删的是内容相似的,如果没重写equals,删除的就是栈中地址一致的信息
        System.out.println(c); //[x=2,y=3, x=3,y=4, x=1,y=2]
    }
}

ArrayList重写的toString方法依次调用了它所包含对象的toString方法,而Point类也重写了它的toString方法

(7)、clear

void clear()方法用于清空集合

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        list.clear();
        System.out.println(list); //[]
    }
}

(8)、isEmpty

boolean isEmpty()方法用于返回集合是否为空

public class Test {
    public static void main(String[] ages) throws ParseException {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        list.clear();
        System.out.println(list.isEmpty()); //true
    }
}

(9)、addAll

addAll方法将另一个集合中所有元素添加进来,“相同”逻辑通过equals方法来判断

public class Test {
    public static void main(String[] ages) throws ParseException {
        List list1 = new ArrayList();
        List list2 = new ArrayList();
        list1.add("one");
        list1.add("two");
        list1.add("three");
        list2.add("four");
        list2.add("five");
        list1.addAll(list2);
        System.out.println(list1); //[one, two, three, four, five]
    }
}

(10)、removeAll

removeAll方法将删除与另一个集合中所有相同的元素,“相同”逻辑通过equals方法来判断

public class Test {
    public static void main(String[] ages) throws ParseException {
        List list1 = new ArrayList();
        List list3 = new ArrayList();
        list1.add("one");
        list1.add("two");
        list1.add("three");
        list3.add("one");
        list1.removeAll(list3);
        System.out.println(list1); //[two, three]
    }
}

(11)、retainAll

retainAll方法将保留与另一个集合中相同的元素,其余的删掉,“相同”逻辑通过equals方法来判断

public class Test {
    public static void main(String[] ages) throws ParseException {
        List list1 = new ArrayList();
        List list2 = new ArrayList();
        list1.add("one");
        list1.add("two");
        list1.add("three");
        list2.add("one");
        list2.add("two");
        list1.retainAll(list2);
        System.out.println(list1); //[one, two]
    }
}

(12)、subList

List subList(int start,int end)方法获取当前集合中指定范围内的子集。同样含头不含尾

import java.util.ArrayList;
import java.util.List;

/**
 * 取子集
 * List subList(int start,int end)
 * 获取当前集合中指定范围内的子集。同样含头不含尾
 */
public class SubListDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for(int i=0;i<10;i++){
            list.add(i);
        }
        System.out.println(list); //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

        //获取3~7
        List<Integer> sublist = list.subList(3,8);
        System.out.println(sublist); //[3, 4, 5, 6, 7]

        //将子集中每个元素扩大10倍
        for (int i=0;i<sublist.size();i++){
            int n = sublist.get(i);
            n = n * 10;
            sublist.set(i,n);
            //sublist.set(i,sublist.get(i) * 10); //可以简写成一步
        }
        System.out.println(sublist); //[30, 40, 50, 60, 70]

        /*
        对子集的修改,就是修改原集合相应内容
         */
        System.out.println(list); //[0, 1, 2, 30, 40, 50, 60, 70, 8, 9]

        /*
        删除集合2~8中的元素
         */
        list.subList(2,8).clear();
        System.out.println(list); //[0, 1, 8, 9]
    }
}

6、List常用算法

(1)、Comparable接口

1)针对对象数组或者集合中的元素进行排序时,首先要确认对象元素的“比较”逻辑(即那个大,那个小)

2)JDK中定义了Comparable接口,用于表示对象间的大小关系,Java类可以通过实现Comparable接口编写对象的大小逻辑

/**
 * 该类用于作为集合的元素
 */
public class Point implements Comparable<Point> {
    private int x;
    private int y;

    Point(int x,int y){
        super();
        this.x = x;
        this.y = y;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public String toString() {
        return "x="+x+",y="+y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Point point = (Point) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }

    /**
     * 当实现了Comparable接口后,需要重写compareTo方法
     * 该方法的作用是定义当前对象与给定参数对象比较大小的法则
     * 返回值为一个int值,该值表示大小关系。它不关注具体的取值是多少,而关注的是取值范围
     * 当返回值>0时:当前对象比参数对象大
     * 当返回值<0时:当前对象比参数对象小
     * 当返回值=0时:两个对象相等
     */
    public int compareTo(Point o) {
        /*
        坐标的比较规则,点到原点的距离长的大
         */
        int len = this.x*this.x + this.y*this.y; //当前对象
        int olen = o.x*o.x + o.y*o.y; //给定的参数对象
        return len-olen; //不关注具体值,为正则当前对象大,为负返之
    }
}

Point实现了Comparable接口,泛型参数指定为Point类型,使得comparaTo方法的参数也为Point类型

在编写comparaTo方法时应该注意和equals方法的一致,即comparaTo判断相等的对象,equals方法应当返回true,反之亦然

(2)、Collections.sort方法

1)java.util.Collections类通过静态方法,提供了对集合的一些实用操作,应用最多的是对List进行排序的sort方法

2)Collections的sort方法要求集合元素(对象)必须实现Comparable接口,从而调用其compareTo方法判断对象的大小

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 排序自定义类型元素的集合
 */
public class SortListDemo {
    public static void main(String[] args) {
        List<Point> list = new ArrayList<Point>();
        list.add(new Point(1,2));
        list.add(new Point(8,3));
        list.add(new Point(3,4));
        list.add(new Point(2,5));
        list.add(new Point(2,1));
        System.out.println(list);

        /*
        sort方法要求集合元素必须实现Comparable接口,该接口用于规定实现类是可以比较的
        其中有一个方法用来自定义比较大小的规则
         */
        Collections.sort(list);
        System.out.println(list);
    }
}

(3)、Comparator接口

1)我们想使用sort方法排序集合,但是该方法要求我们的集合元素必须实现Comparable接口并且定义比较规则。这种我们想使用某个功能,而它要求我们修改程序的现象称为“侵入性”,修改的代码越多,侵入性越强,越不利于程序的扩展

2)一旦Java类实现了Comparable,其比较逻辑就已经确定;如果希望在排序的操作中临时指定比较规则,可以采用Comparator接口回调的方式

3)Comparator接口定义:

import java.util.Comparator;

/**
 * 定义一个额外的比较器
 */
class MyComparator implements Comparator<String> {
    /**
     * 该方法用来定义o1和o2的比较
     * 若返回值>0:o1>o2
     * 若返回值<0:o1<o2
     * 若返回值=0:两个对象相等
     */
    public int compare(String o1, String o2) {
        /*
        字符串中字符多的大
         */
        return o1.length()-o2.length();
    }
}

比较字符串大小:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortListDemo01 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("张三");
        list.add("李湿湿");
        list.add("小泽玛利亚");
        System.out.println(list);

        MyComparator com = new MyComparator();
        /*
        重载的sort方法要求传入一个额外的比较器
        该方法不再要求集合元素必须实现Comparable接口,并且也不再使用集合元素自身的比较规则排序
        而是根据给定的这个额外的比较器的比较规则对集合元素进行排序
        实际开发中也推荐使用这种方式排序集合元素,若集合元素是自定义的,创建比较器时也推荐使用匿名内部类的形式
         */
        Collections.sort(list,com);
        System.out.println(list);

        /*
        Collections有接收Comparator参数的重载sort方法
        可以通过匿名类回调的方式调用,此时sort方法将调用Comparator的compare方法判断两个对象的大小关系
        匿名内部类形式创建(使用一次,用匿名内部类形式创建)
        */
        Comparator<String> com1 = new Comparator<String>() {
            public int compare(String o1, String o2) {
                return o2.length()-o1.length();
            }
        };
        Collections.sort(list,com1);
        System.out.println(list);
    }
}

Arrays中针对对象类型数组的sort方法有和Collections的sort方法类似的设计,通过实现Comparable接口或者使用Comparator回调的方式可以对对象数组进行排序

四、Set集合

Set用于存储不重复的对象集合,在Set集合中存储的对象中不存在两个对象equals比较为true

1、HashSet

HashSet和TreeSet是Set集合两个常用的实现类,分别用hash表和排序二叉树的方式实现Set集合

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<Integer>();
        Random ran = new Random();
        int i=0;
        while (set.size()<20){
            set.add(ran.nextInt(100)); //将20个随机100以内的不重复整数,放入集合中
            i++;
        }
        System.out.println("循环次数:"+i); //循环次数可能大于20,重复的整数无法放入set集合中
        System.out.println(set);
    }
}

2、Set集合遍历

(1)Set集合不同于List集合,其中的元素不能和顺序的下标对应,无法从Set集合中取出特定的元素

(2)遍历Set集合中的元素只能调用其iterator方法,通过返回的Iterator对象来完成

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        set.add("one");
        set.add("four");
        set.add("three");
        set.add("hundred");
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String str = it.next();
            System.out.print(str+"   "); //hundred   four   one   three
        }
        System.out.println();
        
        for(String str: set){
            System.out.print(str+"   "); //hundred   four   one   three
        }
    }
}

3、HashSet和hashCode

(1)HashSet是Set接口的实现类,通过hash表的方式实现

(2)在将对象加入HashSet集合中时,需要获取对象的hashCode值通过hash算法索引到对应的存储空间

在这里插入图片描述

4、hashCode方法

(1)对于重写了equals方法的对象,一般要妥善的重写继承自Object类的hashCode方法(Object提供的hashCode方法将返回该对象所在内存地址的整数形式)

(2)重写hashCode方法需要注意两点:

  • 与equals方法的一致性,即equals比较返回true的两个对象其hashCode方法返回值应当相同

  • hashCode返回的数值应符合hash算法的要求,如果有很多对象的hashCode方法返回值都相同,则会大大降低hash表的效率,一般情况下可以使用IDE(如Eclipse)提供的工具自动生成hashCode方法

public class Point {
    private int x;
    private int y;

    Point(int x,int y){
        super();
        this.x = x;
        this.y = y;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public String toString() {
        return "x="+x+",y="+y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Point point = (Point) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

(3)如果不重写Point类的hashCode方法,如下代码返回false,尽管有两个对象的equals为true,但它们的hashCode返回值不相同(为各自的地址),hashSet将不会给这两个对象进行equals比较的机会

import java.util.HashSet;
import java.util.Set;

public class SetDemo01 {
    public static void main(String[] args) {
        Set<Point> set = new HashSet<Point>();
        set.add(new Point(2,3));
        set.add(new Point(4,1));
        System.out.println(set.contains(new Point(2,3))); //true
    }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鹿快跑~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值