JavaSE高级开发之集合框架(上)

集合

集合的数目是可变的,并且集合只能存储引用数据类型,不能存放基本数据类型.
数组的长度不可变,数组既可以存放基本数据类型,又可以存放引用数据类型.
集合类的继承关系:
在这里插入图片描述
java.util.Collection是集合类的顶层接口,Collection使用泛型技术.

使用建议:

  1. 保存自定义对象的时候使用List接口;
  2. 保存系统类信息的时候使用Set接口(避免重复)

List接口

List接口在集合中被作为首选,因为List接口相比于Collection接口有一个get方法,可以根据索引取得内容.
List集合允许有重复的元素
List接口的常用方法:
1.在结合指定位置插入一个元素

public void add(int index,E element)

2.在集合指定位置插入集合c的所有元素

public boolean addAll(int index,Collection<? extends E> c)  

3.返回集合中指定位置的元素

public  E get(int index) 

4.返回集合中首次出现指定元素的索引,如果没有,返回-1.

public  int indexOf(Object o)  

5.返回列表中最后出现指定元素的索引,不包含返回-1.

public  int lastIndexOf(Object o) 

6.为ListIterator接口实例化,用于遍历集合中的元素.

public  ListIterator<E> listIterator() 

7.删除集合中指定位置的元素

public  E remove(int index) 

8.返回新的元素新的集合中包含start不包含end 的所有元素.

public List<E> subList(int fromIndex, int toIndex) 

9.返回此列表中的元素数

public  int size() 

List方法应用

public class AddTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
       //向集合中添加元素
        list.add("1");
        list.add(1,"2");//向当前集合索引为1的位置添加元素
        list.add("3");
        list.add("4");
        list.add("5");
        System.out.println("List集合:"+list);
        //向集合中的指定位置添加元素
        list.add(0,"0");
        list.add(0,"0");
        System.out.println(list);
        Collection<String> collection=new ArrayList<>();
        collection.add("00");
        collection.add("01");
        collection.add("02");
        //给集合中添加一个集合的所有内容,
        // 若不指定位置,则在当前集合的最后依次添加
        //向当前集合添加的集合,元素类型必须保持一致(当前都为String)
        list.addAll(collection);
        System.out.println(list);
        //删除元素
        list.removeAll(collection);//删除当前集合中指定集合的元素
        list.remove(2);//删除索引为2的元素
        list.remove("0");//删除内容为"00"的元素
        System.out.println(list);//-->[0, 2, 3, 4, 5]
    }
}

1.ArrayList类

ArrayList类是List的实现类,可以通过 ArrayList为List接口实例化, ArrayList是数组列表类,实现了可变长度的数组,允许对集合中的元素进行快速访问,但向ArrayList集合中插入或删除速度较慢.
ArrayList集合的新增方法:
1.如果需要,增加此 ArrayList实例的容量,以确保它可以至少保存最小容量参数指定的元素数

public void ensureCapacity(int minCapacity) 

2.从这个列表中删除所有索引在 fromIndex (含)和 toIndex之间的元素

protected void removeRange(int fromIndex, int toIndex) 

3.修改这个 ArrayList实例的容量是列表的当前大小。

public void trimToSize() 
public static void main(String[] args) {
        List<Integer> list=new ArrayList<>() ;
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list.isEmpty());
        System.out.println(list.contains("a"));
//通过调用集合的对象,可以打印出集合元素
        System.out.println(list);
//通过for循环打印集合
       for(int i=0;i<list.size();i++){
           System.out.print(list.get(i));
       }
        System.out.println("----------------------");
       
     //通过迭代方法打印集合,正向遍历
        ListIterator<Integer> iterator=list.listIterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next());
        }
        System.out.println(">>>>>>>>>>>");

        //通过迭代方法打印集合,反向遍历
       while(iterator.hasPrevious()){//此时游标已经移到了最末尾
           System.out.print(iterator.previous());
           System.out.print(" -> ");
       }

       
//通过对象数组接收集合元素,foreach打印集合

       //1.使用toArray方法需要强转(Collection接口中的内容),不推荐
      //Integer[]  integers1=(Integer[])list.toArray();//toArray, 返回值是Object[]
      
        //2.优化toArray方法
       Integer[] integers=new Integer[list.size()];
        list.toArray(integers);
       for(Integer i:integers){
           System.out.println(i);;
       }

向集合中保存简单的java类对象

public class SaveObject {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("jack",12));
        people.add(new Person("jay",23));
        people.add(new Person("Alice",33));
        System.out.println(people);
        
        //使用覆写的equals方法,返回值就为true
        //equals方法与hashCode方法要一起覆写
        //若不同时覆写,其hashCode的值依然不同,
        // 在Map中,KEY的值由hashCode决定,因此会造成有相同的元素出现.
        System.out.println(people.contains(new Person("jack", 12)));
        people.remove(2);
    }
}
class Person{
    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    
    //手工完成
//@Override
//    public boolean equals(Object obj){
//        if(obj==null){
//            return  false   ;
//        }
//        if(this==obj){
//            return true;
//        }
//        if(obj instanceof Person){
//            Person that=(Person)obj;
//             return this.getName().equals(that.getName()) &&
//                    this.getAge().equals(that.getAge());
//        }
//        return false;
//}

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

        Person person = (Person) o;

        if (!name.equals(person.name)) return false;
        return age.equals(person.age);
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age.hashCode();
        return result;
    }
}

2.Vector

Vector类是从JDK1.0就提出了的,其方法继承了List的方法,与ArrayList使用基本相同.

请解释ArrayList与Vector区别
1.历史时间:ArrayList是从JDK1.2提供的,而Vector是从JDK1.0就提供了。
2. 处理形式:ArrayList是异步处理,性能更高;Vector是同步处理,性能较低。
3. 数据安全:ArrayList是非线程安全;Vector是线程安全。
4. 输出形式:ArrayList支持Iterator、ListIterator、foreach;Vector支持Iterator(也是一个接口)、ListIterator、 foreach、Enumeration

//Enumeration已经不使用了,目前输出集合首选迭代器

public class VectorTest {
    public static void main(String[] args) {
        List<String> vector=new Vector<>();
        vector.add("hello");
        vector.add("java");
        vector.add("!!!");
        //已弃用
        Enumeration<String> enumeration=((Vector<String>) vector).elements();
        System.out.println(enumeration);
        
        //主要使用迭代器遍历输出集合
        Iterator<String> iterator=vector.listIterator();
        while (iterator.hasNext()){
            ((ListIterator<String>) iterator).add("---");
            
            //修改集合元素不能在迭代之前,会报错
           // ((ListIterator<String>) iterator).set("34");//error
            
            System.out.println(iterator.next()+",");
            //修改集合元素必须在遍历之后
            ((ListIterator<String>) iterator).set("***");
            ((ListIterator<String>) iterator).add("+");
        }

        for(int i=0,len=vector.size();i<len;i++){
            System.out.println(vector.get(i));
            // vector.add("sm");//添加删除操作不能在当前遍历打印下起作用
        }
    }
}

3. LinkedList类

LinkedList是一种链表实现

ArrayList与LinkedList的区别:
1.ArrayList里面存放的是一个数组
2.ArrayList的默认无参构造方法实例化,存储数据初始化是在第一次添加元素时进行的(lazy load)–扩容50%–默认容量10
3.ArrayList的初始容量的构造方法实例化,存储数据的数组立即初始化.

如果实例化此类对象时传入了数组大 小,则里面保存的数组就会开辟一个定长的数组,但是后面再进行数据保存的时候发现数组个数不够了 会进行数组动态扩充。 所以在实际开发之中,使用ArrayList最好的做法就是设置初始化大小。

set集合接口

set接口与list接口最大的不同在于set接口中的内容是不允许重复的,且set接口没有get()方法.set接口的两个子类:

  • HashSet是无序存储
  • Treeset是有序存储.

1.HashSet

HashSet的重复元素判断依赖于equals方法和hashCode方法。如果想要标识出对象的唯一性,一定需要equals方法和hashCode方法共同调用,只有当对象的equals方法和hashCode都相同时,才会将其判断为相同的对象

public class HashSetTest {
    public static void main(String[] args) {
        Set set<String>=new HashSet<>();
        set.add("hello");
        set.add("bit");
        set.add("hello");
        set.add("java");
        System.out.println(set);
    }
}
运行结果:[java, hello, bit]

2.TreeSet

TreeSet的重复元素判断依赖于Comparable接口,因此利用TreeSet集合存储数据的数据类型必须实现Comparable接口

 public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("java");
        set.add("hello");
        set.add("java");
        set.add("best");
        System.out.println(set);
    }
运行结果:[best, hello, java]

若需要TreeSet对指定普通泛型排序,就需要对对象数组进行排序,而对对象数组进行排序

TreeSet排序分析

TreeSet通过泛型指定数据类型,因此实质上TreeSet的排序是对对象数组(每一个类都是特殊的数据类型)进行的排序处理,因此要想实现排序,此类就得实现Comparable接口并且覆写compareTo方法(有必要覆写equals和hashCode方法)

方法一:在TreeSet的实例化对象构造方法中传入接口参数,利用匿名内部类或是lambda表达式实现Comparator接口

Set<Student> students=new TreeSet<>(
                new Comparator<Student>() {
                    @Override
                    public int compare(Student o1, Student o2) {
                        return o1.getAge()-o2.getAge();
                    }
                }
        );
        
        //        Set<Student> students=new TreeSet<>(
		//                (o1, o2) -> o1.getAge()-o2.getAge()
		//        );
         students.add(new Student(12, "liu"));
        students.add(new Student(13, "wang"));
        students.add(new Student(24, "wang"));
        students.add(new Student(14, "li"));
        System.out.println(students);
//自定义数据类型
class Student{
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

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

方法二:自定义数据类型通过实现接口实现排序

class Person implements Comparable<Person>{
private int age;
private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public int compareTo(Person o) {
        return this.age-o.getAge();//覆写compareTo方法定义比较策略
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

//若想改变比较策略,可通过将TreeSet对象传入Comparator接口的方法改变
        //这样改变的方法灵活,不需要去数据类型的内部改变compareTo方法
        Set<Person> people1=new TreeSet<>(
                new Comparator<Person>() {
                    @Override
                    public int compare(Person o1, Person o2) {
                        return (o1.getName()).compareTo(o2.getName());
                    }
                }
        );

猜你喜欢

转载自blog.csdn.net/weixin_42962924/article/details/84970880