Java小记-集合类(超级无敌认真好用,万字收藏篇!!!!)

集合类

1 为什么要使用集合类?

集合类就是用于存储多个数据的类
在Java基础中我们学习了数组,而数据时可以存储多个数据的,为什么还要使用集合?

1.2数组的特点

  1. 用于存放多个数据
  2. 数组中的数据的数据类型是相同的
  3. 数组的长度固定
  4. 数组的操作需要开发人员自己定义相关操作算法

1.3 集合类的特点

  1. 集合类中可以存放多个数据
  2. 集合类中存放的数据的类型的任意类型(内部类型为Object类型,所以可以存放任意类型)
  3. 集合类的长度都是可变的
  4. 集合类中提供了关于这类集合的常用操作方法,开发人员可以通过这些方法实现对集合的常见操作

集合类不是一个类,而是一套接口和类的统称

2 Java中集合类的类结构

Java中的集合类根据存储方式不同分为两大类集合

  1. 基于Collection接口的线性集合

    Collection接口下有两个子接口,分别对应不同的线性集合

    1. List接口的特点

      (1).有序的集合(进入到集合中顺序和取出顺序一致)
      (2).可以存放重复数据的集合

      • List接口的的实现类:
        ①.ArrayList
        ②.LinkedList
        ③.Vector
    2. Set接口

      (1).无序的集合(不保证集合中元素的顺序)
      (2).不允许存放重复数据的集合

      • Set接口的实现类:
        ①.HashSet
        ②.TreeSet
  2. 基于Map接口的key-value映射对集合

3 基于List接口的ArrayList类的使用

ArrayList底层是基于动态数组实现的

3.1 ArrayList的特点

  1. ArrayList在使用时,查找其中的元素效率是比较高的,数组有下标,可以通过下标直接锁定到一个元素

  2. ArrayList在插入或移除元素时效率低(内存中要移位)

3.2 ArrayList常用API

  1. 创建ArrayList对象

    //创建ArrayList集合类对象
    ArrayList arrayList = new ArrayList();
    
  2. add(element):向ArrayList的尾部追加一个元素

    //向ArrayList的尾部追加元素
         arrayList.add("aaa");
         arrayList.add(20);
         arrayList.add('a');
         arrayList.add(true);
      arrayList.add(20.5);
    
  3. add(index,element):向集合中的某个位置插入一个元素

    //向ArrayList某个位置插入元素
         arrayList.add(2,"str")
    
  4. set(index,element) :替换集合中的某个元素

    //更改ArrayList替换位置的元素
         arrayList.set(2,"set")
    
  5. contains(element):检查集合是否有指定元素

    //检查ArrayList中是否含有指定元素
         arrayList.contains("set")
    
  6. isEmpty():检查容器是否为空

    arrayList.isEmpty()
    
  7. get(index):根据下标获得该下标对应的元素,默认返回Object类型(根据自己的需要转换具体类型)

    //根据下标获得一个元素
         String str= (String) arrayList.get(0);
         System.out.println(str);
    
  8. remove(element|index):

    如果参数为对象类型,则根据内容移除,如果参数为int类型的基本类型则根据下标移除

         //移除元素
         arrayList.remove("aaa");
         System.out.println(arrayList);
         //如果参数为int类型,则根据下标移除,如果要移除的内容为整数则需要使用Integer类型删除
         arrayList.remove(new Integer(3));
         System.out.println(arrayList);
    
  9. addAll():集合并集操作

            ArrayList<String> arrayList=new ArrayList<>();
            arrayList.add("1");
            arrayList.add("2");
            ArrayList<String> arrayList1=new ArrayList<>();
            arrayList1.add("我是一");
            arrayList1.add("我是二");
            arrayList.addAll(arrayList1);
    
  10. retainAll():集合交集操作

        ArrayList<String> arrayList2=new ArrayList<>();
        arrayList2.add("1");
        arrayList2.add("我是二");
        arrayList2.add("我是一");
        ArrayList<String> arrayList3=new ArrayList<>();
        arrayList3.add("我是一");
        arrayList3.add("我是二");
        boolean flag= arrayList2.retainAll(arrayList3);//判断是否交集成功
  1. removeAll():集合中差集操作

            ArrayList<String> arrayList4=new ArrayList<>();
            arrayList4.add("1");
            arrayList4.add("我是二");
            arrayList4.add("我是一");
            ArrayList<String> arrayList5=new ArrayList<>();
            arrayList5.add("我是一");
            arrayList5.add("我是二");
            boolean flag1=arrayList4.removeAll(arrayList5);
    
  2. 遍历ArrayList集合中的所有元素

    //遍历List集合中的所有元素
            //使用传统for循环遍历
            for(int i=0;i<arrayList.size();i++){
          
          
            Object obj = arrayList.get(i);
            System.out.println(obj);
            }
            System.out.println("---------------");
            //使用for循环加强版遍历
            for(Object obj : arrayList){
          
          
            System.out.println(obj);
            }
            System.out.println("---------------");
            //用迭代器遍历
            Iterator  iterator=arrayList.iterator();
            while(iterator.hasNext()
                System.out.println(iterator.next())
            }
            //使用list集合中的foreach方法进行遍历
            arrayList.forEach(System.out::println);
    

4 基于List接口的实现类Vector

4.1 Vector的特点

1.Vector的底层也是基于动态数组实现
2.Vector中提供的操作和ArrayList基本相同

4.2 ArrayList和Vector的区别

  1. 相同点:ArrayList和Vector底层都是基于动态数组实现,而且提供了相近的API
  2. 不同点:
    (1) ArrayList默认创建长度为0的数组,而Vector创建的长度为10的数组
    (2) Vector是线程安全的,而ArrayList是非线程安全的,在并发情况下建议使用Vector
    我们可以通过外部手段让ArrayList也是线程安全的

5 Vector的子类Stark

Stark栈容器,是Vector的一个子类,它实现了后进先出的栈

5.1 Stark的特点

后进先出

5.2 Stark常用api

  1. 创建Stark对象

     //实例化栈容器
        Stack<String> stack=new Stack<>();
    
  2. push() 入栈,压栈

    //入栈
            stack.push("one");
            stack.push("two");
            stack.push("three");
    
  3. pop() 出栈,弹栈(删除栈顶部对象,并返回他的值)

    //出栈  
    //获取栈容器元素
            System.out.println(stack.pop());
            System.out.println(stack.pop());
            System.out.println(stack.pop()); 
    
  4. empty() 检查栈容器是否为空

    //检查栈容器是否为空 
            System.out.println(stack.empty());
    
  5. peek() 读取栈顶元素

    //查看栈顶元素
            System.out.println(stack.peek());
    
  6. search() 返回栈元素在容器所在位置

    System.out.println(stack.search("one"));
    

5.3 Stark使用案例

  1. 判断元素对称性

    String str=“… {…[…(…)…]…}…(…)…[…]…” ;

    public class Test01 {
          
          
        public static void main(String[] args) {
          
          
            String str="... {.....[....(....)...]....}..(....)..[...]..." ;
            Stack<String> stack=new Stack<>();
            //假设修正法
            boolean flag=true;//假设是匹配的
            //拆分字符串获取字符
            for (int i=0;i<str.length();i++){
          
          
                char chars=str.charAt(i);
                if (chars == '['){
          
          
                    stack.push("]");
                }
                if (chars =='{'){
          
          
                    stack.push("}");
                }
                if (chars =='('){
          
          
                    stack.push(")");
                }
                //判断符号是否匹配
                if (chars =='}'||chars==']'||chars==')'){
          
          
                    if (stack.empty()){
          
          
                        flag=false;
                        break;
                    }
                    String str1= stack.pop();
                    if (str1.charAt(0)!=chars){
          
          
                        flag=false;
                        break;
                    }
                }
            }
            if (!stack.empty()){
          
          
                flag=false;
            }
            System.out.println(flag);
        }
    }
    

6 基于List接口的实现类LinkedList

LinkedList底层是基于链表实现

6.1 LinkedList的特点

1.插入或删除元素时效率高
2.查询及遍历元素时效率低

6.2 LinkedList常用API

  1. add(element):尾部添加
  2. addFirst(element):首部插入
  3. addLast(element):尾部插入
  4. add(index,element):指定下标位置插入元素
  5. push(element):入栈
  6. pop():出栈
  7. toArray():将列表转换为数组

7 基于Set接口的实现类HashSet

7.1 HashSet的特点

  1. 底层基于Map集合的实现
  2. 不能存放重复数据
  3. 集合中的元素不保证顺序
  4. Set集合无法从集合中直接获取某一个元素
  5. Set集合没有下标

7.2 HashSet常用API

1.add(element):向集合中添加一个元素
2.iterator():遍历集合中的所有元素

//遍历集合中元素
        Iterator<String> iterator = hashSet.iterator();
        //循环遍历集合中的每个元素
        while(iterator.hasNext()){
    
    //检测集合中是否存在要迭代的数据,true表示存在
            String str = iterator.next();//获取一个元素
            System.out.println(str);
        }

3.通过foreach循环遍历集合中所有元素

//使用foreach遍历集合中的所有元素
        for(String str : hashSet){
    
    
            System.out.println(str);
        }

4.使用foreach方法遍历集合中的元素

//通过foreach方法遍历集合中的所有元素
        hashSet.forEach(System.out::println);

8 基于Set接口的TreeSet实现

TreeSet是基于树状结构的Set集合,该集合可以排序,被称为可排序的Set集合

8.1 TreeSet集合的特点

1.TreeSet是一个有序的Set集合
2.TreeSet中不能存放重复数据
3.在TreeSet中存储的元素必须为可排序的元素(实现了比较器接口的对象),如果存储的元素为不可排序的元素则会报异常(ClassCastException)

9 基于key-value(键值对)的Map集合

Map集合中存储的元素为一个key对应一个value

9.1 Map集合的特点

1.key不允许重复,默认情况下key是Object类型,可以存放任意类型的数据
2.value是允许重复,默认情况下value是Object类型,可以存放任意类型的数据
3.Map中允许存在null的key(只能出现一次)和null的value

9.2 基于Map接口的实现类HashMap

HashMap中不允许存放重复key,如果新添加的key已存在,则使用新的value替换原有的value值

9.3 HashMap的常用API

1.put(key,val):向Map集合中添加一对key-value
2.get(key):根据key获得对应的value
3.remove(key):根据key移除Map集合中的一个元素
4.size():获得集合中元素的数量
5.keySet():获得Map集合中所有的key,返回一个包含所有key的set集合

        //获取hashmap中所有元素
        System.out.println(hashMap.keySet());
        for (String map :hashMap.keySet()){
    
    
            System.out.println(map+"<--------->"+hashMap.get(map));
        }
    }
}

6.values():获得Map集合中所有的value,返回一个Collection集合
7.entrySet():获得Map集合中每个元素的Entry集合对象,返回Set集合

for (Map.Entry<String,String> entry : map.entrySet()){
    
    
            System.out.println(entry.getKey()+"<--->"+entry.getValue());
        }

Map集合中的key不能重复,如果想Map添加一个新元素,Map集合如何判定该元素在集合中是否存在?

10 基于Map接口的TreeMap实现类

TreeMap和TreeSet一样都是一个可排序的集合
TreeMap中根据key进行排序的
进入到TreeMap中的元素(key)必须为可排序的元素(key)

11 附加知识点

  • Collections工具类

    • Collections常用api
      void sort(List) 对容器内元素进行排序
      void shuffle(List)对List中元素进行随机排序
      void reverse(List)对List中元素进行逆序排序
      void fill(List,Object)用一个特定的对象重写整个容器
      int binarySerach(List,Object)二分查找
      addAll(Collection,element…):一次性向集合添加多个元素
  • equals方法

==也是用于判断两个对象是否相等:用于判断两个对象是否为同一个对象的
equals方法用于判断两个对象的值是否相等

        String s1 = "abc";
        String s2 = "abc";
        //s1和s2两个变量都指向“abc”字符串对象,他们两个是同一个对象
        System.out.println(s1 == s2);
        /**
         * Java中每次使用new关键字创建对象时,在JVM的堆区都会自动创建一个新对象
         * 只不过两个对象的值都是"abc"字符串
         * 这两个对象不是同一个对象,但他们的值是相等
         * 所以“==”的结果为false,他们两个不是同一个对象
         * 如果要判断两个对象的值是否相等使用equals方法
         */
        String str = new String("abc");
        String str1 = new String("abc");
        System.out.println(str == str1);//false
        System.out.println(str.equals(str1));

equals方法在任意对象中都存在,该方法在Object类中定义的,他们默认定位为

 public boolean equals(Object obj) {
    
    
        return this == obj;
    }

从Object类中的源码可以看出,equals方法默认的定义为判断两个对象是否为同一个对象的
所以为了能够判断两个对象的值是否相等,我们在自己定义的实体类中都会重写该方法
String重写equals方法,JDK中大多数类都重写了该方法…

  • hashCode方法

hashCode方法在任意类中都存在,该方法也是在Object类中定义的
hashCode方法用于获得当前对象所对应的内存地址的hash码
如果两个对象的hash相等,则表示当前的两个对象肯定为同一个对象(默认情况)
开发人员可以根据实际需要重写hashCode,重写后不同对象的hashCode就有可能相等

在开发中一般会重写equals方法和hashCode方法以改变他们的默认行为

  • Map集合如何判断新添加的元素的key在集合中是否存在

1.先判断hashCode是否相等,如果hashCode不相等则认为没有相同的对象,直接将新元素添加到map集合中
2.如果hashCode的值存在相等的,则无法确定是否存在相同对象,进而继续判断equals方法,如果equals返回值为true,则认为存在相等元素
使用新元素替换原有的元素,如果equals判断是不相等,则认为不存在相同对象直接将新元素添加到map集合中

  • 比较器接口

比较器是用于定义比较规则,有了比较规则后,就可以对这些数据按照比较规则进行排序
Java中定义比较规则的方式有两种:

(1) 实现Comparable接口:Comparable在java.lang包下
- Comparable用于实现对象的默认比较规则,默认比较规则只有一种
- Comparable中存在一个compareTo方法,该方法用于定义比较规则
- 方法的返回值为正整数表示当前对象大于比较对象
- 方法的返回值等于0两个对象相等
- 方法的返回值为负整数表示当前对象小于比较对象

@Override
    public int compareTo(User user) {
    
    

        return this.userId - user.getUserId();
    }

(2) 实现Comparator接口:Comparator在java.util包下
- Comparator用于定义对象的扩展比较规则的,可以定义多个
- Comparator接口中有一个定义比较规则的方法compare(obj1,obj2)
- 方法的返回值为正整数表示obj1大于obj2
- 方法的返回值等于0两个对象相等
- 方法的返回值为负整数表示obj1小于obj2

/**
 * 使用内部类定义扩展规则
 * 1.根据积分升序排序
 */
    static class sortByScoreASC implements Comparator<User>{
    
    


    @Override
    public int compare(User user1, User user2) {
    
    
        return user1.getUserScore() - user2.getUserScore();
    }
}

/**
 * 2.根据积分降序排序
 */

static class sortByScoreDESC implements Comparator<User>{
    
    


    @Override
    public int compare(User user1, User user2) {
    
    
        return user2.getUserScore() - user1.getUserScore();
    }
}


    /**
     * 2.根据学号降序排序
     */

    static class sortByUserIdDESC implements Comparator<User>{
    
    


        @Override
        public int compare(User user1, User user2) {
    
    
            return user2.getUserId() - user1.getUserId();
        }
    }
    
    //调用
// TreeSet<User> users = new TreeSet<>();//使用user对象中的默认排序规则进行排序
       //使用User内定义的内部类指定排序规则
    // TreeSet<User> users = new TreeSet<>(new User.sortByUserIdDESC());
       //使用匿名内部类定义排序规则
    TreeSet<User> users = new TreeSet<>(new Comparator<User>() {
    
    
       //使用匿名内部类实现比较器接口
       @Override
       public int compare(User user1, User user2) {
    
    
          return user1.getRegDate().compareTo(user2.getRegDate());
       }
    });
  • transient关键字

将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。

1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。

2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。

3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

  • native关键字

Java不能直接访问操作系统及硬件底层,需要通过native关键字来实现对底层的控制,这就需要更底层的语言的支持了,这个就是native的作用


  • 学习来自于西安加中实训

猜你喜欢

转载自blog.csdn.net/woschengxuyuan/article/details/126262111
今日推荐