Java集合

集合

什么是集合

  • 概念:对象的容器 ,实现了对对象常用的操作,类似数组功能
  • 和数字的区别:
    • 数组长度固定,集合长度不固定
    • 数组可以存储基本类型和引用类型,集合只能存储引用类型

Collection体系集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ImGVd54-1647852381270)(D:.李海旭\img\Collection集合框架.png)]

注意:Class Vector过时了

Collection父接口

理论
  • 特点:代表一组任意类型的对象,无序、无下标、不能重复
  • 方法
    • add(Object obj) //添加一个对象
    • addAll(Collection c) //将一个集合中所有的对象添加到此集合中
    • clear() //清空此集合中所有对象
    • contains(Object o) //检查此集合中是否包含o对象
    • equals(Object o) //比较此集合是否与指定对象相等
    • isEmpty() //判断此集合是否为空
    • remove(Object o) //在此集合中移除o对象
    • size()//返回此集合中的元素个数
    • toArray() //将此集合转换成数组

示例:

创建集合:
//创建集合
Collection collection = new ArrayList();//有顺序
添加集合:
//1、添加元素
collection.add("苹果");
collection.add("芭娜娜");
collection.add("芭娜娜");
collection.add("芭娜娜");
collection.add("榴莲");
System.out.println("元素个数"+collection.size());//元素个数5
System.out.println(collection);//[苹果, 芭娜娜, 芭娜娜, 芭娜娜, 榴莲]
删除集合
//2、删除元素
System.out.println("--------删除元素-------");
collection.remove("榴莲");
System.out.println(collection);
遍历元素【重点】
//3、遍历元素[重点]
System.out.println("------增强for------");
for (Object object : collection) {
    System.out.println(object);
}
//迭代器 专门用来遍历集合的一种方式
//hasNext(); 有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
System.out.println("-------迭代器--------");
Iterator it = collection.iterator();
while (it.hasNext()){
    String  s = (String) it.next();
    System.out.println(s);
    //在迭代的过程中不能使用改变集合元素的方法 如:
    //collection.remove(s);
    //但是可以这样
    it.remove();
}
判断
// 4、判断
collection.add("苹果");
System.out.println("0-----判断-----0");
System.out.println(collection.contains("苹果"));//true
System.out.println(collection.isEmpty());//false
补充
//删库跑路
System.out.println("-------清空--------");
collection.clear();
System.out.println(collection);
总:
package com.ytzlgjtx.chapter2jh.Demo1;/*Is FourEleven*/

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
* 接口的使用
* 1、添加元素
* 2、删除元素
* 3、遍历元素
* 4、判断
* */
public class Demo1 {
    public static void main(String[] args) {
        //创建集合
        Collection collection = new ArrayList();//有顺序
        //1、添加元素
        collection.add("苹果");
        collection.add("芭娜娜");
        collection.add("芭娜娜");
        collection.add("芭娜娜");
        collection.add("榴莲");
        System.out.println("元素个数"+collection.size());
        System.out.println(collection);
        //2、删除元素
        System.out.println("--------删除元素-------");
        collection.remove("榴莲");
        System.out.println(collection);
        //3、遍历元素[重点]
        System.out.println("------增强for------");
        for (Object object : collection) {
            System.out.println(object);
        }
        //迭代器 专门用来遍历集合的一种方式
        //hasNext(); 有没有下一个元素
        //next();获取下一个元素
        //remove();删除当前元素
        System.out.println("-------迭代器--------");
        Iterator it = collection.iterator();
        while (it.hasNext()){
            String  s = (String) it.next();
            System.out.println(s);
            //在迭代的过程中不能使用改变集合元素的方法 如:
            //collection.remove(s);
            //但是可以这样
            it.remove();
        }
        // 4、判断
        collection.add("苹果");
        System.out.println("0-----判断-----0");
        //判断集合中是否有苹果
        System.out.println(collection.contains("苹果"));//true
        //判断集合是否为空
        System.out.println(collection.isEmpty());//false

        //删库跑路
        System.out.println("-------清空--------");
        collection.clear();
        System.out.println(collection);
    }
}
遍历元素【迭代器的使用】

示例:

 迭代器使用方式:
 	首先创建Iterator接口  将集合存储进去
    循环查询 条件:集合的下一个不为null
    	将满足条件的进行强转 转换类型为:在创建collection时存储的类型
    	然后再进行输出
        示例:
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            student student = (student) iterator.next();
            System.out.println(student);
        }
        
        迭代器格式:
        Iterator 变量名 = 集合名.iterator();
        while (变量名.hasNext()){
            存储类 存储类变量名 = (存储类) 变量名.next();
            System.out.println(存储类变量名);
        }

实例:List集合

理论
  • 特点:有序、有下标、元素可重复

  • 方法:

    • .add(int index, Object o) //在index位置插入 o 对象

    • .addAll(int index,Collection c)//将一个集合的元素添加到此集合中的index位置

    • Object get (int index) //返回集合中指定位置的元素

    • List subList(int fromIndex,int toIndex)//返回fromIndex和toIndex之间的元素

      实例

实例

Demo类

package com.ytzlgjtx.chapter2jh.Demo1;/*Is FourEleven*/


import com.ysbjxxjd.Students;

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

/*
* 保存学生的信息
* */
public class Demo2 {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        student s1  = new student("张三",12);
        student s2  = new student("里斯",14);
        student s3  = new student("王五",16);
        //1.添加数据
        collection.add(s1);
        collection.add(s2);
        collection.add(s3);
        System.out.println(collection.toString());
        //删除
        collection.remove(s1);
        System.out.println("删除过后:"+collection.toString());
        //遍历 两种方式:
        //增强for
        System.out.println("-----for-------");
        for (Object object:collection ) {
            //转类型
            student s = (student)object;
            System.out.println(s.toString());
        }
        //迭代 hasNext(); next(); remove(); 迭代过程中 不能使用collection删除方法
        System.out.println("-------迭代器-------");
        Iterator it = collection.iterator();
        while (it.hasNext()){
            student s = (student) it.next();
            System.out.println(s.toString());
        }
        //判断
        System.out.println(collection.contains(s1));
        System.out.println(collection.contains(s2));
        System.out.println(collection.isEmpty());
    }
}
package com.ytzlgjtx.chapter2jh.Demo1;/*Is FourEleven*/
/*
* 学生类
*
* */
public class student {
    private String name;
    private int age;

    public student() {
    }

    public student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return
                "name='" + name + '\'' +
                ", age=" + age +
                '\n';
    }

}

List接口

  • 1、有序 有下标
  • 2、可以重复

List实例字符串类型

[List实例int类型](###List实例(int 类型))

List示例(字符串类型)

//创建对象
List list = new ArrayList();
list.add("是");
list.add("帅");
list.add("逼");
list.add(0,"我");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());

//删除
list.remove("我");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());

第一种:fori循环

System.out.println("----------fori-------");
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

第二种:foreach循环

System.out.println("------foreach--------");
for (Object o :
        list) {
    System.out.println(o);
}

第三种:迭代器

System.out.println("------迭代器---------");
Iterator it = list.iterator();
while (it.hasNext()){
    System.out.println(it.next());
}

第四种:列表迭代器(重点)

  • 列表迭代器6个方法
  • add(); 指定元素插入列表
  • hasNext();正向遍历列表有多个元素 如果下一个是元素 不是抛出异常 那么就返回true
  • hasPrevious();逆向遍历列表 列表有多个元素 则返回true
  • next(); 下一个元素
  • nextIndex(); 返回对next的下标
  • previous();返回前一个元素
  • previousIndex();返回前一个元素的下标
  • remove(); 从列表删除 next 或 previous的最后一个元素
  • set(E e); 用指定元素替换next 或 previous的最后一个元素
  • listIterator() 可以向前、后遍历,添加、删除、修改元素

从后向前输出

System.out.println("-------列表迭代器 前-后-----");
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
    System.out.println(lit.nextIndex()+":"+lit.next());
}

从后往前

//由于这是一个变量 上面的指针已经到最后面了 所以这里直接检测前一个并且输出
System.out.println("-------列表迭代器 后-前-----");
while (lit.hasPrevious()) {
    System.out.println(lit.previousIndex()+":"+lit.previous());
}

判断

//判断
System.out.println(list.contains("是"));//true
System.out.println(list.isEmpty());//false

获取元素下标

System.out.println(list.indexOf("是"));//0

全:

package com.ytzlgjtx.chapter2jh.Demo2;/*Is FourEleven*/

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
* List子接口 使用
* 1、有序 有下标
* 2、可以重复
* */
public class Demo {
    public static void main(String[] args) {
        //创建对象
        List list = new ArrayList();
        list.add("是");
        list.add("帅");
        list.add("逼");
        list.add(0,"我");
        System.out.println("元素个数:"+list.size());
        System.out.println(list.toString());
        //删除
        list.remove("我");
        System.out.println("元素个数:"+list.size());
        System.out.println(list.toString());
        //遍历 三种 for foreach 迭代器
        System.out.println("----------fori-------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("------foreach--------");
        for (Object o :
                list) {
            System.out.println(o);
        }
        System.out.println("------迭代器---------");
        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        /*
        * 列表迭代器
        * 6个方法
        * add(); 指定元素插入列表
        * hasNext();正向遍历列表有多个元素 如果下一个是元素 不是抛出异常 那么就返回true
        * hasPrevious();逆向遍历列表 列表有多个元素 则返回true
        * next(); 下一个元素
        * nextIndex(); 返回对next的下标
        * previous();返回前一个元素
        * previousIndex();返回前一个元素的下标
        * remove(); 从列表删除 next 或 previous的最后一个元素
        * set(E e); 用指定元素替换next 或 previous的最后一个元素
        * listIterator() 可以向前、后遍历,添加、删除、修改元素
        * */
        System.out.println("-------列表迭代器 前-后-----");
        ListIterator lit = list.listIterator();
        while (lit.hasNext()) {
            System.out.println(lit.nextIndex()+":"+lit.next());
        }
        //由于这是一个变量 上面的指针已经到最后面了 所以这里直接检测前一个并且输出
        System.out.println("-------列表迭代器 后-前-----");
        while (lit.hasPrevious()) {
            System.out.println(lit.previousIndex()+":"+lit.previous());
        }
        //判断
       System.out.println(list.contains("是"));//true
       System.out.println(list.isEmpty());//false
        //获取位置
       System.out.println(list.indexOf("是"));//0
    }
}

List示例(int 类型)

与字符串不同的是:

  • 根据下标来删除
  • 添加时自动装箱
  • 指定删除某一个元素时要转型

创建集合(增)

//创建集合
List list = new ArrayList();
//添加数字(过程中已经自动装箱了)
list.add(18);
list.add(13);
list.add(14);
list.add(17);
list.add(12);
list.add(14);
list.add(54);
list.add(64);
System.out.println(list.size());//长度
System.out.println(list.toString());//查看元素

.remove(2)

.remove(下标)

根据数字来删除:

remove((类型)(集合中某一个数字));

//删除
		list.remove(2);//根据下标来删除!!
		System.out.println(list.size());
		System.out.println(list.toString());//查看元素
//也可以根据数字来删除 转Object类型/new Integer
        list.remove(new Integer(54));
        list.remove((Object) 12);
        System.out.println(list.size());
        System.out.println(list.toString());

补充

补充方法subList() 返回集合

list.subList(开始,到结束);

//补充方法subList 返回集合
//list.subList(开始,到结束);
System.out.println("---list.subList----");
List sub = list.subList(1,3);
System.out.println(sub);//[13, 17]含头不含尾

package com.ytzlgjtx.chapter2jh.Demo2;/*Is FourEleven*/
import java.util.ArrayList;
import java.util.List;
/*
* list的使用
* */
public class Demo2 {
    public static void main(String[] args) {
        //创建集合
        List list = new ArrayList();
        //添加数字(过程中已经自动装箱了)
        list.add(18);
        list.add(13);
        list.add(14);
        list.add(17);
        list.add(12);
        list.add(14);
        list.add(54);
        list.add(64);
        System.out.println(list.size());//长度
        System.out.println(list.toString());//查看元素
        //删除
        list.remove(2);//根据下标来删除!!
        System.out.println(list.size());
        System.out.println(list.toString());//查看元素
        //也可以根据数字来删除 转Object类型/new Integer
        list.remove(new Integer(54));
        list.remove((Object) 12);
        System.out.println(list.size());
        System.out.println(list.toString());
        //补充方法subList 返回集合
        //list.subList(开始,到结束);
        System.out.println("---list.subList----");
        List sub = list.subList(1,3);
        System.out.println(sub);//[13, 17]含头不含尾
    }
}

List实现类–目录–

ArrayList【重点】:

  • 数组结构实现,查询快、增删慢。
  • JDK1.2版本,运行快、线程不安全

Vector:

  • 数组结构实现,查询快、增删慢。
  • JDK1.0版本,运行慢、线程安全

LinkedList:

  • 链表结构实现,增删快,查询慢。
方法说明
.add()添加元素
.size()元素个数
.remove()删除元素(可以是下标 或者是object类)
.clear()删除所有
.elements()枚举器
.contains()查询某个元素是否存在
.isEmpty()是否为空
.lastElement()查询最后一个元素

ArrayList【重点】:

  • 数组结构实现,查询快、增删慢。
  • JDK1.2版本,运行快、线程不安全

源码分析:

注意:如果没有像集合中添加任何元素时,容量为0

源码分析
DEFAULT_CAPACITY = 10;默认容量(添加元素之后的默认容量)
elementData存放元素的数组
EMPTY_ELEMENTDATA空的字符串
size实际元素个数
示例(Student类型)
创建集合
//创建集合
ArrayList arrayList = new ArrayList();
Student s1 = new Student("里的话",20);
Student s2 = new Student("黎明",20);
Student s3 = new Student("梁朝伟",20);
Student s4 = new Student("郭富城",20);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
System.out.println(arrayList.size());
System.out.println(arrayList.toString());
  • 普通删除
// 删除元素
arrayList.remove(s1);
System.out.println("s1删除过后:"+ arrayList.size());//3
  • 根据new Student 替换

arrayList.remove(new Student(“黎明”,20)); 这样删不了

解决方法:

在Student类中重写equals方法

Student类中

@Override
public boolean equals(Object o) {
    //1、是不是同意个对象
    if (this == o) {
        return true;
    }
    //2、判断是否为空
    if (o == null){
        return false;
    }
    //3、判断是否是Student类型

    if (o instanceof Student){
        Student s = (Student)o;
        //4、比较属性
        return this.name.equals(s.getName()) && this.age == s.getAge();
    }
    //5、都不满足就返回false
    return false;
}

Demo类

//删除元素
arrayList.remove(new Student("黎明",20));
System.out.println("new删除过后:"+ arrayList.size());//3
arrayList.remove(s1);
System.out.println("s1删除过后:"+ arrayList.size());//2

这样就可以进行准确删除了

遍历
  1. 迭代器
  2. 列表迭代器
  3. 列表迭代器(逆序)

迭代器

Iterator it = arrayList.iterator();
while (it.hasNext()) {
    //强转
    Student s = (Student)it.next();
    System.out.println(s.toString());
}

列表迭代器

//2、列表迭代器
ListIterator lit = arrayList.listIterator();
System.out.println("迭代器");
while (lit.hasNext()){
    Student s = (Student)lit.next();
    System.out.println(s.toString());
}

列表迭代器(逆序)

//2.1、列表迭代器 逆序
System.out.println("逆序");
while (lit.hasPrevious()){
    Student s = (Student)lit.previous();
    System.out.println(s.toString());
}
判断
//判断
System.out.println(arrayList.contains(new Student("梁朝伟",20)));//是否存在
System.out.println(arrayList.isEmpty());//是否为空
查询

查询元素位置

//查询
System.out.println("元素位置"+arrayList.indexOf(new Student("梁朝伟",20)));

说明:前面写删除的时候,已经重写了equals方法,所以这里才能直接new进行判断!

Demo类

package com.ytzlgjtx.chapter2jh.Demo3;/*Is FourEleven*/

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ListIterator;

/*
* ArrayList的使用
* 存储结构:数组,查询快 增删慢
*
* */
public class Demo {
    public static void main(String[] args) {
        //创建集合
        ArrayList arrayList = new ArrayList();
        // 添加元素
        Student s1 = new Student("里的话",20);
        Student s2 = new Student("黎明",20);
        Student s3 = new Student("梁朝伟",20);
        Student s4 = new Student("郭富城",20);
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        arrayList.add(s4);
        System.out.println(arrayList.size());
        System.out.println(arrayList.toString());
        // 删除元素
        //注意:
        //arrayList.remove(new Student("黎明",20));   这样删不了
        /*怎么样删?
            解决方法:
            在Student类种重写equals方法即可
        */
        arrayList.remove(new Student("黎明",20));
        System.out.println("new删除过后:"+ arrayList.size());//3
        arrayList.remove(s1);
        System.out.println("s1删除过后:"+ arrayList.size());//2

        // 遍历元素[重点]
        //1、使用迭代器
        Iterator it = arrayList.iterator();
        while (it.hasNext()) {
            //强转
            Student s = (Student)it.next();
            System.out.println(s.toString());
        }
        //2、列表迭代器
        ListIterator lit = arrayList.listIterator();
        System.out.println("迭代器");
        while (lit.hasNext()){
            Student s = (Student)lit.next();
            System.out.println(s.toString());
        }
        //2.1、列表迭代器 逆序
        System.out.println("逆序");
        while (lit.hasPrevious()){
            Student s = (Student)lit.previous();
            System.out.println(s.toString());
        }
        //判断
        System.out.println(arrayList.contains(new Student("梁朝伟",20)));//是否存在
        System.out.println(arrayList.isEmpty());//是否为空
        //查询
        System.out.println("元素位置"+arrayList.indexOf(new Student("梁朝伟",20)));
    }
}

Student类

package com.ytzlgjtx.chapter2jh.Demo3;/*Is FourEleven*/



/*
* 学生类
*
* */
public class Student {
    private String name;
    private int age;
    
    public Student() {}
    public Student(String name, int age) {this.name = name;this.age = age;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public int getAge() {return age;}
    public void setAge(int age) {this.age = age;}
    
    @Override
    public String toString() {
        return
                "name='" + name + '\'' +
                ", age=" + age +
                '\n';
    }
    
    @Override
    public boolean equals(Object o) {
        //是不是同意个对象
        if (this == o) {
            return true;
        }
        //判断是否为空
        if (o == null){
            return false;
        }
        //判断是否是Student类型

        if (o instanceof Student){
            Student s = (Student)o;
            //比较属性
            return this.name.equals(s.getName()) && this.age == s.getAge();
        }
        return false;
    }
}

Vector:

  • 数组结构实现,查询快、增删慢。
  • JDK1.0版本,运行慢、线程安全
示例
创建
//创建集合
Vector vector = new Vector();
添加元素
//添加元素
vector.add("草莓");
vector.add("西瓜");
vector.add("葡萄");
vector.add("西红柿");
vector.add("香蕉");
System.out.println("元素个数:"+vector.size());
删除
//删除
vector.remove(0);//删除下标为0的元素
vector.remove("西瓜");//删除"西瓜"
 //vector.clear();//删除所有
System.out.println("元素个数:"+vector.size());
遍历
//遍历
//除了fori foreach 等之外 可以用独有
// 枚举器
Enumeration en =  vector.elements();
while (en.hasMoreElements()){
    String s = (String) en.nextElement();
    System.out.println(s);
}
判断
//判断
System.out.println(vector.contains("西瓜"));
System.out.println(vector.isEmpty());
开小灶
//vector其他方法
vector.lastElement();//最后一个元素
package com.ytzlgjtx.chapter2jh.Demo4Vector;/*Is FourEleven*/

import java.util.Enumeration;
import java.util.Vector;

/*
* 演示 Vector 集合的使用
* */
public class demo {
    public static void main(String[] args) {
        //创建集合
        Vector vector = new Vector();
        //添加元素
        vector.add("草莓");
        vector.add("西瓜");
        vector.add("葡萄");
        vector.add("西红柿");
        vector.add("香蕉");
        System.out.println("元素个数:"+vector.size());
        //删除
        vector.remove(0);//删除下标为0的元素
        vector.remove("西瓜");//删除"西瓜"
        //vector.clear();//删除所有
        System.out.println("元素个数:"+vector.size());
        //遍历
        //除了fori foreach 等之外 可以用独有
        // 枚举器
        Enumeration en =  vector.elements();
        while (en.hasMoreElements()){
            String s = (String) en.nextElement();
            System.out.println(s); 
        }
        //判断
        System.out.println(vector.contains("西瓜"));
        System.out.println(vector.isEmpty());
        //vector其他方法
        vector.lastElement();//最后一个元素
    }
}

LinkedList:

  • 链表结构实现,增删快,查询慢。

跟前两个没太大的区别,查询方式的不同

直接看代码吧

package com.ytzlgjtx.chapter2jh.Demo5LinkedList;/*Is FourEleven*/

import com.ytzlgjtx.chapter2jh.Demo3.Student;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

public class Demo {
    public static void main(String[] args) {
        //创建集合
        LinkedList linked = new LinkedList<>();
        //添加
        Student s1 = new Student("里的话",20);
        Student s2 = new Student("黎明",20);
        Student s3 = new Student("梁朝伟",20);
        Student s4 = new Student("郭富城",20);
        linked.add(s1);
        linked.add(s2);
        linked.add(s3);
        linked.add(s4);
        System.out.println("元素个数:" + linked.size());
        System.out.println(linked.toString());
        //删除
        linked.remove(new Student("黎明",20));
        //linked.clear();//全部删除
        //遍历
        //1 fori
        for (int i = 0; i < linked.size(); i++) {
            System.out.println(linked.get(i));
        }
        //2 foreach
        for (Object o : linked) {
            Student s = (Student) o;
            System.out.println(o.toString());
        }
        //3 迭代器
        Iterator it = linked.iterator();
        while (it.hasNext()){
            Student s  = (Student) it.next();
            System.out.println(s.toString());
        }
        //4 列表迭代器
        ListIterator lit = linked.listIterator();
        while (lit.hasPrevious()){
            Student s  = (Student) lit.next();
            System.out.println(s.toString());
        }
        //判断
        System.out.println(linked.contains(s1));
        System.out.println(linked.isEmpty());
        //获取
        System.out.println(linked.indexOf(2));
    }
}

ArrayList和LinkedList的区别:

  1. LinkedList做插入、删除的时候,慢在寻址,快在只需要改变前后Entry的引用地址
  2. ArrayList做插入、删除的时候,慢在数组元素的批量copy,快在寻址

ArrayList:开辟的是一个连续的空间

LinkedList:开辟是一个一个开辟 所以增删快

如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tmiy0pLq-1647852381271)(D:.李海旭\img\ArrayList和LinkedList的区别.png)]

泛型

概述:

  • Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递
  • 常见形式有泛型类、泛型接口、泛型方法
  • 语法:
    • <T,…> T称为类型占位符,表示一种引用类型
  • 好处:
    • 1、提高代码的重用性
    • 2、防止类型转换异常,提高代码的安全性

泛型类

语法:

类名<T>

  • T:类型占位符,表示一种引用类型
  • 可以写多个 但是必须用,隔开

实例:

创建Generic类:

package chapter2jh.Demo6MyGeneric;/*Is FourEleven*/

public class MyGeneric<T> {
    //1、创建变量
    T t;
    //2、使用泛型创建方法
    public void show(T t){
        //可以创建对象 但是不能实例化 因为T只能是引用类型
        //T t1 = new T();
        System.out.println(t);
    }
    //3、使用泛型作为方法的返回值
    public T getT(){
        return t;
    }
}

使用Generic类:

package com.ytzlgjtx.chapter2jh.Demo6MyGeneric;/*Is FourEleven*/

public class MyGenericTest {
    public static void main(String[] args) {
        // 使用泛型类创建对象
        // new MyGeneric<String>();中<>的String可写可不写 JDK1.7之前必须写
        //String类型
        MyGeneric<String> myGeneric = new MyGeneric<String>();
        myGeneric.t = "hi!";
        myGeneric.show("字符串!!!");
        String s = myGeneric.getT();
        //Integer类型
        MyGeneric<Integer> myGeneric1 = new MyGeneric<>();
        myGeneric1.t = 200;
        myGeneric1.show(200);
        Integer i = myGeneric1.getT();

        //MyGeneric<String> myGeneric2 = myGeneric1;
    }
}

注意

  • 泛型只能是引用类型
  • 不同的泛型对象不能相互赋值(如myGeneric2)(18行)
  • new MyGeneric<String>();中<>的String可写可不写 JDK1.7之前必须写

泛型接口

泛型接口:表示接口中有一个未知的类型

语法:public interface 接口名<T>{}

  • 不能使用泛型静态常量

如下代码:实现了接口

public interface MyInterface<T> {
    String name = "张三";
    T sever(T t);

}

第一种方式:

继承时改变引用类型

package com.ytzlgjtx.chapter2jh.Demo6MyGeneric;/*Is FourEleven*/
/*
* MyInterface<String> 在这里已经将引用类型传进去了 所以重写方法的时候直接是String
* */
public class MyInterfaceImpl implements MyInterface<String>{
    @Override
    public String sever(String t) {
        System.out.println(t);
        return t;
    }
}

第二种方式:

没有确定引用类型 让类变成引用类型即可,但是在使用的时候要传引用类型!

package com.ytzlgjtx.chapter2jh.Demo6MyGeneric;/*Is FourEleven*/
/*
* 第二种方式: 没有确定引用类型是什么
* 那么就让类也变成泛型
* */
public class MyInterfaceImpl2<T> implements MyInterface<T>{

    @Override
    public T sever(T t) {
        System.out.println(t);
        return t;
    }
}

Test:

package com.ytzlgjtx.chapter2jh.Demo6MyGeneric;/*Is FourEleven*/

public class MyINterfaceText {
    public static void main(String[] args) {
        //第一种方式:
        MyInterfaceImpl impl = new MyInterfaceImpl();
        impl.sever("xxxxx");

        //第二种方式:   注意这里要传入引用类型!
        MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>();
        impl2.sever(1000);
    }
}

泛型方法

语法:

<T> 返回值类型

==注意:==只能在方法中使用!

public class MyGenericMethod {
    //泛型方法
    public<T> void show(T t){
        System.out.println("泛型方法:"+t);
    }
    
    //可以将返回值类型改为泛型
    public<T> T show2(T t){
        System.out.println("泛型方法:"+t);
        return t;
    }

}

Test:

package com.ytzlgjtx.chapter2jh.Demo6MyGeneric;/*Is FourEleven*/

public class MyGenericMethodTest {
    public static void main(String[] args) {
        MyGenericMethod mgm = new MyGenericMethod();
        //不用改变类型 (传什么类型 他就是什么类型)
        mgm.show("1999保密协议");//String
        mgm.show(200);//Integer
        mgm.show(3.14);//浮点数
    }
}

使用的时候不用改变类型

(传什么类型 他就是什么类型)

泛型集合

  • 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
  • 特点:
    • 编译时即可检查,而非运行时抛出异常
    • 访问时,不必类型转换(拆箱)
    • 不同泛型之间引用不能相互赋值,泛型不存在多态。

类型转换异常示例:

public static void main(String[] args) {
    ArrayList arrayList = new ArrayList();
    arrayList.add("xxx");
    arrayList.add("yyy");
    arrayList.add(10);
    arrayList.add(20);
    for (Object o : arrayList) {
        String str = (String) o;
        System.out.println(str);
    }
}

强转后无法进行输出,因为赋值的时候赋了不同的值

正确规范:

 public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("xxx");
        arrayList.add("yyy");
        //添加类型后,其他类型无法进行赋值
        //arrayList.add(10);
        //arrayList.add(20);
        for (String s : arrayList) {
            System.out.println(s);
        }

        ArrayList<Student> arrayList1 = new ArrayList<>();
        Student s1 = new Student("里的话",20);
        Student s2 = new Student("黎明",20);
        Student s3 = new Student("梁朝伟",20);
        Student s4 = new Student("郭富城",20);
        arrayList1.add(s1);
        arrayList1.add(s2);
        arrayList1.add(s3);
        arrayList1.add(s4);
        Iterator<Student> it = arrayList1.iterator();
        while (it.hasNext()){
            //此时比之前少了一步:强转
            Student s = it.next();
            System.out.println(s.toString());
        }
        //不同泛型不能相互赋值!!! 如:
        //arrayList1 = arrayList;
    }

注意:

  • 不同泛型不能相互赋值!!!
  • 添加类型后,其他类型无法进行赋值

Set接口

  • 特点:无序、无下标、元素不可重复
  • 方法:全部继承自Collection中的方法

HashSet的使用【重点】

  • 存储结构 哈希表(数组+链表++红黑树)

增删查判的基本操作与之前差不多

String类型
// 新建集合
HashSet<String> hashSet = new HashSet<>();
// 1.添加元素
hashSet.add("朦胧");
hashSet.add("666");
hashSet.add("李海旭");
hashSet.add("大帅逼");
System.out.println("元素个数:"+hashSet.size());
// 无序的
System.out.println(hashSet.toString());

// 2.删除
// hashSet.remove("666");
// System.out.println(hashSet.toString());

// 3.遍历
/*增强for*/
for (String s: hashSet) {
    System.out.println(s);
}
/*迭代器*/
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}
// 4.判断
System.out.println(hashSet.contains("666"));
System.out.println(hashSet.isEmpty());
自创用户类类型

main

// 创建集合
HashSet<Demo3Person> p = new HashSet<>();
// 1.添加数据
Demo3Person p1 = new Demo3Person("朦胧",12);
Demo3Person p2 = new Demo3Person("666",17);
Demo3Person p3 = new Demo3Person("李海旭",15);
Demo3Person p4 = new Demo3Person("大帅逼",14);
p.add(p1);
p.add(p2);
p.add(p3);
p.add(p4);
// 思考:怎么样才能让程序判断到这个跟p4一样?
p.add(new Demo3Person("大帅逼",14));
// 解决: 在Demo3Person中重写hashcode方法和equals方法来解决
/*
* 重写前:
5
[Demo3Person{name='666', age=17}, Demo3Person{name='大帅逼', age=14}, Demo3Person{name='朦胧', age=12}, Demo3Person{name='李海旭', age=15}, Demo3Person{name='大帅逼', age=14}]
* 重写后:
4
[Demo3Person{name='朦胧', age=12}, Demo3Person{name='李海旭', age=15}, Demo3Person{name='大帅逼', age=14}, Demo3Person{name='666', age=17}]
*/
System.out.println(p.size());
// 无序
System.out.println(p.toString());

// 2.删除元素
p.remove(p2);
// 因为之前重写了方法 所以现在可以删除
p.remove(new Demo3Person("大帅逼",14));
System.out.println(p.size());

// 3.遍历
for (Demo3Person dp :
        p) {
    System.out.println(dp);
}

Iterator<Demo3Person> iterator = p.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}

// 4.判断
System.out.println(p.contains(p3));
System.out.println(new Demo3Person("大帅逼",14));
System.out.println(p.isEmpty());

Demo3Person 类:

package com.ytzlgjtx.chapter2jh.Demo8Set;

import java.util.Objects;

/**
 * Description: 99LittleBugsInTheCode
 * Date: 2021-12-10-1:14
 */
public class Demo3Person{
    private String name;
    private int age;

    public Demo3Person() {
    }

    public Demo3Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
	// 输出
    @Override
    public String toString() {
        return "Demo3Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
	// 重写 HashCode 和 equals 方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Demo3Person that = (Demo3Person) o;
        return age == that.age && Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

重点:

// 1.添加数据
Demo3Person p1 = new Demo3Person("朦胧",12);
Demo3Person p2 = new Demo3Person("666",17);
Demo3Person p3 = new Demo3Person("李海旭",15);
Demo3Person p4 = new Demo3Person("大帅逼",14);
p.add(p1);
p.add(p2);
p.add(p3);
p.add(p4);
// 思考:怎么样才能让程序判断到这个跟p4一样?
p.add(new Demo3Person("大帅逼",14));
// 解决: 在Demo3Person中重写hashcode方法和equals方法来解决
/*
* 重写前:
5
[Demo3Person{name='666', age=17}, Demo3Person{name='大帅逼', age=14}, Demo3Person{name='朦胧', age=12}, Demo3Person{name='李海旭', age=15}, Demo3Person{name='大帅逼', age=14}]
* 重写后:
4
[Demo3Person{name='朦胧', age=12}, Demo3Person{name='李海旭', age=15}, Demo3Person{name='大帅逼', age=14}, Demo3Person{name='666', age=17}]
*/
System.out.println(p.size());
// 无序输出
System.out.println(p.toString());

TreeSet的使用

  • 数集
  • 存储结构:红黑树
  • 增删查判的基本操作与之前差不多
String类型
// 创建集合
TreeSet<String> treeSet = new TreeSet<>();
// 1.添加元素
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("com");
treeSet.add("hello");
//treeSet.add("hello");// 并不能添加
System.out.println(treeSet.size());
// 自动排序输出
System.out.println(treeSet.toString());
// 2.删除
treeSet.remove("hello");
// 3.遍历
for (String s :
        treeSet) {
    System.out.println(s);
}

Iterator<String> iterator = treeSet.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}
// 4.判断
System.out.println(treeSet.contains("xyz"));
System.out.println(treeSet.isEmpty());
自创用户类类型
  • 必须要实现Comparable接口
  • compareTo() 方法返回值为0 认为是重复元素

还是用Demo3中的类

Demo3Person 类:

更新:

1.在类中实现接口

 class Demo3Person implements Comparable<Demo3Person>

2.重写接口方法 如何比较的方法

    // 接口方法 :如何进行比较
    @Override
    public int compareTo(Demo3Person o) {
        // 比较规则
        // 姓名比较
        int name = this.getName().compareTo(o.getName());
        // 年龄比较
        int age = this.age-o.getAge();

        return name==0?age:name;
    }

总共改变:

package com.ytzlgjtx.chapter2jh.Demo8Set;

import java.util.Objects;

/**
 * Description: 99LittleBugsInTheCode
 * Date: 2021-12-10-1:14
 */
public class Demo3Person implements Comparable<Demo3Person>{
    private String name;
    private int age;

    public Demo3Person() {
    }

    public Demo3Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Demo3Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    // 接口方法 :如何进行比较
    @Override
    public int compareTo(Demo3Person o) {
        // 比较规则
        // 姓名比较
        int name = this.getName().compareTo(o.getName());
        // 年龄比较
        int age = this.age-o.getAge();

        return name==0?age:name;
    }
    // 重写 HashCode 和 equals 方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Demo3Person that = (Demo3Person) o;
        return age == that.age && Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

main中:

public static void main(String[] args) {
    // 创建集合
    TreeSet<Demo3Person> treeSet = new TreeSet<Demo3Person>();
    // 1.添加元素
    Demo3Person p1 = new Demo3Person("朦胧", 12);
    Demo3Person p2 = new Demo3Person("666", 17);
    Demo3Person p3 = new Demo3Person("李海旭", 15);
    Demo3Person p4 = new Demo3Person("大帅逼", 14);
    treeSet.add(p1);
    treeSet.add(p2);
    treeSet.add(p3);
    treeSet.add(p4);
    // 思考 添加后会报错 因为这是红黑树进行排列 程序无法准备判断
    System.out.println(treeSet.size());
    // 解决 要添加的类中添加接口
    System.out.println(treeSet.toString());
    // 2.删除
    treeSet.remove(p2);
    // 3.遍历
    for (Demo3Person s :
            treeSet) {
        System.out.println(s);
    }

    Iterator<Demo3Person> iterator = treeSet.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
    // 4.判断
    System.out.println(treeSet.contains(p4));
    System.out.println(treeSet.isEmpty());
更简洁的写法
  • Comparator 实现定制比较(比较器)–前面用的都是这个
  • Comparable 可比较的现在用这个
 // 创建集合
        TreeSet<Demo6Person> people = new TreeSet<>(new Comparator<Demo6Person>() {
            // 创建匿名类 重写比较规则
            @Override
            public int compare(Demo6Person o1, Demo6Person o2) {
                int name = o1.getName().compareTo(o2.getName());
                int age = o1.getAge()-o2.getAge();
                return age==0?name:age;
            }
        });
        // 添加
        Demo6Person p1 = new Demo6Person("朦胧", 12);
        Demo6Person p2 = new Demo6Person("666", 17);
        Demo6Person p3 = new Demo6Person("李海旭", 15);
        Demo6Person p4 = new Demo6Person("大帅逼", 15);
        people.add(p1);
        people.add(p2);
        people.add(p3);
        people.add(p4);
        System.out.println(people.toString());		

重点:

    TreeSet<Demo6Person> people = new TreeSet<>(new Comparator<Demo6Person>() {
        // 创建匿名类 重写比较规则
        @Override
        public int compare(Demo6Person o1, Demo6Person o2) {
            int name = o1.getName().compareTo(o2.getName());
            int age = o1.getAge()-o2.getAge();
            return age==0?name:age;
        }
    });

在这里直接传署名类 那么另一个类里面就无需实现接口了

package com.ytzlgjtx.chapter2jh.Demo8Set;

import java.util.Objects;

/**
 * Description: 99LittleBugsInTheCode
 * Date: 2021-12-10-1:14
 */
public class Demo6Person{
    private String name;
    private int age;

    public Demo6Person() {
    }

    public Demo6Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Demo3Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    // 重写 HashCode 和 equals 方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Demo6Person that = (Demo6Person) o;
        return age == that.age && Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
用TreeSet集合实现对字符串长度进行比较 从小到大排序
 //创建集合
        TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
            // 重写比较方法
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length() - o2.length();
                int n2 = o1.compareTo(o2);
                return n1==0?n2:n1;
            }
        });
        // 添加数据
        treeSet.add("helloWord");
        treeSet.add("99LittleBugsInTheCode");
        treeSet.add("FourEleven");
        treeSet.add("liSi");
        System.out.println(treeSet.toString());

重点:

	   @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length() - o2.length();
                int n2 = o1.compareTo(o2);
                return n1==0?n2:n1;
            }

重写方法的时候对长度进行判断

Map接口

特点:

  • 存储一对数据(Key-Value),无序,无下标,键不可重复,值可重复
  • 常用方法:
    • V put(K key,V value) //将对象存入到集合中,关联键值.key重复则覆盖原值
    • Object get (Object key) // 根据键获取对应的值
    • KeySet<K> // 返回所有的key
    • Collection<V> values() // 返回包含所有值的Collection集合
    • Set<Map.Entry<K,V>> // 键值匹配的Set 集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ke1WAUhv-1647852381272)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20211210173354142.png)]

映射对

HashMap[重点]

  • JDK1.2版本 , 线程不安全,运行效率快 允许使用null作为key或value

Hashtable

  • JDK1.0版本,线程安全,运行效率慢 不允许使用null作为key或value

Hashtable子类:Properties

  • 要求Key和value都是String,通常用于配置文件的读取

详细笔记参考

CSDN

集合概述


  • 概念:对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能。

  • 和数组的区别

  1. 数组长度固定,集合长度不固定。

  2. 数组可以存储基本类型和引用类型,集合只能存储引用类型。

  • 位置: java.util.*;

Collection体系集合


Collection父接口


  • 特点:代表一组任意类型的对象,无序、无下标、不能重复。

  • 方法

    • boolean add(Object obj) //添加一个对象。
    • boolean addAll(Collection c) //讲一个集合中的所有对象添加到此集合中。
    • void clear() //清空此集合中的所有对象。
    • boolean contains(Object o) //检查此集合中是否包含o对象。
    • boolean equals(Object o) //比较此集合是否与指定对象相等。
    • boolean isEmpty() //判断此集合是否为空。
    • boolean remove(Object o) //在此集合中移除o对象。
    • int size() //返回此集合中的元素个数。
    • Object[] toArray() //姜此集合转换成数组。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    COPY
    /**
    * Collection接口的使用(一)
    * 1.添加元素
    * 2.删除元素
    * 3.遍历元素
    * 4.判断
    */
    public class Demo1{
    pubic static void main(String[] args){
    //创建集合
    Collection collection=new ArrayList();
    // * 1.添加元素
    Collection.add("苹果");
    Collection.add("西瓜");
    Collection.add("榴莲");
    System.out.println("元素个数:"+collection.size());
    System.out.println(collection);
    // * 2.删除元素
    collection.remove("榴莲");
    System.out.println("删除之后:"+collection.size());
    // * 3.遍历元素
    //3.1 使用增强for
    for(Object object : collection){
    System.out.println(object);
    }
    //3.2 使用迭代器(迭代器专门用来遍历集合的一种方式)
    //hasnext();判断是否有下一个元素
    //next();获取下一个元素
    //remove();删除当前元素
    Iterator iterator=collection.Itertor();
    while(iterator.hasnext()){
    String object=(String)iterator.next();
    System.out.println(s);
    //删除操作
    //collection.remove(s);引发错误:并发修改异常
    //iterator.remove();应使用迭代器的方法
    // * 4.判断
    System.out.println(collection.contains("西瓜"));//true
    System.out.println(collection.isEmpty());//false
    }
    }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
COPY
/**
* Collection接口的使用(二)
* 1.添加元素
* 2.删除元素
* 3.遍历元素
* 4.判断
*/
public class Demo2 {
public static void main(String[] args) {
Collection collection=new ArrayList();
Student s1=new Student("张三",18);
Student s2=new Student("李四", 20);
Student s3=new Student("王五", 19);
//1.添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
//collection.add(s3);可重复添加相同对象
System.out.println("元素个数:"+collection.size());
System.out.println(collection.toString());
//2.删除数据
collection.remove(s1);
System.out.println("删除之后:"+collection.size());
//3.遍历数据
//3.1 增强for
for(Object object:collection) {
Student student=(Student) object;
System.out.println(student.toString());
}
//3.2迭代器
//迭代过程中不能使用collection的删除方法
Iterator iterator=collection.iterator();
while (iterator.hasNext()) {
Student student=(Student) iterator.next();
System.out.println(student.toString());
}
//4.判断和上一块代码类似。
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
COPY
/**
* 学生类
*/
public class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age +"]";
}
}

Collection子接口


List集合
    • 特点:有序、有下标、元素可以重复。

    • 方法

      • void add(int index,Object o) //在index位置插入对象o。
      • boolean addAll(index,Collection c) //将一个集合中的元素添加到此集合中的index位置。
      • Object get(int index) //返回集合中指定位置的元素。
      • List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之间的集合元素。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      COPY
      /**
      * List子接口的使用(一)
      * 特点:1.有序有下标 2.可以重复
      *
      * 1.添加元素
      * 2.删除元素
      * 3.遍历元素
      * 4.判断
      * 5.获取位置
      */
      public class Demo3 {
      public static void main(String[] args) {
      List list=new ArrayList<>();
      //1.添加元素
      list.add("tang");
      list.add("he");
      list.add(0,"yu");//插入操作
      System.out.println("元素个数:"+list.size());
      System.out.println(list.toString());
      //2.删除元素
      list.remove(0);
      //list.remove("yu");结果同上
      System.out.println("删除之后:"+list.size());
      System.out.println(list.toString());
      //3.遍历元素
      //3.1 使用for遍历
      for(int i=0;i<list.size();++i) {
      System.out.println(list.get(i));
      }
      //3.2 使用增强for
      for(Object object:list) {
      System.out.println(object);
      }
      //3.3 使用迭代器
      Iterator iterator=list.iterator();
      while (iterator.hasNext()) {
      System.out.println(iterator.next());
      }
      //3.4使用列表迭代器,listIterator可以双向遍历,添加、删除及修改元素。
      ListIterator listIterator=list.listIterator();
      //从前往后
      while (listIterator.hasNext()) {
      System.out.println(listIterator.next());
      }
      //从后往前(此时“遍历指针”已经指向末尾)
      while(listIterator.hasPrevious()) {
      System.out.println(listIterator.previous());
      }
      //4.判断
      System.out.println(list.isEmpty());
      System.out.println(list.contains("tang"));
      //5.获取位置
      System.out.println(list.indexOf("tang"));
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      COPY
      /**
      * List子接口的使用(二)
      * 1.添加元素
      * 2.删除元素
      * 3.遍历元素
      * 4.判断
      * 5.获取位置
      */
      public class Demo4 {
      public static void main(String[] args) {
      List list=new ArrayList();
      //1.添加数字数据(自动装箱)
      list.add(20);
      list.add(30);
      list.add(40);
      list.add(50);
      System.out.println("元素个数:"+list.size());
      System.out.println(list.toString());
      //2.删除元素
      list.remove(0);
      //list.remove(20);很明显数组越界错误,改成如下
      //list.remove(Object(20));
      //list.remove(new Integer(20));
      System.out.println("元素个数:"+list.size());
      System.out.println(list.toString());
      //3-5不再演示,与之前类似
      //6.补充方法subList,返回子集合,含头不含尾
      List list2=list.subList(1, 3);
      System.out.println(list2.toString());
      }
      }

      List实现类
      ArrayList【重点】
      • 数组结构实现,查询块、增删慢;
      • JDK1.2版本,运行效率快、线程不安全。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      COPY
      /**
      * ArrayList的使用
      * 存储结构:数组;
      * 特点:查找遍历速度快,增删慢。
      * 1.添加元素
      * 2.删除元素
      * 3.遍历元素
      * 4.判断
      * 5.查找
      */
      public class Demo5 {
      public static void main(String[] args) {
      ArrayList arrayList=new ArrayList<>();
      //1.添加元素
      Student s1=new Student("唐", 21);
      Student s2=new Student("何", 22);
      Student s3=new Student("余", 21);
      arrayList.add(s1);
      arrayList.add(s2);
      arrayList.add(s3);
      System.out.println("元素个数:"+arrayList.size());
      System.out.println(arrayList.toString());
      //2.删除元素
      arrayList.remove(s1);
      //arrayList.remove(new Student("唐", 21));
      //注:这样可以删除吗(不可以)?显然这是两个不同的对象。
      //假如两个对象属性相同便认为其是同一对象,那么如何修改代码?
      //3.遍历元素
      //3.1使用迭代器
      Iterator iterator=arrayList.iterator();
      while(iterator.hasNext()) {
      System.out.println(iterator.next());
      }
      //3.2使用列表迭代器
      ListIterator listIterator=arrayList.listIterator();
      //从前往后遍历
      while(listIterator.hasNext()) {
      System.out.println(listIterator.next());
      }
      //从后往前遍历
      while(listIterator.hasPrevious()) {
      System.out.println(listIterator.previous());
      }
      //4.判断
      System.out.println(arrayList.isEmpty());
      //System.out.println(arrayList.contains(new Student("何", 22)));
      //注:与上文相同的问题。
      //5.查找
      System.out.println(arrayList.indexOf(s1));
      }
      }

      :Object里的equals(this==obj)用地址和当前对象比较,如果想实现代码中的问题,可以在学生类中重写equals方法:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      COPY
      @Override
      public boolean equals(Object obj) {
      //1.是否为同一对象
      if (this==obj) {
      return true;
      }
      //2.判断是否为空
      if (obj==null) {
      return false;
      }
      //3.判断是否是Student类型
      if (obj instanceof Student) {
      Student student=(Student) obj;
      //4.比较属性
      if(this.name.equals(student.getName())&&this.age==student.age) {
      return true;
      }
      }
      //不满足,返回false
      return false;
      }
      ArrayList源码分析
      • 默认容量大小:private static final int DEFAULT_CAPACITY = 10;

      • 存放元素的数组:transient Object[] elementData;

      • 实际元素个数:private int size;

      • 创建对象时调用的无参构造函数:

      • 1
        2
        3
        4
        5
        COPY
        //这是一个空的数组
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
        public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }

        这段源码说明当你没有向集合中添加任何元素时,集合容量为0。那么默认的10个容量怎么来的呢?

        这就得看看add方法的源码了:

        1
        2
        3
        4
        5
        COPY
        public boolean add(E e) {
        ensureCapacityInternal(size + 1); // Increments modCount!!
        elementData[size++] = e;
        return true;
        }

        假设你new了一个数组,当前容量为0,size当然也为0。这时调用add方法进入到ensureCapacityInternal(size + 1);该方法源码如下:

        1
        2
        3
        COPY
        private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }

        该方法中的参数minCapacity传入的值为size+1也就是 1,接着我们再进入到calculateCapacity(elementData, minCapacity)里面:

        1
        2
        3
        4
        5
        6
        COPY
        private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
        }

        上文说过,elementData就是存放元素的数组,当前容量为0,if条件成立,返回默认容量DEFAULT_CAPACITY也就是10。这个值作为参数又传入ensureExplicitCapacity()方法中,进入该方法查看源码:

        1
        2
        3
        4
        5
        6
        COPY
        private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        grow(minCapacity);
        }

        我们先不要管modCount这个变量。

        因为elementData数组长度为0,所以if条件成立,调用grow方法,重要的部分来了,我们再次进入到grow方法的源码中:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        COPY
        private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
        }

        这个方法先声明了一个oldCapacity变量将数组长度赋给它,其值为0;又声明了一个newCapacity变量其值为oldCapacity+一个增量,可以发现这个增量是和原数组长度有关的量,当然在这里也为0。第一个if条件满足,newCapacity的值为10(这就是默认的容量,不理解的话再看看前面)。第二个if条件不成立,也可以不用注意,因为MAX_ARRAY_SIZE的定义如下:

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

        这个值太大了以至于第二个if条件没有了解的必要。

        最后一句话就是为elementData数组赋予了新的长度,Arrays.copyOf()方法返回的数组是新的数组对象,原数组对象不会改变,该拷贝不会影响原来的数组。copyOf()的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值。

        这时候再回到add的方法中,接着就向下执行elementData[size++] = e;到这里为止关于ArrayList就讲解得差不多了,当数组长度为10的时候你们可以试着过一下源码,查一下每次的增量是多少(答案是每次扩容为原来的1.5倍)。


        Vector
        • 数组结构实现,查询快、增删慢;

        • JDK1.0版本,运行效率慢、线程安全。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          COPY
          /**
          * Vector的演示使用
          *
          *1.添加数据
          *2.删除数据
          *3.遍历
          *4.判断
          */
          public class Demo1 {
          public static void main(String[] args) {
          Vector vector=new Vector<>();
          //1.添加数据
          vector.add("tang");
          vector.add("he");
          vector.add("yu");
          System.out.println("元素个数:"+vector.size());
          //2.删除数据
          /*
          * vector.remove(0); vector.remove("tang");
          */
          //3.遍历
          //使用枚举器
          Enumeration enumeration=vector.elements();
          while (enumeration.hasMoreElements()) {
          String s = (String) enumeration.nextElement();
          System.out.println(s);
          }
          //4.判断
          System.out.println(vector.isEmpty());
          System.out.println(vector.contains("he"));
          //5. Vector其他方法
          //firstElement() lastElement() ElementAt();
          }
          }

        LinkedList
        • 链表结构实现,增删快,查询慢。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        COPY
        /**
        * LinkedList的用法
        * 存储结构:双向链表
        * 1.添加元素
        * 2.删除元素
        * 3.遍历
        * 4.判断
        */
        public class Demo2 {
        public static void main(String[] args) {
        LinkedList linkedList=new LinkedList<>();
        Student s1=new Student("唐", 21);
        Student s2=new Student("何", 22);
        Student s3=new Student("余", 21);
        //1.添加元素
        linkedList.add(s1);
        linkedList.add(s2);
        linkedList.add(s3);
        linkedList.add(s3);
        System.out.println("元素个数:"+linkedList.size());
        System.out.println(linkedList.toString());
        //2.删除元素
        /*
        * linkedList.remove(new Student("唐", 21));
        * System.out.println(linkedList.toString());
        */
        //3.遍历
        //3.1 使用for
        for(int i=0;i<linkedList.size();++i) {
        System.out.println(linkedList.get(i));
        }
        //3.2 使用增强for
        for(Object object:linkedList) {
        Student student=(Student) object;
        System.out.println(student.toString());
        }
        //3.3 使用迭代器
        Iterator iterator =linkedList.iterator();
        while (iterator.hasNext()) {
        Student student = (Student) iterator.next();
        System.out.println(student.toString());
        }
        //3.4 使用列表迭代器(略)
        //4. 判断
        System.out.println(linkedList.contains(s1));
        System.out.println(linkedList.isEmpty());
        System.out.println(linkedList.indexOf(s3));
        }
        }
        LinkedList源码分析

        LinkedList首先有三个属性:

        • 链表大小:transient int size = 0;
        • (指向)第一个结点/头结点: transient Node<E> first;
        • (指向)最后一个结点/尾结点:transient Node<E> last;

        关于Node类型我们再进入到类里看看:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        COPY
        private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
        }
        }

        首先item存放的是实际数据;next指向下一个结点而prev指向上一个结点。

        Node带参构造方法的三个参数分别是前一个结点、存储的数据、后一个结点,调用这个构造方法时将它们赋值给当前对象。

        LinkedList是如何添加元素的呢?先看看add方法:

        1
        2
        3
        4
        COPY
        public boolean add(E e) {
        linkLast(e);
        return true;
        }

        进入到linkLast方法:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        COPY
        void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
        first = newNode;
        else
        l.next = newNode;
        size++;
        modCount++;
        }

        假设刚开始new了一个LinkedList对象,first和last属性都为空,调用add进入到linkLast方法。

        首先创建一个Node变量 l 将last(此时为空)赋给它,然后new一个newNode变量存储数据,并且它的前驱指向l,后继指向null;再把last指向newNode。如下图所示:

        如果满足if条件,说明这是添加的第一个结点,将first指向newNode:

        至此,LinkedList对象的第一个数据添加完毕。假设需要再添加一个数据,我们可以再来走一遍,过程同上不再赘述,图示如下:


        ArrayList和LinkedList区别
        • ArrayList:必须开辟连续空间,查询快,增删慢。
        • LinkedList:无需开辟连续空间,查询慢,增删快。

        泛型概述
        • Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
        • 常见形式有泛型类、泛型接口、泛型方法。
        • 语法:
          • <T,…> T称为类型占位符,表示一种引用类型。
        • 好处:
          • 提高代码的重用性。
          • 防止类型转换异常,提高代码的安全性。
        泛型类
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        COPY
        /**
        * 泛型类
        * 语法:类名<T>
        * T是类型占位符,表示一种引用类型,编写多个使用逗号隔开
        *
        */
        public class myGeneric<T>{
        //1.创建泛型变量
        //不能使用new来创建,因为泛型是不确定的类型,也可能拥有私密的构造方法。
        T t;
        //2.泛型作为方法的参数
        public void show(T t) {
        System.out.println(t);
        }
        //泛型作为方法的返回值
        public T getT() {
        return t;
        }
        }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        COPY
        /**
        * 注意:
        * 1.泛型只能使用引用类型
        * 2.不同泛型类型的对象不能相互赋值
        */
        public class testGeneric {
        public static void main(String[] args) {
        //使用泛型类创建对象
        myGeneric<String> myGeneric1=new myGeneric<String>();
        myGeneric1.t="tang";
        myGeneric1.show("he");

        myGeneric<Integer> myGeneric2=new myGeneric<Integer>();
        myGeneric2.t=10;
        myGeneric2.show(20);
        Integer integer=myGeneric2.getT();
        }
        }
        泛型接口
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        COPY
        /**
        * 泛型接口
        * 语法:接口名<T>
        * 注意:不能创建泛型静态常量
        */
        public interface MyInterface<T> {
        //创建常量
        String nameString="tang";

        T server(T t);
        }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        COPY
        /**
        * 实现接口时确定泛型类
        */
        public class MyInterfaceImpl implements MyInterface<String>{
        @Override
        public String server(String t) {
        System.out.println(t);
        return t;
        }
        }
        1
        2
        3
        4
        COPY
        //测试
        MyInterfaceImpl myInterfaceImpl=new MyInterfaceImpl();
        myInterfaceImpl.server("xxx");
        //xxx
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        COPY
        /**
        * 实现接口时不确定泛型类
        */
        public class MyInterfaceImpl2<T> implements MyInterface<T>{
        @Override
        public T server(T t) {
        System.out.println(t);
        return t;
        }
        }
        1
        2
        3
        4
        COPY
        //测试
        MyInterfaceImpl2<Integer> myInterfaceImpl2=new MyInterfaceImpl2<Integer>();
        myInterfaceImpl2.server(2000);
        //2000
        泛型方法
        1
        2
        3
        4
        5
        6
        7
        8
        9
        COPY
        /**
        * 泛型方法
        * 语法:<T> 返回类型
        */
        public class MyGenericMethod {
        public <T> void show(T t) {
        System.out.println("泛型方法"+t);
        }
        }
        1
        2
        3
        4
        5
        COPY
        //测试
        MyGenericMethod myGenericMethod=new MyGenericMethod();
        myGenericMethod.show("tang");
        myGenericMethod.show(200);
        myGenericMethod.show(3.14);
        泛型集合
        • 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
        • 特点
          • 编译时即可检查,而非运行时抛出异常。
          • 访问时,不必类型转换(拆箱)。
          • 不同泛型指尖引用不能相互赋值,泛型不存在多态。
        • 之前我们在创建LinkedList类型对象的时候并没有使用泛型,但是进到它的源码中会发现:

          1
          2
          3
          COPY
          public class LinkedList<E>
          extends AbstractSequentialList<E>
          implements List<E>, Deque<E>, Cloneable, java.io.Serializable{//略}

          它是一个泛型类,而我之前使用的时候并没有传递,说明java语法是允许的,这个时候传递的类型是Object类,虽然它是所有类的父类,可以存储任意的类型,但是在遍历、获取元素时需要原来的类型就要进行强制转换。这个时候就会出现一些问题,假如往链表里存储了许多不同类型的数据,在强转的时候就要判断每一个原来的类型,这样就很容易出现错误。


          Set集合概述
          Set子接口
          • 特点:无序、无下标、元素不可重复。
          • 方法:全部继承自Collection中的方法。
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          COPY
          /**
          * 测试Set接口的使用
          * 特点:1.无序,没有下标;2.重复
          * 1.添加数据
          * 2.删除数据
          * 3.遍历【重点】
          * 4.判断
          */
          public class Demo1 {
          public static void main(String[] args) {
          Set<String> set=new HashSet<String>();
          //1.添加数据
          set.add("tang");
          set.add("he");
          set.add("yu");
          System.out.println("数据个数:"+set.size());
          System.out.println(set.toString());//无序输出
          //2.删除数据
          /*
          * set.remove("tang"); System.out.println(set.toString());
          */
          //3.遍历【重点】
          //3.1 使用增强for
          for (String string : set) {
          System.out.println(string);
          }
          //3.2 使用迭代器
          Iterator<String> iterator=set.iterator();
          while (iterator.hasNext()) {
          System.out.println(iterator.next());
          }
          //4.判断
          System.out.println(set.contains("tang"));
          System.out.println(set.isEmpty());
          }
          }
          Set实现类
          HashSet【重点】
          • 基于HashCode计算元素存放位置。
          • 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
          • 1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            COPY
            /**
            * 人类
            */
            public class Person {
            private String name;
            private int age;
            public Person(String name,int age) {
            this.name = name;
            this.age = age;
            }
            public String getName() {
            return name;
            }
            public void setName(String name) {
            this.name = name;
            }
            public int getAge() {
            return age;
            }
            public void setAge(int age) {
            this.age = age;
            }
            @Override
            public String toString() {
            return "Peerson [name=" + name + ", age=" + age + "]";
            }
            }
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            COPY
            /**
            * HashSet集合的使用
            * 存储结构:哈希表(数组+链表+红黑树)
            * 1.添加元素
            * 2.删除元素
            * 3.遍历
            * 4.判断
            */
            public class Demo3 {
            public static void main(String[] args) {
            HashSet<Person> hashSet=new HashSet<>();
            Person p1=new Person("tang",21);
            Person p2=new Person("he", 22);
            Person p3=new Person("yu", 21);
            //1.添加元素
            hashSet.add(p1);
            hashSet.add(p2);
            hashSet.add(p3);
            //重复,添加失败
            hashSet.add(p3);
            //直接new一个相同属性的对象,依然会被添加,不难理解。
            //假如相同属性便认为是同一个对象,怎么修改?
            hashSet.add(new Person("yu", 21));
            System.out.println(hashSet.toString());
            //2.删除元素
            hashSet.remove(p2);
            //3.遍历
            //3.1 增强for
            for (Person person : hashSet) {
            System.out.println(person);
            }
            //3.2 迭代器
            Iterator<Person> iterator=hashSet.iterator();
            while (iterator.hasNext()) {
            System.out.println(iterator.next());
            }
            //4.判断
            System.out.println(hashSet.isEmpty());
            //直接new一个相同属性的对象结果输出是false,不难理解。
            //注:假如相同属性便认为是同一个对象,该怎么做?
            System.out.println(hashSet.contains(new Person("tang", 21)));
            }
            }

            :hashSet存储过程:

            1. 根据hashCode计算保存的位置,如果位置为空,则直接保存,否则执行第二步。
            2. 执行equals方法,如果方法返回true,则认为是重复,拒绝存储,否则形成链表。

            存储过程实际上就是重复依据,要实现“注”里的问题,可以重写hashCode和equals代码:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            COPY
            @Override
            public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + age;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
            }
            @Override
            public boolean equals(Object obj) {
            if (this == obj)
            return true;
            if (obj == null)
            return false;
            if (getClass() != obj.getClass())
            return false;
            Person other = (Person) obj;
            if (age != other.age)
            return false;
            if (name == null) {
            if (other.name != null)
            return false;
            } else if (!name.equals(other.name))
            return false;
            return true;
            }

            hashCode方法里为什么要使用31这个数字大概有两个原因:

            1. 31是一个质数,这样的数字在计算时可以尽量减少散列冲突。
            2. 可以提高执行效率,因为31*i=(i<<5)-i,31乘以一个数可以转换成移位操作,这样能快一点;但是也有网上一些人对这两点提出质疑。

            TreeSet
            • 基于排序顺序实现不重复。
            • 实现了SortedSet接口,对集合元素自动排序。
            • 元素对象的类型必须实现Comparable接口,指定排序规则。
            • 通过CompareTo方法确定是否为重复元素。
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            COPY
            /**
            * 使用TreeSet保存数据
            * 存储结构:红黑树
            * 要求:元素类必须实现Comparable接口,compareTo方法返回0,认为是重复元素
            */
            public class Demo4 {
            public static void main(String[] args) {
            TreeSet<Person> persons=new TreeSet<Person>();
            Person p1=new Person("tang",21);
            Person p2=new Person("he", 22);
            Person p3=new Person("yu", 21);
            //1.添加元素
            persons.add(p1);
            persons.add(p2);
            persons.add(p3);
            //注:直接添加会报类型转换错误,需要实现Comparable接口
            System.out.println(persons.toString());
            //2.删除元素
            persons.remove(p1);
            persons.remove(new Person("he", 22));
            System.out.println(persons.toString());
            //3.遍历(略)
            //4.判断
            System.out.println(persons.contains(new Person("yu", 21)));
            }
            }

            查看Comparable接口的源码,发现只有一个compareTo抽象方法,在人类中实现它:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            COPY
            public class Person implements Comparable<Person>{
            @Override
            //1.先按姓名比
            //2.再按年龄比
            public int compareTo(Person o) {
            int n1=this.getName().compareTo(o.getName());
            int n2=this.age-o.getAge();
            return n1==0?n2:n1;
            }
            }

            除了实现Comparable接口里的比较方法,TreeSet也提供了一个带比较器Comparator的构造方法,使用匿名内部类来实现它:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            COPY
            /**
            * TreeSet的使用
            * Comparator:实现定制比较(比较器)
            */
            public class Demo5 {
            public static void main(String[] args) {
            TreeSet<Person> persons=new TreeSet<Person>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
            // 先按年龄比较
            // 再按姓名比较
            int n1=o1.getAge()-o2.getAge();
            int n2=o1.getName().compareTo(o2.getName());
            return n1==0?n2:n1;
            }
            });
            Person p1=new Person("tang",21);
            Person p2=new Person("he", 22);
            Person p3=new Person("yu", 21);
            persons.add(p1);
            persons.add(p2);
            persons.add(p3);
            System.out.println(persons.toString());
            }
            }

            接下来我们来做一个小案例:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            COPY
            /**
            * 要求:使用TreeSet集合实现字符串按照长度进行排序
            * helloworld tangrui hechengyang wangzixu yuguoming
            * Comparator接口实现定制比较
            */
            public class Demo6 {
            public static void main(String[] args) {
            TreeSet<String> treeSet=new TreeSet<String>(new Comparator<String>() {
            @Override
            //先比较字符串长度
            //再比较字符串
            public int compare(String o1, String o2) {
            int n1=o1.length()-o2.length();
            int n2=o1.compareTo(o2);
            return n1==0?n2:n1;
            }
            });
            treeSet.add("helloworld");
            treeSet.add("tangrui");
            treeSet.add("hechenyang");
            treeSet.add("yuguoming");
            treeSet.add("wangzixu");
            System.out.println(treeSet.toString());
            //输出[tangrui, wangzixu, yuguoming, hechenyang, helloworld]
            }
            }

            Map体系集合

            • Map接口的特点:

              1. 用于存储任意键值对(Key-Value)。
              2. 键:无序、无下标、不允许重复(唯一)。
              3. 值:无序、无下标、允许重复。

            Map集合概述

            • 特点:存储一对数据(Key-Value),无序、无下标,键不可重复。

            • 方法

              • V put(K key,V value)//将对象存入到集合中,关联键值。key重复则覆盖原值。
            • Object get(Object key)//根据键获取相应的值。

              • Set<K>//返回所有的key
              • Collection<V> values()//返回包含所有值的Collection集合。
              • Set<Map.Entry<K,V>>//键值匹配的set集合
              1
              2
              3
              4
              5
              6
              7
              8
              9
              10
              11
              12
              13
              14
              15
              16
              17
              18
              19
              20
              21
              22
              23
              24
              25
              26
              COPY
              /**
              * Map接口的使用
              * 特点:1.存储键值对 2.键不能重复,值可以重复 3.无序
              */
              public class Demo1 {
              public static void main(String[] args) {
              Map<String,Integer> map=new HashMap<String, Integer>();
              //1.添加元素
              map.put("tang", 21);
              map.put("he", 22);
              map.put("fan", 23);
              System.out.println(map.toString());
              //2.删除元素
              map.remove("he");
              System.out.println(map.toString());
              //3.遍历
              //3.1 使用keySet();
              for (String key : map.keySet()) {
              System.out.println(key+" "+map.get(key));
              }
              //3.2 使用entrySet();效率较高
              for (Map.Entry<String, Integer> entry : map.entrySet()) {
              System.out.println(entry.getKey()+" "+entry.getValue());
              }
              }
              }

            Map集合的实现类

            HashMap【重点】
            • JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value。

              1
              2
              3
              4
              5
              6
              7
              8
              9
              10
              11
              12
              13
              14
              15
              16
              17
              18
              19
              20
              21
              22
              23
              24
              25
              26
              27
              28
              COPY
              /**
              * 学生类
              */
              public class Student {
              private String name;
              private int id;
              public Student(String name, int id) {
              super();
              this.name = name;
              this.id = id;
              }
              public String getName() {
              return name;
              }
              public void setName(String name) {
              this.name = name;
              }
              public int getId() {
              return id;
              }
              public void setId(int id) {
              this.id = id;
              }
              @Override
              public String toString() {
              return "Student [name=" + name + ", age=" + id + "]";
              }
              }
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            COPY
            /**
            * HashMap的使用
            * 存储结构:哈希表(数组+链表+红黑树)
            */
            public class Demo2 {
            public static void main(String[] args) {
            HashMap<Student, String> hashMap=new HashMap<Student, String>();
            Student s1=new Student("tang", 36);
            Student s2=new Student("yu", 101);
            Student s3=new Student("he", 10);
            //1.添加元素
            hashMap.put(s1, "成都");
            hashMap.put(s2, "杭州");
            hashMap.put(s3, "郑州");
            //添加失败,但会更新值
            hashMap.put(s3,"上海");
            //添加成功,不过两个属性一模一样;
            //注:假如相同属性便认为是同一个对象,怎么修改?
            hashMap.put(new Student("he", 10),"上海");
            System.out.println(hashMap.toString());
            //2.删除元素
            hashMap.remove(s3);
            System.out.println(hashMap.toString());
            //3.遍历
            //3.1 使用keySet()遍历
            for (Student key : hashMap.keySet()) {
            System.out.println(key+" "+hashMap.get(key));
            }
            //3.2 使用entrySet()遍历
            for (Entry<Student, String> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey()+" "+entry.getValue());
            }
            //4.判断
            //注:同上
            System.out.println(hashMap.containsKey(new Student("he", 10)));
            System.out.println(hashMap.containsValue("成都"));
            }
            }

            注:和之前说过的HashSet类似,重复依据是hashCode和equals方法,重写即可:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            COPY
            @Override
            public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + id;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
            }
            @Override
            public boolean equals(Object obj) {
            if (this == obj)
            return true;
            if (obj == null)
            return false;
            if (getClass() != obj.getClass())
            return false;
            Student other = (Student) obj;
            if (id != other.id)
            return false;
            if (name == null) {
            if (other.name != null)
            return false;
            } else if (!name.equals(other.name))
            return false;
            return true;
            }
            HashMap源码分析
          • 默认初始化容量:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

            • 数组最大容量:static final int MAXIMUM_CAPACITY = 1 << 30;
          • 默认加载因子:static final float DEFAULT_LOAD_FACTOR = 0.75f;

          • 链表调整为红黑树的链表长度阈值(JDK1.8):static final int TREEIFY_THRESHOLD = 8;

          • 红黑树调整为链表的链表长度阈值(JDK1.8):static final int UNTREEIFY_THRESHOLD = 6;

          • 链表调整为红黑树的数组最小阈值(JDK1.8):static final int MIN_TREEIFY_CAPACITY = 64;

          • HashMap存储的数组:transient Node<K,V>[] table;

          • HashMap存储的元素个数:transient int size;

            • 默认加载因子是什么?
              • 就是判断数组是否扩容的一个因子。假如数组容量为100,如果HashMap的存储元素个数超过了100*0.75=75,那么就会进行扩容。
            • 链表调整为红黑树的链表长度阈值是什么?
              • 假设在数组中下标为3的位置已经存储了数据,当新增数据时通过哈希码得到的存储位置又是3,那么就会在该位置形成一个链表,当链表过长时就会转换成红黑树以提高执行效率,这个阈值就是链表转换成红黑树的最短链表长度;
            • 红黑树调整为链表的链表长度阈值是什么?
              • 当红黑树的元素个数小于该阈值时就会转换成链表。
            • 链表调整为红黑树的数组最小阈值是什么?
              • 并不是只要链表长度大于8就可以转换成红黑树,在前者条件成立的情况下,数组的容量必须大于等于64才会进行转换。

            HashMap的数组table存储的就是一个个的Node<K,V>类型,很清晰地看到有一对键值,还有一个指向next的指针(以下只截取了部分源码):

            1
            2
            3
            4
            5
            COPY
            static class Node<K,V> implements Map.Entry<K,V> {
            final K key;
            V value;
            Node<K,V> next;
            }

            之前的代码中在new对象时调用的是HashMap的无参构造方法,进入到该构造方法的源码查看一下:

            1
            2
            3
            COPY
            public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
            }

            发现没什么内容,只是赋值了一个默认加载因子;而在上文我们观察到源码中table和size都没有赋予初始值,说明刚创建的HashMap对象没有分配容量,并不拥有默认的16个空间大小,这样做的目的是为了节约空间,此时table为null,size为0。

            当我们往对象里添加元素时调用put方法:

            1
            2
            3
            COPY
            public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
            }

            put方法把key和value传给了putVal,同时还传入了一个hash(Key)所返回的值,这是一个产生哈希值的方法,再进入到putVal方法(部分源码):

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            COPY
            final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
            boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
            if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
            if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
            else{
            //略
            }
            }

            这里面创建了一个tab数组和一个Node变量p,第一个if实际是判断table是否为空,而我们现在只关注刚创建HashMap对象时的状态,此时tab和table都为空,满足条件,执行内部代码,这条代码其实就是把resize()所返回的结果赋给tab,n就是tab的长度,resize顾名思义就是重新调整大小。查看resize()源码(部分):

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            COPY
            final Node<K,V>[] resize() {
            Node<K,V>[] oldTab = table;
            int oldCap = (oldTab == null) ? 0 : oldTab.length;
            int oldThr = threshold;
            if (oldCap > 0);
            else if (oldThr > 0);
            else { // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
            }
            @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
            table = newTab;
            return newTab;
            }

            该方法首先把table及其长度赋值给oldTab和oldCap;threshold是阈值的意思,此时为0,所以前两个if先不管,最后else里newCap的值为默认初始化容量16;往下创建了一个newCap大小的数组并将其赋给了table,刚创建的HashMap对象就在这里获得了初始容量。然后我们再回到putVal方法,第二个if就是根据哈希码得到的tab中的一个位置是否为空,为空便直接添加元素,此时数组中无元素所以直接添加。至此HashMap对象就完成了第一个元素的添加。当添加的元素超过16*0.75=12时,就会进行扩容:

            1
            2
            3
            4
            COPY
            final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict){
            if (++size > threshold)
            resize();
            }

            扩容的代码如下(部分):

            1
            2
            3
            4
            5
            6
            7
            8
            9
            COPY
            final Node<K,V>[] resize() {
            int oldCap = (oldTab == null) ? 0 : oldTab.length;
            int newCap;
            if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {//略}
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
            oldCap >= DEFAULT_INITIAL_CAPACITY)
            }
            }

            核心部分是else if里的移位操作,也就是说每次扩容都是原来大小的两倍

          • *注**:额外说明的一点是在JDK1.8以前链表是头插入,JDK1.8以后链表是尾插入。


          • HashSet源码分析

            了解完HashMap之后,再回过头来看之前的HashSet源码,为什么放在后面写你们看一下源码就知道了(部分):

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            COPY
            public class HashSet<E>
            extends AbstractSet<E>
            implements Set<E>, Cloneable, java.io.Serializable
            {
            private transient HashMap<E,Object> map;
            private static final Object PRESENT = new Object();
            public HashSet() {
            map = new HashMap<>();
            }
            }

            可以看见HashSet的存储结构就是HashMap,那它的存储方式是怎样的呢?可以看一下add方法:

            1
            2
            3
            COPY
            public boolean add(E e) {
            return map.put(e, PRESENT)==null;
            }

            很明了地发现它的add方法调用的就是map的put方法,把元素作为map的key传进去的。。

            Hashtable
            • JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
              • 初始容量11,加载因子0.75。

                这个集合在开发过程中已经不用了,稍微了解即可。

              Properties
              • Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
              • 它继承了Hashtable的方法,与流关系密切,此处不详解。

                TreeMap
                • 实现了SortedMap接口(是Map的子接口),可以对key自动排序。
                • 1
                  2
                  3
                  4
                  5
                  6
                  7
                  8
                  9
                  10
                  11
                  12
                  13
                  14
                  15
                  16
                  17
                  18
                  19
                  20
                  21
                  22
                  23
                  24
                  25
                  26
                  27
                  28
                  29
                  30
                  31
                  32
                  33
                  COPY
                  /**
                  * TreeMap的使用
                  * 存储结构:红黑树
                  */
                  public class Demo3 {
                  public static void main(String[] args) {
                  TreeMap<Student, Integer> treeMap=new TreeMap<Student, Integer>();
                  Student s1=new Student("tang", 36);
                  Student s2=new Student("yu", 101);
                  Student s3=new Student("he", 10);
                  //1.添加元素
                  treeMap.put(s1, 21);
                  treeMap.put(s2, 22);
                  treeMap.put(s3, 21);
                  //不能直接打印,需要实现Comparable接口,因为红黑树需要比较大小
                  System.out.println(treeMap.toString());
                  //2.删除元素
                  treeMap.remove(new Student("he", 10));
                  System.out.println(treeMap.toString());
                  //3.遍历
                  //3.1 使用keySet()
                  for (Student key : treeMap.keySet()) {
                  System.out.println(key+" "+treeMap.get(key));
                  }
                  //3.2 使用entrySet()
                  for (Entry<Student, Integer> entry : treeMap.entrySet()) {
                  System.out.println(entry.getKey()+" "+entry.getValue());
                  }
                  //4.判断
                  System.out.println(treeMap.containsKey(s1));
                  System.out.println(treeMap.isEmpty());
                  }
                  }

                  在学生类中实现Comparable接口:

                  1
                  2
                  3
                  4
                  5
                  6
                  COPY
                  public class Student implements Comparable<Student>{
                  @Override
                  public int compareTo(Student o) {
                  int n1=this.id-o.id;
                  return n1;
                  }

                  除此之外还可以使用比较器来定制比较:

                  1
                  2
                  3
                  4
                  5
                  6
                  7
                  COPY
                  TreeMap<Student, Integer> treeMap2=new TreeMap<Student, Integer>(new Comparator<Student>() {
                  @Override
                  public int compare(Student o1, Student o2) {
                  // 略
                  return 0;
                  }
                  });
                  TreeSet源码

                  和HashSet类似,放在TreeMap之后讲便一目了然(部分):

                  1
                  2
                  3
                  4
                  5
                  6
                  7
                  8
                  9
                  10
                  11
                  12
                  COPY
                  public class TreeSet<E> extends AbstractSet<E>
                  implements NavigableSet<E>, Cloneable, java.io.Serializable
                  {
                  private transient NavigableMap<E,Object> m;
                  private static final Object PRESENT = new Object();
                  TreeSet(NavigableMap<E,Object> m) {
                  this.m = m;
                  }
                  public TreeSet() {
                  this(new TreeMap<E,Object>());
                  }
                  }

                  TreeSet的存储结构实际上就是TreeMap,再来看其存储方式:

                  1
                  2
                  3
                  COPY
                  public boolean add(E e) {
                  return m.put(e, PRESENT)==null;
                  }

                  它的add方法调用的就是TreeMap的put方法,将元素作为key传入到存储结构中。


                  Collections工具类

                  • 概念:集合工具类,定义了除了存取以外的集合常用方法。

                  • 方法

                    • public static void reverse(List<?> list)//反转集合中元素的顺序
                    • public static void shuffle(List<?> list)//随机重置集合元素的顺序
                    • public static void sort(List<T> list)//升序排序(元素类型必须实现Comparable接口)
                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
                    9
                    10
                    11
                    12
                    13
                    14
                    15
                    16
                    17
                    18
                    19
                    20
                    21
                    22
                    23
                    24
                    25
                    26
                    27
                    28
                    29
                    30
                    31
                    32
                    33
                    34
                    35
                    36
                    37
                    38
                    39
                    40
                    41
                    42
                    43
                    44
                    45
                    46
                    47
                    48
                    49
                    50
                    51
                    52
                    COPY
                    /**
                    * 演示Collections工具类的使用
                    *
                    */
                    public class Demo4 {
                    public static void main(String[] args) {
                    List<Integer> list=new ArrayList<Integer>();
                    list.add(20);
                    list.add(10);
                    list.add(30);
                    list.add(90);
                    list.add(70);

                    //sort排序
                    System.out.println(list.toString());
                    Collections.sort(list);
                    System.out.println(list.toString());
                    System.out.println("---------");

                    //binarySearch二分查找
                    int i=Collections.binarySearch(list, 10);
                    System.out.println(i);

                    //copy复制
                    List<Integer> list2=new ArrayList<Integer>();
                    for(int i1=0;i1<5;++i1) {
                    list2.add(0);
                    }
                    //该方法要求目标元素容量大于等于源目标
                    Collections.copy(list2, list);
                    System.out.println(list2.toString());

                    //reserve反转
                    Collections.reverse(list2);
                    System.out.println(list2.toString());

                    //shuffle 打乱
                    Collections.shuffle(list2);
                    System.out.println(list2.toString());

                    //补充:list转成数组
                    Integer[] arr=list.toArray(new Integer[0]);
                    System.out.println(arr.length);
                    //补充:数组转成集合
                    String[] nameStrings= {"tang","he","yu"};
                    //受限集合,不能添加和删除
                    List<String> list3=Arrays.asList(nameStrings);
                    System.out.println(list3);

                    //注:基本类型转成集合时需要修改为包装类
                    }
                    }

                  完结撒花❀

                    <!-- reward -->
                    
                    <div id="reword-out">
                      <div id="reward-btn">
                        打赏
                      </div>
                    </div>
                    
                  </div>
                  
                评论
                添加红包

                请填写红包祝福语或标题

                红包个数最小为10个

                红包金额最低5元

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

                抵扣说明:

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

                余额充值