栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java基础(十)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java基础(十)

前面的话
博客主页:hyhWTX的博客主页

欢迎关注点赞收藏⭐留言✒

本文由hyhWTX原创,csdn首发!

二十四.Set接口 一.接口

java.util.Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的补充,只是比Cooection接口更加严格了,与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。

Set集合有多个子类。

HashSet集合介绍:

java.util.HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致—)。Java.util.HashSet底层其实是一个java.util,HashMap支持。

HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此就有良好的存取和查找性能,保证元素唯一性的方式依赖于:hashCode与equals方法。

源码示例:

Person.java

package Day12.Hashcode;


public class Person extends Object{
    //重写HashCode方法

//    @Override
//    public int hashCode() {
//        return 1;
//    }
}

Demo01HashCode.java

package Day12.Hashcode;



public class Demo01HashCode {
    public static void main(String[] args) {
        //Person类继承Object类,所以可以使用Object里面的hashcode方法
        Person p1 = new Person();
        int h1 = p1.hashCode();
        System.out.println(h1);//21685669

        Person p2 = new Person();
        int h2 = p2.hashCode();
        System.out.println(h2);//2133927002

        
        System.out.println(p1);//Day12.Hashcode.Person@14ae5a5

        System.out.println(p2);//Day12.Hashcode.Person@7f31245a

        System.out.println(p1==p2);

        
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());

        System.out.println("重地".hashCode());
        System.out.println("通话".hashCode() );

    }
}

二.结构——hashmap

哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址),在Object类中有一个方法,可以获取对象的哈希值。int hashCode()返回该对象的哈希码值。

源码实例:

Person.java

package Day12.Hashcode;


public class Person extends Object{
    //重写HashCode方法

//    @Override
//    public int hashCode() {
//        return 1;
//    }
}

Demo01HashCode.java

package Day12.Hashcode;



public class Demo01HashCode {
    public static void main(String[] args) {
        //Person类继承Object类,所以可以使用Object里面的hashcode方法
        Person p1 = new Person();
        int h1 = p1.hashCode();
        System.out.println(h1);//21685669

        Person p2 = new Person();
        int h2 = p2.hashCode();
        System.out.println(h2);//2133927002

        
        System.out.println(p1);//Day12.Hashcode.Person@14ae5a5

        System.out.println(p2);//Day12.Hashcode.Person@7f31245a

        System.out.println(p1==p2);

        
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());

        System.out.println("重地".hashCode());
        System.out.println("通话".hashCode() );

    }
}

什么是哈希表呢?

在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储

在一个链表里,但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低,而JDK1.8中,哈希表存储采用数组+链表+红黑数实现,当链表长度超过阙值(8)时,将链表转换为红黑树,这样就大大减少了查找时间。

简单而言,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PAKMLKLx-1657717102995)(2022-07-09%201png.png)]

三.HashSet存储数据的结构

源码示例:

Demo02Set.java

package Day12.Set;

import java.util.HashSet;




public class Demo02Set {
    public static void main(String[] args) {
        //创建HashSet集合对象
        HashSet set = new HashSet<>();
        String s1 = new String("abc");
        String s2 = new String("abc");
        set.add(s1);
        set.add(s2);
        set.add("重地");
        set.add("通话");
        set.add("abc");
        System.out.println(set);

    }
}

 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yVFp7hjx-1657717102997)(2022-07-09%202.png)]

给HashSet中存放自定义类型元素时,需要重写对象中的HashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。

源码示例:

Person.java

package Day12.Set;

import java.util.Objects;


public 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 +
                '}';
    }
    //重写之后两者的equal值相同,存储一次
    @Override
    public boolean equals(Object o) {
        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 int hashCode() {
        return Objects.hash(name, age);
    }
}

Demo03Set.java

package Day12.Set;



import java.util.HashSet;



public class Demo03Set {
    public static void main(String[] args) {
        //创建HashSet集合存储Person
        HashSet set = new HashSet<>();
        Person p1 = new Person("小美女", 12);
        Person p2 = new Person("小美女", 12);
        Person p3 = new Person("小美女", 12);

        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());
        System.out.println(p1==p2);//两者的hashcode值不同
        set.add(p1);
        set.add(p2);
        set.add(p3);
        System.out.println(set);
    }
}

四.LinkedHashSet

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,该如何实现呢?在Hashset下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到 set s 中。)

**注意,此实现不是同步的。**如果多个线程同时访问链接的哈希 set,而其中至少一个线程修改了该 set,则它必须 保持外部同步。这一般通过对自然封装该 set 的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装”该 set。最好在创建时完成这一操作,以防止意外的非同步访问:

     Set s = Collections.synchronizedSet(new LinkedHashSet(...));
 

此类的 iterator 方法返回的迭代器是快速失败 的:在迭代器创建之后,如果对 set 进行修改,除非通过迭代器自身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来不确定的时间任意发生不确定行为的风险。

注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何强有力的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。

此类是 Java Collections Framework 的成员。

源码示例:

package Day12.Set;



import java.util.HashSet;
import java.util.LinkedHashSet;



public class Demo04LinkedHashSet {
    public static void main(String[] args) {
        HashSet set = new HashSet<>();
        set.add("www");
        set.add("abc");
        set.add("abc");
        ;
        set.add("itcast");
        System.out.println(set);//无序的,不允许重复

        LinkedHashSet linked = new LinkedHashSet<>();
        linked.add("www");
        linked.add("abc");
        linked.add("abc");
        linked.add("itcast");
        System.out.println(linked);//有序,且不允许重复
    }
}
五.可变参数

在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化成如下格式:

修饰符 返回值类型 方法名(参数类型...形参名){}

书写等价于:

修饰符 返回值类型 方法名(参数类型...形参名){}

只是后面的这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。

JDK1.5以后,出现了简化操作。…用于参数上,称之为可变参数。

同样是代表数组,但是在调用这个带有可变参数的方法时,不用创建数组(这就是简单之处),直接将数组中的元素作为实际参数进行传递,其实编译撑的class文件,将这些元素先封装到一个数组中,在进行传递,这些动作都在编译.class文件时,自动完成了。

注意事项:

  1. 一个方法的参数列表,只能有一个可变参数
  2. 如果方法的参数有多个,那么可变参数必须写在参数列表的末尾。

可变参数特殊写法

public static void method(Object ...object)//可接受任意类型的参数

源码示例:

package Day12.VarArgs;


public class Demo01Args {
    public static void main(String[] args) {
        int i = add(10,20,30,40,50,60,70,80,90,100);
        System.out.println(i);
    }

    
    public  static int add(int...arr){
        System.out.println(arr);//底层是一个数组



        //定义一个初始化的变量,记录累加求和
        int sum = 0;
        //遍历数组,获取数组中的每一个元素
        for (int i : arr) {
            //累加求和
            sum +=i;

        }
        //将求和结果返回
        return sum;
    }

//    //定义一个方法,计算三个int类型整数的和
//    public static  int add(int a,int b,int c){
//        return a+b+c;
//    }
//    //定义一个方法,计算两个int类型的整数的和
//    public static  int add(int a,int b){
//        return a+b;
//    }

}

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号