Java进阶第七章——数据结构:Collection

数据结构:Collection

本章所涉及到的数据结构知识可在数据结构学习记录中学习:
咖啡ice的数据结构学习记录

1.Collection常用方法

  • 没有使用“泛型”之前,Collection中可以存储Object中的所有子类型。

  • 集合不能直接存储基本数据类型,也不能存储java对象。只能存储java对象的内存地址。

  • Collection中常用方法:

    往集合里加元素:boolean add(Object e)

    获取集合中元素个数:int size()

    清空集合:void clear()

    判断集合是否包含元素:boolean contains(Object o)

    删除集合中某个元素:boolean remove(Object o)

    判断集合是否为空:boolean isEmpty()

    把集合转换成数组:Object[] toArray()

package collection;

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

public class CollectionTest {
    public static void main(String[] args) {
        //创建一个集合对象
        //Collection c = new Collection();  接口是抽象的,无法实例化
        Collection c = new ArrayList<>();//用一个父类型指向子类型。
        c.add(1200);//自动装箱,实际上放进去了一个对象的内存地址Integer x = new Integer(1200);
        c.add(new Object());
        System.out.println("集合中元素个数:"+ c.size());  //集合中元素个数:2
        //清空集合
        c.clear();
        System.out.println("集合中元素个数:"+ c.size());  //集合中元素个数:0

        c.add("ice");
        c.add("coffee");
        c.add("is");
        c.add("perfect");

        boolean flag = c.contains("coffee");
        System.out.println(flag); //true
        boolean flag2 = c.contains("coffee2");
        System.out.println(flag2); //false

        System.out.println("集合中元素个数:"+ c.size());  //集合中元素个数:4
        c.remove("is");
        System.out.println("集合中元素个数:"+ c.size());  //集合中元素个数:3

        System.out.println(c.isEmpty());  //false
        c.clear();
        System.out.println(c.isEmpty());  //true

        c.add("abc");
        c.add("def");
        c.add(100);
        c.add("ice-coffee");
        Object[] objs = c.toArray();
        for (int i = 0; i < objs.length; i++) {
            System.out.printf(objs[i] + " ");  //abc def 100 ice-coffee
        }

    }
}

  • 所有Collection通用的一种方法:迭代方式(也就是遍历)。

  • 在Map集合中不能用迭代器,而在Collection以及子类中使用。

  • 迭代器定义的变量类似于指针,且不是指向第一个元素。,可以使用两个方法来迭代对象Iterator中方法:

    ​ boolean hasNext() 如果仍有元素可以迭代(遍历),则返回true。如果false表示没有更多元素可以迭代。

    ​ Object next() 返回迭代的下一个元素。

    注:也就是说迭代器对象指向要输出位置的前一个位置

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest01 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        //存储时的类型和取出的类型一样
        c.add("ice");
        c.add("coffee");
        c.add(100);

        Iterator it = c.iterator();
        while(it.hasNext()){ //下一个元素存在,返回true
            System.out.printf(it.next() + "  ");  //ice  coffee  100
        }
    }
}
  • HashSet集合:无序不可重复
public class CollectionTest01 {
    public static void main(String[] args) {
        Collection c = new HashSet();
        //存进去和取出来顺序不一样
        c.add(100);+
        c.add(200);
        c.add(300);
        c.add(100);
        c.add(40);

        Iterator it = c.iterator();
        while(it.hasNext()){
            System.out.printf(it.next() + "  ");  //100  200  40  300 
        }
    }
}
  • contains()方法:

    boolean contains(Object o):判断集合中是否包含某个对象o,如果包含返回true,如果不包含返回false。

    注:在底层中,contains()方法调用equals()方法,所以放在集合里边的对象需要重写equals()方法。

public class CollectionTest01 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(new String("abc"));
        c.add(new String("def"));
        
        String x = new String("abc"); //由于String对象在new时会放到字符串常量池,创建相同的字段时会指向同一个位置。
        System.out.println(c.contains(x));  //true
        
        User u1 = new User("coffee");
        User u2 = new User("coffee");
        c.add(u1);  
        System.out.println(c.contains(u2));//这里没有重写,这个结果比较的是内存地址,结果是:false
    }
}
class User{
    private String name;
    public User(){

    }
    public User(String name){
        this.name = name;
    }
}

contains方法在底层会调用equals方法进行比较,所以这里对象重写了equals方法则会是true

public class CollectionTest {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        User u1 = new User("coffee");
        User u2 = new User("coffee");
        c.add(u1);
        System.out.println(c.contains(u2)); //true
    }
}
class User{
    private String name;
    public User(){  }
    public User(String name){ this.name = name; }
    //重写equals方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(name, user.name);
    }
}
  • remove()方法:

    boolean remove(Object o):删除集合中包含某个对象o,如果包含返回true,如果不包含返回false。

    注:在底层中,remove()方法调用equals()方法,所以放在集合里边的对象需要重写equals()方法。

public class CollectionTest01 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        String s1 = new String("hello");
        String s2 = new String("hello");
        c.add(s1);
        c.remove(s2);
        System.out.println(c.size());  //0
    }
}
  • 综上所属,remove和contains两个方法在底层都需要调用equals方法,所以放在集合里边的对象需要重写equals()方法。

2.List常用方法

  • List集合特点:每个元素有下标(下标从0开始),可以有重复元素。相当于数据结构中的线性表(数组)。

  • List作为Collection的子接口,list接口有自己常用的特色方法:

    在指定位置插入指定元素:void add(int index,E element)

    返回指定下标元素:E get(int index)

    返回元素第一次出现索引:int indexOf(Object o)

    返回元素最后一次出现索引:int lastIndexOf(Object o)

    移除指定下标元素:E remove(int index)

    用指定元素替换指定位置元素:E set(int index,E element)

package list;

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

public class ListTest{
    public static void main(String[] args) {
        //创建list类型集合
        List mylist = new ArrayList();
        //add()默认在数组末尾添加元素
        mylist.add("ice");
        mylist.add("coffee");
        mylist.add("is");
        mylist.add("nice");

        Iterator it = mylist.iterator();
        while(it.hasNext()){
            Object elt = it.next();
            System.out.printf(elt + " ");  //ice coffee is nice
        }

        System.out.println();  //分割线

        //add(index,element)在指定位置插入添加指定元素
        //这个方法使用效率低,使用情况较少
        mylist.add(1,"milk");
        Iterator it2 = mylist.iterator();
        while(it2.hasNext()){
            Object elt = it2.next();
            System.out.printf(elt + " ");  //ice milk coffee is nice
        }
        System.out.println();//分割线

        //根据下标获取元素get()方法
        System.out.println(mylist.get(0));  //ice


        //由于List有下标,List有独特的遍历方式for循环
        for (int i = 0; i < mylist.size(); i++) {
            System.out.printf(mylist.get(i) + " ");  //ice milk coffee is nice
        }

        System.out.println();//分割线
        //获取指定对象第一次出现处索引
        System.out.println(mylist.indexOf("is")); //3

        mylist.add(3,"coffee");
        //获取指定对象最后一次出现索引
        System.out.println(mylist.lastIndexOf("coffee")); //3

        //删除指定下标位置的元素
        mylist.remove(2);
        mylist.remove(1);
        for (int i = 0; i < mylist.size(); i++) {
            System.out.printf(mylist.get(i) + " ");  //ice coffee is nice
        }

        System.out.println();//分割线
        //修改指定位置元素
        mylist.set(3,"good");
        for (int i = 0; i < mylist.size(); i++) {
            System.out.printf(mylist.get(i) + " ");  //ice coffee is good
        }

    }
}
  • 注:计算机英语常用增删改查几个单词

    增:add、save、new

    删:delete、drop

    改:update、set、modify

    查:find、get、query、select

3.List实现类——ArrayList

  • ArrayList特性:

    ①ArrayList集合初始化容量是10。

    ②ArrayList集合底层是Object类型的数组Object[]。

    ③构造方法:new ArrayList(); 或者 List list2 = new ArrayList(20);

    ④一般给定一个预估价初始化容量,减少数组扩容次数。每次扩容会扩1.5倍。

    ⑤数组检索效率高,使用频率最多。

    ⑥随机增删元素效率比较低。但是在末尾增加效率高不受影响。

    ⑦ArrayList是非线程安全的

package list;

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

public class ArrayListTest {
    public static void main(String[] args) {
        //默认初始化容量10
        List list1 = new ArrayList();
        //size()方法是获取当前集合中元素个数,而不是获取集合容量。
        System.out.println(list1.size()); //0

        //指定初始化容量
        List list2 = new ArrayList(20);

        //通过构造方法将HashSet集合转换成List集合
        Collection c = new HashSet();
        c.add("ice");
        c.add("coffee");
        List list3 = new ArrayList(c);
        for (int i = 0; i < list3.size(); i++) {
            System.out.printf(list3.get(i) + " ");  //coffee ice 
        }
    }
}
  • 将非线程安全的ArrayList变成线程安全方法:Collections.synchronizedList
public class ArrayListTest {
    public static void main(String[] args) {
        List mylist = new ArrayList();
        Collections.synchronizedList(mylist);
        
        mylist.add("111");
    }
}

4.List实现类——LinkedList

  • LinkedList底层为双向链表数据结构。LinkedList集合底层也是有下标的,不过底层是双向链表,所以查找效率较低。

  • 与ArrayList对比:

    LinkedList在检索(查找)效率较低,在增删方面效率较高。

    ArrayList在检索(查找)效率较高,在增删方面效率较低。不过只在末尾添加元素时效率还是很高的。

    所以ArrayList比较常用。

import java.util.LinkedList;
import java.util.List;
public class LinkedListTest01 {
    public static void main(String[] args) {
        List list = new LinkedList();
        list.add("ice");
        list.add("coffee");
        for (int i = 0; i < list.size(); i++) {
            System.out.printf(list.get(i) + " ");
        }
    }
}

5.List实现类——Vector

  • Vector底层也是一个数组,初始化容量为10。
  • 扩容:扩容之后是原容量的2倍。
  • Vector中所有方法都是线程同步的,都带有synchronized关键字,是线程安全的,效率比较低,使用较少。

import java.util.Iterator;
import java.util.Vector;

public class VectorTest {
    public static void main(String[] args) {
        Vector vector = new Vector();
        vector.add(1);
        vector.add(2);
        vector.add(3);
        vector.add(4);
        vector.add(5);
        vector.add(6);
        vector.add(7);
        vector.add(8);
        vector.add(9);
        vector.add(10);

        Iterator it = vector.iterator();

        while(it.hasNext()){
            Object obj = it.next();
            System.out.printf(obj + " ");  //1 2 3 4 5 6 7 8 9 10 
        }
        
    }
}

6.机制补充—泛型

  • JDK5.0后推出的新特性:泛型

  • 在没有使用泛型时,it.next()取出来的是Object类型,使用起来不方便。

public class GenericTest {
    public static void main(String[] args) {
        List myList = new ArrayList();
        
        Cat c = new Cat();
        Bird b = new Bird();
        
        myList.add(c);
        myList.add(b);
        
        Iterator it = myList.iterator();
        while(it.hasNext()){

            // Animal a = it.next();迭代器取出的是Object,所以这么写会报错
            Object obj = it.next();
            if(obj instanceof Animal){
                Animal a = (Animal)obj;
                a.move();
            }
        }
    }
}
class Animal{
    public void move(){
        System.out.println("动物在移动");
    }
}
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}
class Bird extends Animal{
    public void fly(){
        System.out.println("鸟在飞");
    }
}
  • 在JDK5之后泛型机制,表示List中只允许存储某个类型(例如Animal)的数据,语法:List
  • 使用泛型,集合中元素类型能够统一。
public class GenericTest {
    public static void main(String[] args) {
        List<Animal> myList = new ArrayList<Animal>();
        Cat c = new Cat();
        Bird b = new Bird();
        myList.add(c);
        myList.add(b);
        //myList.add("abc");只能存储Animal类型的数据,不允许存储String或其他类型

        //这个表示迭代器迭代的是Animal类型
        Iterator<Animal> it = myList.iterator();
        while(it.hasNext()){
            //使用泛型后,每一次迭代返回的数据都是Animal类型
            Animal a =it.next();
            //不需要强制类型转换,直接调用
            a.move();
        }
    }
}
class Animal{
    public void move(){
        System.out.println("动物在移动");
    }
}
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}
class Bird extends Animal{
    public void fly(){
        System.out.println("鸟在飞");
    }
}
  • JDK8后引入,自动类型推断机制(即钻石表达式):List myList = new ArrayList<>();
public class GenericTest {
    public static void main(String[] args) {
        List<Animal> myList = new ArrayList<>();
        myList.add(new Animal());
        myList.add(new Cat());
        myList.add(new Bird());
        //myList.add("abc");只能存储Animal类型的数据,不允许存储String或其他类型
        Iterator<Animal> it = myList.iterator();
        while(it.hasNext()){
            Animal a = it.next();
            a.move();
        }
    }
}

  • 可以自定义泛型,自定义泛型时<>里边是一个标识符,可以随便写。一般写或者写
public class GenericTest<E> {
    public void doSome(E o){
        System.out.println(o);
    }
    public static void main(String[] args) {
        GenericTest<String> gt = new GenericTest<>();
        gt.doSome("icecoffee");
        //gt.doSome(123); 报错,类型不匹配

        GenericTest<Integer> gt2 = new GenericTest<>();
        //gt2.doSome("icecoffee");报错,类型不匹配
        gt2.doSome(123);
    }
}

7.增强for循环foreach

  • 增强for(foreach)语法:变量名是用来标记数组中的元素。

    for(元素类型 变量名 : 数组名){ }

public class ForEachTest {
    public static void main(String[] args) {
        int[] arr = {123,11,4,1453,45,21};
        for(int data : arr){
            System.out.printf(data + " "); //123 11 4 1453 45 21 
        }
    }
}
  • foreach有一个缺点:没有下标,在需要使用下标的循环中,不建议使用foreach
public class ForEachTest {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("ice");
        myList.add("coffee");
        myList.add("is");
        myList.add("nice");
        for (String s: myList) {
            System.out.printf(s + " ");  //ice coffee is nice 
        }
    }
}

8.Set常用方法

  • HashSet集合元素:存入时与取出时不一定一样,可重复,没有下标。
public class SetTest {
    public static void main(String[] args) {
        Set<String> strs = new HashSet<>();
        //HashSet中add实际上是存储到HashMap的key部分。
        strs.add("ice");
        strs.add("coffee");
        strs.add("coffee");
        strs.add("very");
        strs.add("good");
        strs.add("very");
        strs.add("good");

        for (String s:
             strs) {
            System.out.printf(s + " "); //very coffee ice good 
        }
    }
}
  • TreeSet集合:存入时与取出时不一定一样,不可重复,没有下标。但是存储的元素自动按照大小排序。
public class SetTest {
    public static void main(String[] args) {
        Set<String> strs = new TreeSet<>();
        strs.add("A");
        strs.add("C");
        strs.add("V");
        strs.add("R");
        strs.add("N");
        strs.add("J");
        strs.add("O");

        for (String s:
                strs) {
            System.out.printf(s + " "); //A C J N O R V
        }
    }
}

——本章节为个人学习笔记。学习视频为动力节点Java零基础教程视频:动力节点—JAVA零基础教程视频

你可能感兴趣的:(咖啡ice的Java学习记录,java,数据结构,python)