JavaSE笔记16:集合(二)

28 篇文章 0 订阅

集合(二)

上一篇:集合(一)
下一篇:集合(三)

关于集合元素的remove

迭代过程中,不能直接通过集合删除元素,要通过迭代器删除元素

package se3.collection;

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

public class CollectionTest06 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(1);
        c.add(2);
        c.add(3);

        Iterator it = c.iterator();
        while (it.hasNext()){
            //编写代码时next()方法返回值类型必须是Object
            Object obj = it.next();
            //c2.remove();//直接通过集合去删除元素,没有通知迭代器,会报错
            //使用迭代器来删除
            it.remove();//删除的一定是迭代器指向的当前元素
            System.out.println(obj);
        }
        System.out.println(c.size());//0
    }
}
List接口特有方法
测试List接口中常用方法
  1. List集合存储元素特点:有序可重复

    有序:List集合中的元素有下标,从0开始,以1递增

    可重复:存储一个1,还可以在存储1

  2. List既然是Collection接口的子接口,那么肯定List接口有自己“特色”的方法:

    以下只列出List接口常用的方法

    ​ void add(int index,Object element)

    ​ Object get(int index)

    ​ int indexOf(Object o)

    ​ int lastIndexOf(Object o)

    ​ Object remove(int index)

    ​ Object set(int index,Object element)

package se3.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class ListTest01 {
    public static void main(String[] args) {
        //创建List类型的集合
        List myList = new ArrayList();
        //List myList = new LinkedList();
        //添加元素
        myList.add("A");//默认都是向集合末尾添加元素
        myList.add("B");
        myList.add("C");
        myList.add("C");
        myList.add("D");
        //在指定位置添加指定元素(第一个参数是下标)
        //使用不多,对ArrayList来说效率比较低
        myList.add(1,"KING");
        //迭代
        Iterator it = myList.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            System.out.print(obj + "  ");
        }
        //运行结果:A  KING  B  C  D

        System.out.println();
        //根据下标获取元素
        Object obj1 = myList.get(0);
        System.out.println(obj1);//A

        //因为有下标,所以list集合有自己比较特殊的遍历方式
        //通过下标遍历(List集合特有的方式,Set没有)
        for (int i = 0; i < myList.size(); i++) {
            Object object = myList.get(i);
            System.out.print(object + "  ");
        }//运行结果:A  KING  B  C  D
        System.out.println();
        //获取指定对象第一次出现处的索引
        System.out.println(myList.indexOf("KING"));//1
        //获取指定对象最后一次出现处的索引
        System.out.println(myList.lastIndexOf("C"));//4

        //删除指定下标的元素
        //删除下标为0的元素
        myList.remove(0);
        System.out.println(myList.size());//5

        //修改指定位置的元素
        myList.set(2,"Soft");
        //遍历
        for (int i = 0; i < myList.size(); i++) {
            Object object = myList.get(i);
            System.out.print(object + "  ");
        }
        //运行结果:KING  B  Soft  C  D  
    }
}
ArrayList集合
ArrayList集合初始化容量及扩容
1. 默认初始化容量是10(底层先创建长度为0的数组,当添加第一个元素的时候,初始化容量为10)
   2. 集合底层是一个Object[]数组
   3. ArrayList集合的扩容
         原容量的1.5倍
         ArrayList集合底层是数组,怎么优化?
              尽可能少的扩容,因为数组扩容效率低,建议使用ArrayList集合的时候预估计元素的个数,给定一个初始化容量。
   4. 数组优点:检索效率高
   5. 数组缺点:随机增删元素效率较低,以及数组无法存储大数据量(很难找到一块大的连续的存储空间)
   6. 向数组末尾添加元素,效率很高,不受影响
   7. 面试:这么多集合中,你用哪个集合最多?
      答:ArrayList集合,因为往数组末尾添加元素效率不受影响,另外,我们检索/查找某个元素的操作比较多。
   8.ArrayList集合是非线程安全的
package se3.list;

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

public class ArrayListTest01 {
    public static void main(String[] args) {
        //默认初始化容量是10
        List list1 = new ArrayList<>();
        System.out.println(list1.size());//0

        //指定初始化容量:20(数组长度是20)
        List list2 = new ArrayList(20);
        //集合的size()方法是获取当前集合中元素的个数,不是获取集合的容量
        System.out.println(list2.size());//0
        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list1.add(5);
        list1.add(6);
        list1.add(7);
        list1.add(8);
        list1.add(9);
        list1.add(10);
        System.out.println(list1.size());
        //再加一个元素
        list1.add(11);
        //这里容量扩大为原来的1.5倍(自动扩容)
        System.out.println(list1.size());//11
    }
}
构造方法
  1. new ArrayList();
  2. new ArrayList(20);
package se3.list;

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

//集合ArrayList的构造方法
public class ArrayListTest02 {
    public static void main(String[] args) {
        //默认初始化容量10
        List myList1 = new ArrayList();
        //指定初始化容量100
        List myList2 = new ArrayList(100);
        //创建一个HashSet集合
        Collection c = new HashSet();
        //添加元素到Set集合
        c.add(100);
        c.add(200);
        c.add(900);
        c.add(50);
        //通过这个构造方法就可以将HashSet集合转换成List集合
        List myList3 = new ArrayList(c);
        for (int i = 0; i < myList3.size(); i++) {
            System.out.println(myList3.get(i));
        }
        /*运行结果:
            50
            100
            900
            200
         */
    }
}
单向链表数据结构

对于链表数据结构来说:基本的单元是节点Node

对于单向链表来说,任何一个节点Node中都有两个属性:

  1. 存储的数据
  2. 下一节点的内存地址
单向链表示意图

在这里插入图片描述

增加元素图

在这里插入图片描述

删除元素图

在这里插入图片描述

链表的优点与缺点
  1. 优点:随机增删元素效率较高。(因为增删元素不涉及到大量元素位移)。如果遇到随机增删集合中元素的业务比较多时,建议使用LinkedList。
  2. 缺点:查询效率较低,每一次查找某个元素的时候都需要从头节点开始往下遍历。

ArrayList:把检索发挥到极致

LinkedList:把随机增删发挥到极致

package se3.list;

import java.util.LinkedList;
import java.util.List;

public class LinkedListTest01 {
    public static void main(String[] args) {
        /**
         * LinkedList集合底层也是有下标的
         * 注意:ArrayList之所以检索效率比较高,不是单纯因为下标的原因。是因为底层数组发挥的作用。
         * LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头节点一个一个遍历。
         */
        List list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        for (int i = 0; i < list.size(); i++) {
            Object obj = list.get(i);
            System.out.print(obj + "  ");
        }
        //输出结果:a  b  c 
    }
}
双向链表与LinkedList集合

双向链表的基本单元还是节点Node

双向链表结构图

在这里插入图片描述

package se3.list;

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

public class LinkedListTest01 {
    public static void main(String[] args) {
        /**
         * LinkedList集合底层也是有下标的
         * 注意:ArrayList之所以检索效率比较高,不是单纯因为下标的原因。是因为底层数组发挥的作用。
         * LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头节点一个一个遍历。
         */
        List list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        for (int i = 0; i < list.size(); i++) {
            Object obj = list.get(i);
            System.out.print(obj + "  ");
        }
        //输出结果:a  b  c
        /**
         * LinkedList集合有初始化容量吗?没有
         * 不管是LinkedList还是ArrayList,以后不需要关心具体是哪个集合
         * 因为我们要面向接口编程,调用的方法都是接口中的方法
         */
        System.out.println();
        List list2 = new ArrayList();//这样写表示底层用了数组
        //List list2 = new LinkedList();//这样写表示底层用了双向链表
        list2.add("123");
        list2.add("456");
        list2.add("789");
        for (int i = 0; i < list2.size(); i++) {
            System.out.print(list2.get(i) + "  ");
        }
        //输出结果:123  456  789
    }
}
Vector集合
package se3.list;

import java.util.*;
/**Vector
 * 1.底层也是一个数组
 * 2.初始化容量:10
 * 3.怎么扩容的?
 * Vector集合扩容的特点:10-->20-->40-->80
 *扩容之后是原容量的2倍
 * 4.ArrayList集合扩容特点:10-->15-->15*1.5
 * ArrayList扩容是原容量的1.5倍
 * 5.Vector中所有的方法都是线程同步的,都带有synchronized关键字
 * 是线程安全的。效率比较低,使用较少了。
 */
public class VectorTest {
    public static void main(String[] args) {
        //创建一个集合
        List v = new Vector();
        //Vector v = new Vector();
        //默认容量10
        v.add(1);
        v.add(2);
        v.add(3);
        v.add(4);
        v.add(5);
        v.add(6);
        v.add(7);
        v.add(8);
        v.add(9);
        v.add(10);
        //满了之后扩容(扩容之后是20)
        v.add(11);

        Iterator it = v.iterator();
        while (it.hasNext()){
            Object object = it.next();
            System.out.print(object + " ");
        }//输出结果;1 2 3 4 5 6 7 8 9 10 11
	    
        /*
        怎么将一个线程不安全的ArrayList集合转换成线程安全的呢?
	    使用集合工具类:java.util.Collections;
 			java.util.Collection是集合接口
			java.util.Collections是集合工具类
	    */
        List mylist = new ArrayList();//非线程安全的
        //变成线程安全的
        Collections.synchronizedList(mylist);
        //myList集合就是线程安全的了
        mylist.add("111");
        mylist.add("222");
        mylist.add("333");
    }
}
泛型

泛型这种语法机制,只在程序编译阶段起作用,只是给编译器看的。(运行阶段泛型没用)

使用泛型的优点:
  1. 集合中存储的元素类型统一了
  2. 从集合中取出的元素类型是泛型指定的类型,不需要进行大量的向下转型
缺点

泛型的缺点:导致集合中存储的元素缺乏多样性!

注意:大多数业务中,集合的元素类型还是统一的。

package se3.collection;

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

public class GenericTest01 {
    public static void main(String[] args) {
        //不使用泛型机制,分析程序存在的缺点
        List myList = new ArrayList();
        //准备对象
        Cat c = new Cat();
        Bird b = new Bird();
        //将对象添加到集合当中
        myList.add(c);
        myList.add(b);
        //遍历集合,取出Cat让她抓老鼠,取出Bird让她飞!
        Iterator it = myList.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            //强制转型
            if (obj instanceof Animal){
                Animal a = (Animal)obj;
                a.move();
            }
            if(obj instanceof Cat){
                Cat c1 = (Cat)obj;
                c1.catMouse();
            }
            if(obj instanceof Bird){
                Bird b1 = (Bird)obj;
                b1.fly();
            }
        }
        //输出结果:
        //动物在移动!
        //猫在抓老鼠!
        //动物在移动!
        //鸟儿在飞翔!
    }
}
class  Animal{
    //父类自带的方法
    public void move(){
        System.out.println("动物在移动!");
    }
}
class Cat extends Animal{
    //特有方法
    public void catMouse(){
        System.out.println("猫在抓老鼠!");
    }
}
class Bird extends Animal{
    //特有方法
    public void fly(){
        System.out.println("鸟儿在飞翔!");
    }
}
package se3.collection;

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

public class GenericTest02 {
    public static void main(String[] args) {
        //使用泛型List<Animal2>之后,表示List集合中只允许存储Animal类型的数据
        //用泛型来指定集合中数据存储的数据类型
        List<Animal2> myList2 = new ArrayList<Animal2>();
        //指定list集合在只能存储Animal
        //myList2.add("abc");报错
        Cat2 c2 = new Cat2();
        Bird2 b2 = new Bird2();
        myList2.add(c2);
        myList2.add(b2);
        //获取迭代器
        //这个表示迭代器迭代的是Animal类型
        Iterator<Animal2> it2 = myList2.iterator();
        while (it2.hasNext()){
            //使用泛型之后,每一次迭代返回的数据类型都是Animal类型
            Animal2 a2 = it2.next();
            //如果直接使用Animal类型,不需要进行强制类型转换了,直接调用
            //a2.move();
            if(a2 instanceof Cat2){
                Cat2 x = (Cat2)a2;
                x.catMouse();
            }
            if (a2 instanceof Bird2){
                Bird2 y = (Bird2)a2;
                y.fly();
            }
        }
        //输出结果:
        //猫在抓老鼠!
        //鸟儿在飞翔!
    }
}
class  Animal2{
    //父类自带的方法
    public void move(){
        System.out.println("动物在移动!");
    }
}
class Cat2 extends Animal2{
    //特有方法
    public void catMouse(){
        System.out.println("猫在抓老鼠!");
    }
}
class Bird2 extends Animal2{
    //特有方法
    public void fly(){
        System.out.println("鸟儿在飞翔!");
    }
}
自动类型推断

JDK8之后引入了:自动类型推断机制(又称钻石表达式)

package se3.collection;

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

public class GenericTest03 {
    public static void main(String[] args) {
        //ArrayList<这里的类型会自动推断,前提是JDK8之后才允许>
        //自动类型推断
        //List<Animal2> myList3 = new ArrayList<Animal2>();
        List<Animal2> myList3 = new ArrayList<>();
        myList3.add(new Animal2());
        myList3.add(new Cat2());
        myList3.add(new Bird2());
        //遍历
        Iterator<Animal2> it3 = myList3.iterator();
        while (it3.hasNext()){
            Animal2 aa = it3.next();
            aa.move();
        }
        List<String> stringList = new ArrayList<>();
        //类型不匹配
        //stringList.add(new Cat2());
        //stringList.add(123);
        stringList.add("http://www.163.com");
        stringList.add("http://www.baidu.com");
        stringList.add("http://www.bjpownode.com");
        Iterator<String> its = stringList.iterator();
        while (its.hasNext()){
            String s = its.next();
            String newString = s.substring(7);
            System.out.println(newString);
        }
        /**
         * 运行结果:
         * 动物在移动!
         * 动物在移动!
         * 动物在移动!
         * www.163.com
         * www.baidu.com
         * www.bjpownode.com
         */
    }
}
自定义泛型

自定义泛型的时候,<>(尖括号)中的是一个标识符,随便写

java源码中经常出现的是和
1.E是Element单词首字母
2.T是Type单词首字母

package se3.collection;

public class GenericTest04<标识符随便写> {

    public void doSome(标识符随便写 o){
        System.out.println(o);
    }

    public static void main(String[] args) {
        GenericTest04<String> gt = new GenericTest04<>();
        //gt.doSome(100);报错:类型不匹配
        gt.doSome("qwq");//输出qwq
        //==========================================
        GenericTest04<Integer> gt2 = new GenericTest04<>();
        //gt2.doSome("阿波");报错:类型不匹配
        gt2.doSome(100);//输出100

        MyIterator<String> mi = new MyIterator<>();
        String s1 = mi.get();
        //Animal aaa2 = mi2.get();报错

        MyIterator<Animal> mi2 = new MyIterator<>();
        Animal aaa = mi2.get();
        //String s2 = mi2.get();报错

        //不用泛型就是Object类型
        GenericTest04 gt3 = new GenericTest04();
        gt3.doSome(new Object());
        gt3.doSome(200);
        gt3.doSome("阿波");
    }
}
class MyIterator<T>{
    public T get(){
        return null;
    }
}
集合使用foreach
package se3.collection;

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

public class ForEachTest01 {
    public static void main(String[] args) {
        //创建List集合
        List<String> stringList = new ArrayList<>();
        //添加元素
        stringList.add("hello");
        stringList.add("阿波");
        stringList.add("123");
        //遍历,使用迭代器方式
        Iterator<String> it = stringList.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.print(s + " ");
        }
        System.out.println();
        //使用下标的方式(只针对于有下标的集合)
        for (int i = 0; i < stringList.size(); i++) {
            System.out.print(stringList.get(i) + " ");
        }
        System.out.println();
        //使用foreach
        for (String s : stringList) {//因为泛型使用的是Sting类型,所以是String s
            System.out.print(s + " ");
        }
        System.out.println();
        
        List<Integer> list = new ArrayList<>();
        list.add(100);
        list.add(200);
        list.add(300);
        for (Integer i : list){//i代表集合中的元素
            System.out.print(i + " ");
        }
        /**
         * 输出结果:
         * hello 阿波 123 
         * hello 阿波 123 
         * hello 阿波 123 
         * 100 200 300 
         */
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值