集合框架及背后的数据结构、Collection,Map、ArrayList的使用

集合框架及背后的数据结构、Collection,Map、ArrayList的使用,第1张

集合框架及背后的数据结构、Collection,Map、ArrayList的使用 一、类和接口总览

Java 集合框架的优点及作用

  • 使用成熟的集合框架,有助于我们便捷、快速的写出高效、稳定的代码
  • 学习背后的数据结构知识,有助于我们理解各个集合的优缺点及使用场景

二、Collection 接口 1、Collection 常用方法
  • 将元素放入集合中、返回集合中的元素个数
import java.util.ArrayList;
import java.util.Collection;

public class TestDemo {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>();
        collection.add("hello");
        collection.add("world");
        System.out.println(collection.size()); // 2

        // 尖括号中 不能放简单的基本类型 一定是类类型
        Collection collection1 = new ArrayList<>();
        collection1.add(10);
    }
}
  • 删除集合中的所有元素、判断集合是否没有任何元素
import java.util.ArrayList;
import java.util.Collection;

public class TestDemo {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>();
        collection.add("hello");
        collection.add("world");
        System.out.println(collection); // [hello, world]
        collection.clear();
        System.out.println(collection); // []

        System.out.println(collection.isEmpty()); // true
    }
}
  • 返回一个装有所有集合中元素的数组

不建议进行整体的强制类型转换

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

public class TestDemo {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>();
        collection.add("hello");
        collection.add("world");
        Object[] objects = collection.toArray();
        System.out.println(Arrays.toString(objects)); // [hello, world]
    }
}
  • 如果元素 e 出现在集合中,删除其中一个
import java.util.ArrayList;
import java.util.Collection;

public class TestDemo {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>();
        collection.add("hello");
        collection.add("world");
        collection.remove("world");
        System.out.println(collection); // [hello]
    }
}

2、Map 接口 方法签名说明V get(Object k)根据指定的 k 查找对应的 vV getOrDefault(Object k, V defaultValue)根据指定的 k 查找对应的 v,没有找到用默认值代替V put(K key, V value)将指定的 k-v 放入 Mapboolean containsKey(Object key)判断是否包含 keyboolean containsValue(Object value)判断是否包含 valueSet> entrySet()将所有键值对返回boolean isEmpty()判断是否为空int size()返回键值对的数量
import java.util.ArrayList;
import java.util.Collection;

public class TestDemo {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("及时雨", "宋江");
        map.put("豹子头", "林冲");

        System.out.println(map.isEmpty()); // false
        System.out.println(map.size()); // 2

        String ret = map.get("及时雨");
        System.out.println(ret); // 宋江
        // 没有找到用默认值代
        System.out.println(map.getOrDefault("花和尚", "鲁智深")); // 鲁智深

        System.out.println(map.containsKey("豹子头")); // true
        System.out.println(map.containsValue("林冲")); // true

        // 不是按顺序
        System.out.println(map); // {豹子头=林冲, 及时雨=宋江}

        Set> entrySet = map.entrySet(); // 把k v组装成一个整体

        for (Map.Entry entry : entrySet) {
            System.out.println("key: "+entry.getKey()+" value:"+entry.getValue());
        }
    }
}

三、预备知识-泛型(Generic)

class MyArrayList代表这个类是一个泛型类,此时的这个E,就是一个占位符而已

public class Test {
    public static void main(String[] args) {
        // 把类型 参数化了
        MyArrayList myArrayList1 = new MyArrayList<>();
        MyArrayList myArrayList2 = new MyArrayList<>();
        MyArrayList myArrayList3 = new MyArrayList<>();
    }

泛型的意义:
1. 自动对类型进行检查
2. 自动对类型进行了强制类性转换

class MyArrayList {
    private E[] elem;
    private int usedSize;
    public MyArrayList() {
        this.elem = (E[])new Object[10];
    }
    public void add(E val) {
        this.elem[usedSize] = val;
        usedSize++;
    }
    public E get(int pos) {
        return this.elem[pos];
    }
}

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList<>();
        myArrayList.add("ABC");
        myArrayList.add("bit");
        String ret = myArrayList.get(1);
        System.out.println(ret); // bit

        MyArrayList myArrayList1 = new MyArrayList<>();
        myArrayList1.add(11);
        myArrayList1.add(22);
        int ret2 = myArrayList1.get(1);
        System.out.println(ret2); // 22
    }
}
  • 泛型中尖括号中的内容,不参与类型的组成

关于Object[] 强制类型转换的思考

		// 前提:Object数组进行向下转换
		String[] strings = new String[10];
        Object o1 = new String[10];
        Object[] o2 = new String[10];

JAVA提高六:泛型


泛型是怎么编译的?

泛型是编译时期的一种机制,擦除机制(-> Object)

Creating a Generic Array in Java
使用泛型数组时的注意事项:
数组和泛型之间的一个重要区别是它们如何强制执行类型检查。 具体来说,数组在运行时存储和检查类型信息。 然而,泛型在编译时检查类型错误,并且在运行时没有类型信息。


四、预备知识-包装类(Wrapper Class) 基本数据类型包装类byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBoolean
public class TestDemo {
    public static void main(String[] args) {
        String str = "123";
        int ret = Integer.valueOf(str);
        System.out.println(ret+1); // 124
    }
}
装箱(boxing)和拆箱(unboxing)
public class TestDemo {
    public static void main(String[] args) {
        Integer a = 123; //装箱  装包【隐式的】
        int b = a; //拆箱  拆包【隐式的】
        System.out.println(a+" " + b); // 123 123

        System.out.println("=============");

        Integer a2 = Integer.valueOf(123); //显示地装包
        Integer a3 = new Integer(123); // 显示地装包

        int b2 = a2.intValue(); // 显示地拆包
        double d = a2.doublevalue(); // 显示地拆包
        int i = 10; // 显示地初始化
    }
}

一道面试题:

public class TestDemo {
    public static void main(String[] args) {
        Integer a = 128;
        Integer b = 128;
        System.out.println(a == b); // false
    }
}


五、List
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList<>(20);

        ArrayList list2 = new ArrayList<>();
    }
}

  1. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  2. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  3. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  4. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  5. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

六、ArrayList使用 1、ArrayList的构造

public class Test {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        list.add("hello");
        list.add("bit");
        list.add("haha");
        System.out.println(list);

        // 使用另外一个ArrayList对list3进行初始化
        ArrayList list3 = new ArrayList<>(list);
    }
}
2、ArrayList的遍历
public class Test {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        list2.add("hello");
        list2.add("bit");
        list2.add("haha");
        // 重写了ToString()
        System.out.println(list2);
        System.out.println("================");
        for(int i = 0; i < list2.size(); i++) {
            System.out.print(list2.get(i)+" ");
        }
        System.out.println();
        System.out.println("==================");
        for (String s : list2) {
            System.out.print(s+" ");
        }
        System.out.println();
        System.out.println("========迭代器打印==========");
        Iterator it = list2.iterator();
        while (it.hasNext()) {
            System.out.print(it.next()+" ");
        }

        System.out.println();
        System.out.println("========迭代器List相关打印==========");
        ListIterator it2 = list2.listIterator();
        // Iterator it2 = list2.listIterator();
        while (it2.hasNext()) {
            System.out.print(it2.next()+" ");
        }
    }
}
Iterator 和 ListIterator 的区别
  • remove
public class Test {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        list2.add("hello");
        list2.add("bit");
        list2.add("haha");

        Iterator it = list2.iterator();
        while (it.hasNext()) {
            String ret = it.next();
            if(ret.equals("hello")) {
                it.remove(); // 首先需要使用next方法迭代出集合中的元素 ,然后才能调用remove方法
            }else {
                System.out.print(ret + " ");
            }
        }

        ListIterator it2 = list2.listIterator();
        while (it2.hasNext()) {
            String ret = it2.next();
            if(ret.equals("hello")) {
                it2.remove(); // 首先需要使用next方法迭代出集合中的元素 ,然后才能调用remove方法
            }else {
                System.out.print(ret + " ");
            }
        }
    }
}
  • add
    Iterator没有add方法
public class Test {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        // CopyOnWriteArrayList list2 = new CopyOnWriteArrayList<>(); // 线程安全的
        list2.add("hello");
        list2.add("bit");
        list2.add("haha");

        ListIterator it2 = list2.listIterator();
        while (it2.hasNext()) {
            String ret = it2.next();
            if(ret.equals("bit")) {
                it2.add("gaobo"); // 放到下一个
            }else {
                System.out.print(ret + " ");
            }
        }
        System.out.println("=================");
        System.out.println(list2);
        // hello haha =================
        // [hello, bit, gaobo, haha]
    }
}
3、ArrayList常见 *** 作

public class Test {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        list2.add("a");
        list2.add("b");
        list2.add("c");
        // add方法,默认放到数组的最后一个位置
        System.out.println(list2); // [a, b, c]
        
        list2.add(0, "hello");
        System.out.println(list2); // [hello, a, b, c]

        ArrayList list3 = new ArrayList<>();
        list3.add("我是测试List1");
        list3.add("我是测试List2");
        list3.add("我是测试List3");
        list2.addAll(list3); // [hello, a, b, c, 我是测试List1, 我是测试List2, 我是测试List3]
        System.out.println(list2);
    }
}

public class Test {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        list2.add("a");
        list2.add("b");
        list2.add("c");
        String ret = list2.remove(0);
        System.out.println(ret); // a
        System.out.println(list2); // [b, c]

		boolean flag = list2.remove("c");
        System.out.println(flag); // true
        System.out.println(list2); // [b]
    }
}

public class TestDemo {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        list2.add("a");
        list2.add("b");
        list2.add("c");
        String ret = list2.get(0);
        System.out.println(ret); // a
        System.out.println(list2); // [a, b, c]

        String ret2 = list2.set(0, "p");
        System.out.println("原来的字符串是:"+ret2); // 原来的字符串是:a
        System.out.println(list2); // [p, b, c]

        // 判断是否包含"p"
        System.out.println(list2.contains("p")); // true

        // 查找下标
        System.out.println(list2.indexOf("c")); // 2

        System.out.println(list2.lastIndexOf("c")); // 2

        // 清空
        list2.clear();
        System.out.println(list2); // []
    }
}
public class Test {
    public static void main(String[] args) {
        ArrayList list2 = new ArrayList<>();
        list2.add("a");
        list2.add("b");
        list2.add("c");
        list2.add("f");
        list2.add("g");
        List sub = list2.subList(1, 3);
        System.out.println(sub); // [b, c]

        sub.set(0, "bit");
        // 把截取的[b, c] 起始位置给了sub
        System.out.println(sub); // [bit, c]
        System.out.println(list2); // [a, bit, c, f, g]
    }
}

4、ArrayList的扩容机制

public class Test {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList<>(); // 初始的大小是几?答案是0
        list1.add("bit"); // 当第一次存放数据元素的时候,顺序表被分配大小为10
        System.out.println(list1);
        ArrayList list2 = new ArrayList<>(13); //初始大小是指定的13
    }

结论:

  • 如果ArrayList调用,不带参数的构造方法,那顺序表的大小0,第一次add时,整个顺序表才变为了10
    当这10个放满了,开始扩容,以1.5倍的方式扩容
  • 如果调用的是给定容量的构造方法,顺序表的大小就是你给定的容量,放满了还是以1,5倍进行扩容

5、模拟实现ArrayList
import java.util.Arrays;

class MyArrayList {
    private Object[] elementData;//数组
    private int usedSize;//代表有效的数据个数

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    public MyArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public MyArrayList(int capacity) {
        //对参数进行判断
        if(capacity > 0) {
            this.elementData = new Object[capacity];
        }else if(capacity == 0) {
            this.elementData = new Object[0];
        }else {
            throw new IllegalArgumentException("初始化的容量不能为负数");
        }
    }

    
    public boolean add(E e) {
        //确定一个真正的容量,预测->扩容【把检查顺序表空和满和扩容放到了一起】
        ensureCapacityInternal(usedSize+1);
        elementData[usedSize] = e;
        usedSize++;
        return true;
    }

    private void ensureCapacityInternal(int minCapacity) {
        //1、计算出需要的容量
        int capacity = calculateCapacity(elementData,minCapacity);
        //2、拿着计算出的容量,去看,满了扩容。空的也是。给一个明确的容量
        ensureExplicitCapacity(capacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        // 进不去if语句,数组还没有放满
        if (minCapacity - elementData.length > 0)
            //扩容了
            grow(minCapacity);
    }

    private static final int MAX_ARRAY_SIZE =  Integer.MAX_VALUE-8;

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍扩容
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE> 0)
            //说明你要的容量非常大
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //1、是否之前elementData数组分配过大小
        if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(10,minCapacity);
        }
        //2、分配过 就返回+1后的值
        return minCapacity;
    }

    
    public void add(int index,E e) {
        //1、检查下标是否合法
        rangeCheckForAdd(index);
        //2、确定真正的容量
        ensureCapacityInternal(usedSize+1);
        //3、挪数据
        copy(index,e);
        usedSize++;
    }

    private void copy(int index,E e) {
        for (int i = usedSize-1; i >= index ; i--) {
            elementData[i+1] = elementData[i];
        }
        elementData[index] = e;
    }

    private void rangeCheckForAdd(int index) {
        if(index < 0 || index > size()) {
            throw new IndexOutOfBoundsException("index位置不合法,不能插入!");
        }
    }

    
    public int size() {
        return this.usedSize;
    }

}

public class TestDemo {
    public static void main(String[] args) {

    }
}

七、练习 1、自定义数据类型

比特科技有若干学生(学生对象放在一个List中),每个学生有一个姓名(String)、班级(Strin和考试成绒属性(double)
某次考试结束后,每个学生都获得了一个考试成绩
遍历list集合,并把学生对象的属性打印出来

class Student {
    private String name;
    private String  classes;
    private double score;
    public Student(String name, String classes, double score) {
        this.name = name;
        this.classes = classes;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getClasses() {
        return classes;
    }
    public void setClasses(String classes) {
        this.classes = classes;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", classes='" + classes + ''' +
                ", score=" + score +
                '}';
    }
}

public class Test {
    public static void main(String[] args) {
        ArrayList students = new ArrayList<>();
        students.add(new Student("bit", "102-1", 10.9));
        students.add(new Student("zhangsan", "102-2", 70.9));
        students.add(new Student("lisi", "102-1", 50.9));
        System.out.println(students);
    }
}
2、使用Collections排序
public static void main(String[] args) {
        ArrayList integers = new ArrayList<>();
        integers.add(12);
        integers.add(53);
        integers.add(37);
        Collections.sort(integers); // [12, 37, 53]
        System.out.println(integers);
        Collections.reverse(integers);
        System.out.println(integers); // [53, 37, 12]
    }
3、Welcome to CVTE

删除第一个字符串中出现的第二个字符串中的字符
例:
String str1 = “welcome to CVTE”;
String str2 = “come”;
输出:wl t CVTE

public class Test {
    // 2
    public static void main2(String[] args) {
        // 用ArrayList
        String str1 = "welcome to CVTE";
        String str2 = "come";
        ArrayList list = new ArrayList<>();
        for (int i = 0; i < str1.length(); i++) {
            char ch = str1.charAt(i);
            if(!str2.contains(ch+"")) {
                list.add(ch);
            }
        }
        // System.out.println(list); // [w, l,  , t,  , C, V, T, E]
        for (char ch : list) {
            System.out.print(ch);
        }
    }

    // 1
    public static void main(String[] args) {
        String str1 = "welcome to CVTE";
        String str2 = "come";
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < str1.length(); i++) {
            char ch = str1.charAt(i);
            if(!str2.contains(ch+"")) {
                sb.append(ch);
            }
        }
        System.out.println(sb);
    }
}

5、扑克牌
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

class Card {
    private int rank; // 数字
    private String suit; // 花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    public String toString() {
        return "[ "+this.suit+":"+this.rank+" ]";
    }
}

public class TestDemo {
    public static final String[] suits = {"♥","♠","♣","♦"};

    public static List budCard() {
        ArrayList cards = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <= 13; j++) {
                
                cards.add(new Card(j, suits[i]));
            }
        }
        return cards;
    }

    // 交换
    public static void swap(List cards, int i, int j) {
        Card tmp = cards.get(i);
        cards.set(i, cards.get(j));
        cards.set(j, tmp);
    }

    // 洗牌
    public static void shuffle(List cards) {
        int size = cards.size();
        for (int i = size - 1; i > 0; i--) {
            Random random = new Random();
            int rand = random.nextInt(i);
            swap(cards, i, rand);
        }
    }

    public static void main(String[] args) {
        List cards =  budCard();
        System.out.println("买牌"+cards);

        shuffle(cards);
        System.out.println("洗牌"+cards);

        System.out.println("揭牌:3个人每人轮流揭5张牌");

        ArrayList> hand = new ArrayList<>();

        List hand1 = new ArrayList<>();
        List hand2 = new ArrayList<>();
        List hand3 = new ArrayList<>();

        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                Card card = cards.remove(0);
                hand.get(j).add(card);
            }
        }

        System.out.println("第1个人的牌:"+hand1);
        System.out.println("第2个人的牌:"+hand2);
        System.out.println("第3个人的牌:"+hand3);
        System.out.println("剩下的牌:"+cards);
    }
}

6、杨辉三角
class Solution {
    public List> generate(int numRows) {
        List> ret = new ArrayList<>();
        // 第一行
        List list1 = new ArrayList<>();
        list1.add(1);
        ret.add(list1); // 此时才把第一行的数据放到了ret中
        for (int i = 1; i < numRows; i++) {
            List list = new ArrayList<>();
            list.add(1); // 每行开始都是1
            List preRow = ret.get(i-1); // 上一行
            for (int j = 1; j < i; j++) {
                int num = preRow.get(j) + preRow.get(j-1);
                list.add(num);
            }
            list.add(1); // 结尾都是1
            ret.add(list);
        }
        return ret;
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5636585.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存