Java集合框架

Java集合框架

1、 什么是集合

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

  • 集合和数组的区别:

    (1)数组长度固定,集合长度不固定

    (2)数组可以存储基本类型和引用类型,集合只能存储引用类型(对象)

    (3)集合中存放的都是对象的引用,而非对象本身。所以我们称集合中的对象就是集合中对象的引用。对象本身还是存放在堆内存中

    (3)数组存储的元素必须是同一个数据类型,集合存储的对象可以是不同数据类型的

  • 存放的包:java.uti.*;

  • 基本数数据类型和引用数据类型区别

  • 类(class), 接口(interface),数组(array),(枚举类型、注解类型、字符串(String)类型) 。
    简单来说,只要不是基本数据类型.都是引用数据类型

2、 数组存储的特点:

一旦初始化以后,其长度就确定了。 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。

比如:String[] arr、int[] arr1、Object[] arr2

3、 数组存储的弊端:

  1. 一旦初始化以后,其长度就不可修改。
  2. 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
  3. 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
  4. 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

4、 集合存储的优点:

解决数组存储数据方面的弊端

5、 Collection体系集合

6、 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() 将此集合转换成数组

6.1 Collection接口的使用

(1)添加元素
(2)删除元素
(3)遍历元素
(4)判断

  1. 创建集合

    Collection collection = new ArrayList();

(1)添加元素

collection.add("苹果");
collection.add("雪梨");
collection.add("榴莲");
System.out.println("元素个数:"+collection.size());//输出:元素个数:3
System.out.println(collection); //输出:[苹果, 雪梨, 榴莲]

(2)删除元素

collection.remove("榴莲");
//collection.clear(); //清空集合
System.out.println("元素个数:"+collection.size());

(3)遍历元素

①使用增强for (不能使用for循环)

for (Object obj: collection) {
  System.out.println(obj);
}

②使用迭代器(迭代器专门用来遍历集合的一种方式)

Iterator的三个方法
  1. hasNext()
    2. next()
    3. remove()
Iterator it = collection.iterator();
while (it.hasNext()){
  String s = (String) it.next(); //强转类型
  System.out.println(s);
  //collection.remove(s); 不能使用collection的remove()方法,会报并发修改异常
  it.remove(); //可以使用it.remove(); 进行移除元素
}
System.out.println("元素个数:"+collection.size());//元素个数:0

注意:使用迭代器的过程中,不能使用collection中的方法

(4)判断

System.out.println(collection.contains("西瓜"));//判断是否包含元素 西瓜
System.out.println(collection.isEmpty());  //判断集合是否为空

7、 List集合

  • 特点:有序、有下标、元素可以重复
  • 常用的方法有:
方法 功能
void add(int index, Object o) 在index位置插入对象o
boolean addAll(int index, Collection c) 将一个集合中的元素添加到此集合中的index位置
Object get(int index) 返回集合中指定位置的元素
List subList(int fromIndex, int toIndex) 返回fromIndex和toIndex之间的集合的元素

7.1 List子接口的使用

(1)添加元素 (会对基本类型进行自动装箱)
(2)删除元素
当删除数字与索引矛盾时 对数字强转
list.remove((Object) 10) 或 list.remove(new Integer(10))
(3)遍历元素
(4)判断

  1. 创建List集合(通过实现类创建)

    ​ List list = new ArrayList();

    或者 List list = new LinkedList();

(1)添加元素

list.add("苹果");
list.add("华为");
list.add(0,"小米"); //在0位置添加
System.out.println("元素个数:"+list.size());//输出 元素个数:3
System.out.println(list.toString());//输出 [小米, 苹果, 华为]

(2)删除元素

list.remove("苹果");
System.out.println(list.toString()); //输出 [小米, 华为]
list.remove(0);//删除0号位置的元素

(3)遍历集合

①使用for i

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

②使用增强for

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

③使用iterator迭代器

Iterator it = list.iterator();
while (it.hasNext()){
  System.out.println(it.next());
}

④使用列表迭代器 ListIterator (注意和迭代器的区别)

ListIterator lit = list.listIterator();
while (lit.hasNext()){
  System.out.println(lit.nextIndex()+":"+lit.next());//从前往后遍历
}

while (lit.hasPrevious()){
  System.out.println(lit.previousIndex()+":"+lit.previous());//从后往前遍历
}

(4)判断

​ list.contains() 和 list.isEmpty()

(5)获取某个元素所在位置 :list.indexOf()

(6)返回子集合(含头不含尾) :subList(int fromIndex, int toIndex)

7.2 List实现类

  • ArrayList【重点】:

    • 数组结构实现,查询快、增删慢
    • jdk1.2版本,运行效率快、线程不安全
  • Vector:

    • 数组结构实现,查询快、增删慢
    • jdk1.0版本,运行速度慢、线程安全
  • LinkedList:

    • 双向链表结构实现,增删快、查询慢

1、 ArrayList

  1. 创建ArrayList集合

    ​ ArrayList arrayList = new ArrayList();

(1)添加元素 arrayList.add();

(2)删除元素 arrayList.remove(new Student("name", 10));

这里重写了 equals(this == obj) 方法

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)obj;
    //4 比较属性
    if(this.name.equals(s.getName()) && this.age == s.getAge()){
      return true;
    }
  }
  //5 不满足条件返回false
  return false;
}

(3)遍历元素【重点】

①使用for

②使用增强for

③使用迭代器

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

④使用列表迭代器

ListIterator li = arrayList.listIterator();
while(li.hasNext()){
  Student s = (Student)li.next(); //从前往后遍历
}

while(li.hasPrevious()){
  Student s = (Student)li.previous();//从后往前遍历
}

(4)判断

arrayList.contains(); 和 arrayList.isEmpty();

(5)查找某个元素的下标

arrayList.indexof();

ArrayList源码分析

DEFAULT_CAPACITY = 10; //默认容量是10
//注意:如果没有向集合中添加任何元素时,容量0,添加一个后,容量为10
//每次扩容是原来的1.5倍
elementData:存放元素的数组
size :实际元素个数

2、 Vector

  1. 创建Vector集合

    ​ Vector vector = new Vector();

增加、删除、判断同上的集合

遍历:使用枚举器遍历集合(Enumeration)

Enumeration en = vector.elements();
while (en.hasMoreElements()){
  String s = (String) en.nextElement();
  System.out.println(s.toString());
}

3、LinkedList

  1. 创建链表集合:

    ​ LinkedList li = new LinkedList();

常用方法与List一致

4、ArrayList 和 LinkedList的区别

两者结构的实现方式

8、 Set集合

  • 特点:无序、无下标、元素不可重复
  • 方法:全部继承自Collection中的方法
  • 增、删、遍历、判断与collection一致
  • 创建Set集合:通过实现类创建
    • Set set = new HashSet();
    • Set set = new TreeSet();

8.1 Set实现类

  • HashSet【重点】

    • 基于HashCode计算元素存放位置
    • 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
  • TreeSet

    • 基于排列顺序实现元素不重复
    • 实现了SortSet接口,对集合元素自动排序
    • 元素对象的类型必须实现Comparable接口,指定排序规则
    • 通过CompareTo方法确定是否为重复元素

1. HashSet

  • HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet

  • 创建HashSet集合:

    ​ Set hashSet = new HashSet();

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

  • HashSet按Hash算法来存储集合中的元素,因此具有很好地存取和查找性能。

  • 存储过程(重复依据):需重写hashCode和equals方法

  1. 根据hashCode计算保存的位置,如果位置为空,直接保存;若不为空,则进行第2步
  2. 再执行equals方法,如果equals为true,则认为是重复的,否则形成链表
  • 特点:

    • 基于HashCode计算元素的存放位置
    • 通过重写HashCode的方法,可得知:
      • 利用31这个质数,减少散列冲突
      • 31提高执行效率 ,31 * i = (i << 5) - i 转为移位操作
    • 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet中的存储位置
    • 当存入元素的hashCode值相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
    • 如果两个元素的equals()方法返回true,但它们的hashCode()返回值不相等,hashSet将会把它们存储在不同的位置,但依然可以添加成功
  • HashSet具有以下特点:

  1. 不能保证元素的排列顺序
  2. 不可重复
  3. HashSet不是线程安全的
  4. 集合元素可以是null

1.添加元素: hashSet.add( );

2.删除元素: hashSet.remove( );

3.遍历操作

  1. 增强for:

    ​ for( type typevar : hashSet)

  2. 迭代器:

    ​ Iterator it = hashSet.iterator( );`

4.判断: hashSet.contains( ); hashSet.isEmpty();

2. TreeSet

  • 创建TreeSet集合:

    ​ TreeSet treeSet = new TreeSet();

  • 存储结构:红黑树

  • 要求:元素必须要实现Comparable接口,否则会报异常!!重写compareTo()方法,返回值为0,认为是重复元素

写一个TreeSet集合

/*
    使用TreeSet保存数据,存储一个学生类
    存储数据:红黑树   
 */
public class Test {
    public static void main(String[] args) {
        //创建TreeSet集合
        TreeSet<Student> treeSet = new TreeSet<>();

        //添加元素
        Student s1 = new Student("彭于晏",20);
        Student s2 = new Student("胡歌",22);
        Student s3 = new Student("杨洋",21);
        treeSet.add(s1);
        treeSet.add(s2);
        treeSet.add(s3);
        System.out.println("元素个数:"+treeSet.size());
        System.out.println(treeSet.toString());
    }

写到这里,运行后会发现异常,编译器会返回ClassCastException,名为类型转换异常:Student cannot be cast to java.lang.Comparable,这时的解决办法有两种:

第一种:Student类需实现Comparable接口,实现接口中的compareTo()方法

//Student类实现Comparable接口
public class Student implements Comparable<Student>{
    String name;
    int age;
  @Override //实现接口中的compareTo()方法
    public int compareTo(Student o) {
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.age - o.getAge();
        return n1 == 0 ? n2 : n1;
    }

这时再执行,就能正常存储Student元素到TreeSet中

第二种:不需实现Comparable接口,需在创建TreeSet集合时使用Comparator接口

Comparator :实现定制比较(比较器)

Comparable: 可比较的

public class Test2 {
    public static void main(String[] args) {
      //创建集合,并指定比较规则
      TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() { //创建一个匿名内部类实现接口
        @Override
        public int compare(Student o1, Student o2) {
          int n1 = o1.getName().compareTo(o2.getName());
          int n2 = o1.getAge()-o2.getAge();
          return n1==0 ? n2:n1;
        }
      });

        //添加元素
        Student s1 = new Student("aaa",20);
        Student s2 = new Student("zxh",21);
        Student s3 = new Student("hello",23);
        treeSet.add(s1);
        treeSet.add(s2);
        treeSet.add(s3);
        System.out.println("元素个数:"+treeSet.size());
        System.out.println(treeSet.toString());

除了以Map结尾的类之外,其他类都实现Collection接口,而以Map结尾的类实现了Map接口

9、 Map体系集合

10、 Map父接口

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

10.1 Map接口的使用

Map集合的特点:

(1)存储键值对

(2)键不能重复,值可以重复

(3)无序

  1. 创建Map集合 比如键值对都为String类型

    ​ Map<String, String> hashMap = new HashMap<>();

(1)添加元素

hashMap.put("cn","中国");
hashMap.put("usa","美国");
hashMap.put("uk","英国");
hashMap.put("cn","zhongguo"); //key重复,后面的值会覆盖原值
System.out.println("元素个数:"+hashMap.size()); //输出 元素个数:3
System.out.println(hashMap.toString()); //输出 {usa=美国, uk=英国, cn=zhongguo}

(2)删除

hashMap.remove("usa");
System.out.println("元素个数:"+hashMap.size());

(3)遍历【重点】

①使用keySet() :返回的是key

Set<String> keySet = hashMap.keySet(); //返回key的Set集合,可以用增强for或者迭代器遍历
for (String key : keySet) {
  System.out.println(key+"---"+hashMap.get(key)); //get():返回键所对应的值
}

②使用entrySet() : 返回的是键值对

Set<Map.Entry<String, String>> entries = hashMap.entrySet(); //返回键值对的Set集合,可以用增强for或者迭代器遍历
for (Map.Entry<String, String> entry : entries) {
  System.out.println(entry.getKey()+"----"+entry.getValue());
}

(4)判断

System.out.println(hashMap.containsKey("cn"));
System.out.println(hashMap.containsValue("泰国"));

10.2 Map集合的实现类

  • HashMap:

    • jdk1.2版本,线程不安全,运行效率快;允许用null作为key或者value
  • Hashtable:

1. HashMap【重点】

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

  • 使用key可使hashcode和equals作为重复依据:需重写hashCode和equals方法

  • 增、删、遍历、判断与Map集合一致

  • 源码分析总结:

  1. HashMap刚创建时,table是null,节省空间,当添加第一个元素时,table容量调整为16
  2. 加载因子为0.75,当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
  3. jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
  4. jdk1.8 当链表长度 <6 时 调整成链表
  5. jdk1.8 以前,链表时头插入,之后为尾插入

2. TreeMap

  • 存储结构:红黑树

  • TreeMap集合的使用:

  1. 添加元素时,写代码的流程时与TreeSet一致,都需要实现Comparable接口,实现接口中的compareTo()方法;或者不需实现Comparable接口,需在创建TreeSet集合时使用Comparator接口。区别是TreeMap能对key自动排序
  2. 删、遍历、判断与Map集合一致

知识点:

  1. HashMap集合和HashSet集合添加元素时都需要重写hashCode和equals方法

  2. TreeMap集合与TreeSet集合添加元素时一样都需要实现Comparable接口

11、 Collections工具类

  • 概念:集合工具类,定义了除了存储以外的集合常用方法
  • 常用方法:
方法 功能
public static void reverse(List<?> list) 反转集合元素中的顺序
public static void shuffle(List<?> list) 随机重置集合元素的顺序
public static void sort(List list) 升序排序(元素类型必须实现Comparable接口)
public static void copy(dest, src) 将src的所有元素复制到另一个集合中

Collections工具类的使用

1.首先创建一个集合

ArrayList<Integer> list = new ArrayList<>();
list.add(12);
list.add(22);
list.add(5);
list.add(35);
list.add(17);

(1)排序sort() :默认升序

System.out.println("排序之前:"+list.toString());
Collections.sort(list);
System.out.println("排序之后:"+list.toString());

(2)二分查找 binarySearch():返回负数表示不存在

int i = Collections.binarySearch(list, 12);
System.out.println(i);

(3)复制 copy() :要求目标集合与原来的集合长度要一样

ArrayList<Integer> dest = new ArrayList<>();
for(int j = 0; j < list.size(); j++) {
  dest.add(0);
}
Collections.copy(dest,list);
System.out.println(dest);

(4)反转 reverse()

Collections.reverse(list);
System.out.println("反转之后:"+list);

(5)打乱 shuffle() :每次执行顺序都不一样

Collections.shuffle(list);
System.out.println("打乱之后:"+list.toString());

2.补充两个转换

(1)集合转成数组: toArray()

Integer[] array = list.toArray(new Integer[0]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));

(2)数组转成集合 :asList()

String[] name = {"小明","小红","小东"};
//转成之后的集合是一个受限集合,不能添加和删除
List<String> strings = Arrays.asList(name);
System.out.println(strings.toString());

//把基本数据类型的数组转成集合时,需要修改为包装类型
Integer[] num = {10,20,30,40};
List<Integer> list1 = Arrays.asList(num);
System.out.println(list1.toString());

12、 泛型

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

12.1 泛型类

写一个泛型类,语法:类名

/*
    泛型类
    语法:类名<T>
    T是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开
 */
public class MyGeneric<T> {
    //使用泛型T
    //1.创建变量
    T t;

    //泛型作为方法的参数
    public void show(T t){
        System.out.println(t);
    }

    //泛型作为方法的返回值
    public T getT(){
        return t;
    }
}

使用泛型类

public class TestGeneric {
    public static void main(String[] args) {
        //创建泛型类对象
        //注意:1.泛型只能使用引用类型  2.不同泛型类型对象之间不能相互赋值
        MyGeneric<String> generic = new MyGeneric<String>();
        generic.t="hello";
        generic.show("你好"); //输出 你好
        String s = generic.getT();
        System.out.println(s); //输出 hello

        MyGeneric<Integer> generic1 = new MyGeneric<>();
        generic1.t = 10;
        generic1.show(100);//输出 100
        Integer t = generic1.getT();
        System.out.println(t); //输出 10

        // MyGeneric<String> my = generic1; //报错 不同泛型类型对象之间不能相互赋值

    }

}

12.2 泛型接口

写一个泛型接口,语法:接口名

/*
    泛型接口
    语法:接口名<T>
    注意:不能使用泛型创建静态常量
 */
public interface MyInterface<T> {
    String name = "张三";
    T show(T t);
}

第一种实现类(在接口名直接标明泛型类型)

public class MyImplement implements MyInterface<String>{

    @Override
    public String show(String s) {
        System.out.println(s);
        return s;
    }
}

第二种实现类(不知道哪一种泛型类型时,通过测试类创建对象时标明泛型类型)

public class MyImplement2<T> implements MyInterface<T>{

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

//测试类
public static void main(String[] args) {
    MyImplement2<Integer> integerMyImplement2 = new MyImplement2<>();//标明使用的泛型类型
    integerMyImplement2.show(100);
}

12.3 泛型方法

写一个泛型方法类,语法:修饰符 返回值类型 方法名()

/*
    泛型方法
    语法:修饰符 <T> 返回值类型 方法名(){ }
 */
public class GenericMethod {
    public <T> T show(T t){
        System.out.println("泛型类型:"+t);
        return t;
    }
}

使用泛型方法(泛型类型不需要传递,而是根据所写参数决定)

GenericMethod genericMethod = new GenericMethod();
genericMethod.show("中国加油");
genericMethod.show(100);
genericMethod.show(3.14);

13、 Java集合的总结

1.Java集合类存放于java.uti包中,是一个用来存放对象的容器

①集合只能存放对象。比如你存一个int型数据1放入集合中,其实它是自动转换成integer类后存入的,Java中每一种基本类型都有对应的引用类型

②集合存放的是多个对象的引用,对象本身还是放在堆内存中

③集合可以存放不同类型,不限数量的数据类型

2.Java集合可分为List、Set和Map三种大体系

  • Set:无序、无下标、不可重复的集合

  • List:有序、有下标、可重复的集合

  • Map:具有映射关系的集合,

3.在JDK5之后,增加了泛型,Java集合可以记住容器中对象的数据类型

posted @ 2023-03-27 11:28  ·追·  阅读(95)  评论(0)    收藏  举报
/*鼠标跟随效果*/ //返回顶部 returnTop