Surpass Day——Java List 接口、ArrayList集合、位运算、LinkedList集合、Vector集合、泛型、foreach

100 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

1、关于List接口

1)List集合存储元素特点:有序可重复

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

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

2)List接口中特有的常用方法:

添加元素到指定位置 void add(int index,E element)

返回列表中指定位置的元素 Object get(int index)

返回列表中第一个出现的指定元素的索引,如果不包含返回-1 int intdexOf(Object c)

返回列表中最后出现的指定元素的索引,如果不包含返回-1 int lastIndexOf(Object c)

移除列表中指定位置的元素(可选操作) Object move(Object o)

用指定元素替换列表中指定位置的元素(可选操作) Object set(int index,E element)

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
​
public class asdf{
    public static void main(String[] args) {
        //调用List特有的方法需要创建List引用
        List myList = new ArrayList();
        //添加元素
        myList.add("A");//默认都向集合末尾添加元素
        myList.add("B");
        myList.add("C");
        myList.add("D");
        myList.add("E");
        //在列表的指定位置插入元素(第一个参数是下标)
        myList.add(1,"KING");//这个方法使用的不多,因为效率太低
        //迭代
        Iterator it = myList.iterator();
        while(it.hasNext()){
            Object ect = it.next();
            System.out.println(ect);
        }
        //根据下标获取元素
        Object firstObj = myList.get(0);
        System.out.println(firstObj);
        //因为有下标,所以List集合有自己比较独特的遍历方式【通过下标】
        for(int i = 0;i<mylist.size();i++){
            Object obj = myList.get(i);
            System.out.println(obj);
        }
    }
}

2、ArrayList集合

2.1 Arrays工具类的使用

判断两个数组是否相等。 boolean equals(int[] a,int[] b)

输出数组信息。 String toString(int[] a)

将指定值填充到数组之中。 void fill(int[] a,int val)

对数组进行排序。 void sort(int[l a)

对排序后的数组进行二分法检索指定的值。 int binarySearch(int[] a,int key)

2.2 初始化容量

1)默认初始化容量是10(JDK13新特性:底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量为10)

注意:size方法测的是集合中元素的个数,不是集合的容量

2)集合底层是一个Object [ ] 数组

3)构造方法:

new ArrayList();
new ArrayList(20);

//指定初始化容量100
List myList2 = new ArrayList(100);
//创建一个HashSet集合
Collection c = new HashSet();
//添加元素到Set集合
c.add(100);
c.add(200);
c.add(900);
//通过这个构造方法就可以将HashSet集合转换成List集合
List myList3 = new ArrayList(c);
for(int i =0;i<myList3.size();i++){
    System.out.println(myList3.get(i));
}

2.3 扩容

1)默认初始化容量是10,容量满了之后如果再添加元素,自动扩容,扩容的大小是原来的1.5倍

2)ArrayList的底层是数组,尽可能少的扩容,因为数组扩容效率比较低。建议在使用ArrayList的是初始化容量给顶一个预估计的初始化容量,减少扩容

2.4 关于数组

优点:检索效率比较高;

缺点:随机增删元素的效率比较低;

向数组元素末尾添加元素,效率很高,不受影响;

3、位运算

// 5
// >> 1 二进制右移1位
// >> 2 二进制右移2位
// 10的二进制:00001010  【10】
// 10的二进制右移1位是:00000101 【5】

左移是乘以,右移是除以 2的n次方倍,n为移动的位数

4、LinkedList集合

4.1 链表的优缺点

链表的优点:空间存储内存地址不连续,随机增删元素效率较高(因为增删元素不涉及到大量的元素位移)

链表的缺点:查询效率较低,每一次查找某个元素的时候都需要从头节点开始往下遍历

ArrayList之所以检索效率高,不是单纯因为下标的原因,是因为底层数组发挥的作用

LinkedList集合照样有下标,但是检索某个元素的时候效率比较低,因为只能从头节点开始一个一个遍历

4.2 Java实现单链表

public class asdf{
    public static void main(String[] args) {
        Link link = new Link();
        link.add(100);
        link.add(200);
        link.add(300);
        System.out.println(link.size);
    }
}
class Node{
    //存储的数据
    Object data;
    //下一个结点的内存地址
    Node next;
    public Node(){
​
    }
    public Node(Object data,Node next){
        this.data = data;
        this.next = next;
    }
}
​
class Link {
    //头指针
    Node header = null;
​
    int size = 0;
​
    public int size(){
        return size;
    }
​
    //向链表中添加元素的方法
    public void add(Object data) {
        //创建一个新的节点对象
        //让之前单链表的末尾节点next指向新节点对象
        if(header == null) {
            //说明还没有节点,new一个新的节点对象,作为头节点对象
            header = new Node(data,null);
        }else{
            //说明头结点已经有了
            //找出当前末尾节点,让当前末尾节点的next是新节点
            Node currentLastNode = findLast(header);
            currentLastNode.next = new Node(data,null);
        }
        size++;
​
    }
​
    //专门查找末尾结点的方法
    private Node findLast(Node node) {
        if(node.next == null) {
            //如果节点的next是空则为末尾节点
            return node;
        }
        return findLast(node.next);//递归
    }
​
    //删除链表中的某个数据的方法
    public void remove(Object obj){
​
    }
​
    //修改链表中的某个数据元素的方法
    public void modify(Object newobj){
​
    }
​
    //查找链表中某个元素的方法
    public int find(Object obj){
        return 1;
    }
}

4.3 关于LinkedList

1)LinkedList集合没有初始化容量

2)最初这个链表中没有任何元素。first和last引用都是null

3)不管是LinkedList还是ArrayList,以后写代码不需要关系是哪个集合,我们需要面向接口编程,调用的方法都是接口中的方法

List list2 = new ArrayList();//这样写表示底层用的是数组
List list2 = new LinkedList();//这样写表示底层用的是双向链表
List2.add("123");
List2.add("456");
List2.add("789");
//这些方法都是面向的是接口编程


5、Vector集合

5.1 关于Vector集合

1)底层是一个数组

2)初始化容量是10

3)超过10后自动扩容,每次扩容是原容量的2倍

import java.util.Iterator;
import java.util.List;
import java.util.Vector;
​
public class java{
    public static void main(String[] args) {
        List l = new Vector();
        l.add("123");
        l.add("456");
        l.add("789");
        l.add("122");
        Iterator as = l.iterator();
        while(as.hasNext()){
            Object object = as.next();
            System.out.println(object);
        }
    }
}

4)Vector中的所有方法都是线程同步的,都带有synchronized关键字,是线程安全的。效率较低,使用较少

5.2 将不安全的ArrayList集合转换成线程安全

使用集合工具类 java.utill.Collections;

注意:java.utill.Collection 是集合接口

java.utill.Collections 是集合工具类

List myList = new ArrayList();//非线程安全的
//变成线程安全的
Collection.synchronizedList(myList);
//现在mylist就是线程安全的了

6、泛型

6.1 关于泛型

jdk1.5后的新特性

泛型这种语法机制只能在程序编译阶段起作用,只是给编译器参考的【运行阶段泛型意义不大】

优点:

1)集合中存储的元素类型统一了

2)从集合中取出的元素类型是泛型指定的类型,不需要进行大量的"向下转型"

缺点:

1)导致集合中元素缺乏多样性

2)调用父类中特有的方法不需要向下转型,但调用子类中特有的方法还是需要向下转型

6.2 泛型的具体使用

public class java{
    public static void main(String[] args) {
        /*List l = new Vector();
        Cat cat = new Cat();
        Dog dog = new Dog();
        l.add(cat);
        l.add(dog);
        Iterator it = l.iterator();
        while(it.hasNext()){
            Object object = it.next();
            //                                 使用泛型前需要向下转型
            if(object instanceof Animal){
                Animal a =(Animal)object;
                a.move();
            }
        }*/
        
        //使用泛型后
        List <Animal> l = new Vector<Animal>();
        //指定list集合只能存储Animal,那么存储String就编译报错了
        //这样使用泛型之后,集合中元素的数据类型更加统一
        Cat cat = new Cat();
        Dog dog = new Dog();
        l.add(cat);
        l.add(dog);
        //获取迭代器
        //表示迭代器迭代的是Animal类型
        Iterator <Animal>it = l.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 move(){
        System.out.println("猫在吃鱼");
    }
}
class Dog extends Animal{
    public void move(){
        System.out.println("狗在吃肉");
    }
}

6.3 类型自动推断【钻石表达式】

ArrayList<这里的类型会自动推断>(),前提是jdk8之后才允许

List myList = new ArrayList <> ();

6.4 自定义泛型

<>尖括号里面的是一个标识符,随便写

一般是,

E是Element单词首字母

T是Type单词首字母

public class asdf<E>{
    public void Do(E o){
        System.out.println(o);
    }
    public static void main(String[] args) {
        asdf<String> gt = new asdf<>();
        gt.Do("ssd");
    }
}

7、foreach【增强for循环】

jdk5.0之后的新特性

7.1 语法格式

for(元素类型 变量名:数组或集合){
    System.out.println(变量名);
}

7.2 增强for(foreach)

int[] arr = {43,34,3241,5463,23,1};
for(int data:arr){
    System.out.println(data);
}

data代表数组中的每一个元素,可以改变

缺点:没有下标

7.3 集合使用foreach

//创建List集合
List<String>strList = new ArrayList<>();
​
//添加元素
strList.add("hello");
strList.add("world");
strList.add("kitty");
​
//遍历使用选代器方式
Iterator<String> it = strlist.iterator();
while(it.hasNext()){
    String s = it.next();
    System.out.println(s);
}
​
//使用下标方式(只针对于有下标的集合)
for(int i = B; i < strList.size(); i++){
    System.out.println(strList.get(i));
}
​
//使用oreach
for(String s:strlist){  // 因为泛型使用的是String关星,所以是:String s
    System.out.println(s);
}
​