【Java】列表、集合、哈希表和可变参数

1 List

1.1 List的特点

  1. List接口继承自Collection接口
  2. List是有序集合,存取顺序一致
  3. 允许存储重复元素

1.2 List的特有方法【带索引】

  1. public void add(int index, E element);
  2. public E get(int index)
  3. public E remove(int index):返回移除元素
  4. public E set(int index, E element):替换指定位置的元素,返回更新前元素
  5. 遍历List:for+get+index(iterator、foreach非特有)

使用示例

public static void main(String[] args) {
    
    
        List<String> list = new ArrayList<>();
        //1.
        list.add("a");
        list.add("b");
        list.add("b");//可重复
        list.add("d");

        System.out.println(list);//[a, b, b, d]重写了toString直接打印列表 而不是地址
        //2.
        list.remove(2);

        System.out.println(list);//[a, b, d]
        //3.
        String s = list.get(1);

        System.out.println(s);//b
        //4.
        String result = list.set(2, "c");

        System.out.println(result);//d
        System.out.println(list);//[a, b, c]
    }

1.3 List的实现类

ArrayList:数组实现,查询快,增删慢
LinkedList:链表实现,查询慢,增删快

LinkedList特有方法:不能用多态

  1. addFirst(E, e) getFirst removeFirst
  2. addLast(E, e) getLast removeLast
  3. push(E e)
  4. pop()

使用示例

public static void main(String[] args) {
    
    
        LinkedList<String> list = new LinkedList<>();
        list.add("b");
        list.add("c");
        System.out.println(list);//[b, c]

        list.addFirst("a");
        System.out.println(list);//[a, b, c]
        list.addLast("d");
        System.out.println(list);//[a, b, c, d]

        list.push("1");//==addFirst
        System.out.println(list);//[1, a, b, c, d]
        list.pop();//==removeFirst
        System.out.println(list);//[a, b, c, d]

        String first = list.getFirst();
        String last = list.getLast();
        System.out.println(first+" "+last);// a d

        String s1 = list.removeFirst();
        String s2 = list.removeLast();
        System.out.println(s1+" "+s2);// a d
        System.out.println(list);//[b,c]
    }

2 Set

2.1 Set的特点

  1. Set接口继承自Collection接口
  2. 不允许存储重复元素
  3. 无索引,不能使用普通for循环遍历

2.2 Set的实现类

HashSet:无序集合、不同步、底层是哈希表(查询快)
使用HashSet

public static void main(String[] args) {
    
    
        Set<String> set = new HashSet<>();
        set.add("1");
        set.add("2");
        set.add("3");
        set.add("3");
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
    
    
            System.out.print(it.next() + " ");
        }
        System.out.println();
        for(String s: set){
    
    
            System.out.print(s+" ");
        }

    }

2.3 哈希表

哈希值:十进制整数,系统随机给出。(逻辑地址而非物理地址)
hashCode方法源码没有方法体 native代表调用本地操作系统的方法

public native int hashCode();

数据结构
jdk1.8之前:数组+链表
使用链表处理冲突,同一hash值的链表都存储在一个链表里。hash值相等的元素较多时,通过key值依次查找的效率较低
jdk1.8之后:数组+链表+红黑树(提高查询速度)
哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

Set集合判断元素是否重复:在调用add方法的时候会调用元素的hashCode方法和equals方法。如果hashCode一样,则发生了哈希冲突,调用equals方法判断两个元素是否相同,不相同时才存入表中。

前提:要重写equals方法和hashCode方法
原因:不重写:默认的equals()判断的是两个对象的引用指向的是不是同一个对象;而hashCode()根据对象地址生成一个整数数值;hashCode()的修饰符为native,表明该方法是否操作系统实现,java调用操作系统底层代码获取哈希值。

自定义类型存入HashSet
定义Person类

import java.util.Objects;

public class Person {
    
    
    String name;
    int age;

    public Person(String name, int age) {
    
    
        this.name = name;
        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;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    //属性的hash值
    public int hashCode() {
    
    
        return Objects.hash(name, age);
    }

定义测试类

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

public class HashSetTest {
    
    
    public static void main(String[] args) {
    
    
        Set <Person> persons = new HashSet<>();
        Person p1 = new Person("张三",30);
        Person p2 = new Person("张三",25);
        Person p3 = new Person("张三",30);
        System.out.println(p1.hashCode());//重写后:24022550
        System.out.println(p3.hashCode());//重写后:24022550
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        //重写了equals 认为同名同姓是一个人	重写前比较对象地址
        //重写了toString 打印对象属性信息 	重写前是包名.类型@16进制哈希值
        //重写了hashCode 					重写前是对象地址的hash值
        System.out.println(persons);//[Person{name='张三', age=30}, Person{name='张三', age=25}]
    }
}

2.4 LinkedHashSet

底层是哈希表(数组+链表/+红黑树)+链表,多加一条链表用来记录元素的存储顺序,保证元素有序

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

public class LinkedHashSetTest {
    
    
    public static void main(String[] args) {
    
    
        Set<String> hs = new HashSet<>();
        hs.add("def");
        hs.add("abc");
        hs.add("ghi");
        System.out.println(hs);//存取无序 [abc, def, ghi]
        Set<String> lhs = new LinkedHashSet<>();
        lhs.add("def");
        lhs.add("abc");
        lhs.add("ghi");
        System.out.println(lhs);//存取有序 [def, abc, ghi]
    }
}

3 可变参数

JDK1.5之后出现的新特性。当方法的参数列表数据类型已确定,但参数个数不确定,就可以使用可变参数。

修饰符 返回值类型 方法名(数据类型…遍历名){}

原理:底层是一个数组,根据参数个数的不同创建不同长度的数组,来存储这些参数传递的参数个数。

public static void main(String[] args) {
    
    
        int result = add(1,2,3,4,5);
        System.out.println(result);
    }
    //计算0~n个整数和的方法
    public static int add(int...nums){
    
    
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
    
    
            sum += nums[i];
        }
        return sum;
    }

4 Collections

4.1 常用功能

  1. addAll:往集合中添加一些元素
  2. shuffle:打乱集合顺序
  3. sort:按默认规则排序
  4. sort:按指定规则排序。this.排序属性 - 参数.排序属性:升序

在自定义类中重写

//implement Comparable<Person>
@Override
    public int compareTo(Person o) {
    
    
    	//初始认为元素相同
        //return 0;
        
        //自定义:
        //return this.getAge() - o.getAge();//按年龄升序
        //return this.getName() - o.getName();//按名字升序
        
        //组合排序:
        int result = this.getAge() - o.getAge();
        if(result == 0){
    
    
        	return this.getName() - o.getName();
        }
        return result;
    }

示例1 在定义类时实现接口并重写compareTo

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

        Collections.addAll(list,"a","b","c","d","e");
        System.out.println(list);//[a, b, c, d, e]

        Collections.shuffle(list);
        System.out.println(list);//[e, b, c, a, d]

        Collections.sort(list);//默认规则:升序排序
        System.out.println(list);//[a, b, c, d, e]

        ArrayList<Person> persons = new ArrayList<>();
        persons.add(new Person("张三",50));
        //sort使用前提是实现了Comparable接口重写CompareTo方法
        persons.add(new Person("李四",20));
        //对自定义类排序
        Collections.sort(persons);
        System.out.println(persons);
        //[Person{name='李四', age=20}, Person{name='张三', age=50}]
    }

示例2 在调用sort时 通过匿名对象进行重写

public static void main(String[] args) {
    
    
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6,7);
        Collections.shuffle(list);
        Collections.sort(list, new Comparator<Integer>() {
    
    
            @Override
            public int compare(Integer o1, Integer o2) {
    
    
                return o1 - o2;//升序
                //return o2 - o1;//降序
            }
        });
        System.out.println(list);
    }

猜你喜欢

转载自blog.csdn.net/xd963625627/article/details/105275487