Java学习笔记3——集合框架

文章目录

  • 1 集合的概念
  • 2 Collection体系集合
    • Collection父接口
  • 3 List接口与实现类
    • List接口
    • List实现类
      • ArrayList
      • Vector
      • LinkedList
  • 4 Set接口与实现类
    • Set接口
    • Set实现类
      • HashSet
      • TreeSet
  • 5 Map接口与实现类
    • Map接口
      • Map接口的内部接口Entry

1 集合的概念

  • 概念:对象的容器,实现了对对象常用的操作
  • 与数组的区别:
    1.数组长度固定,集合长度不固定;
    2.数组可以存储基本类型和引用类型,集合只能存储引用类型
  • 位置:集合类存放在java.util包中

2 Collection体系集合

在这里插入图片描述

Collection父接口

  • 创建Collection集合ArrayList对象:Collection collection = new ArrayList();

常用方法

  • 添加元素:
    collection.add(E e);

  • 删除元素:
    移除指定:collection.remove(Object o);
    移除所有:collection.clear();

  • 遍历元素(重点):

方法1:使用增强for(因为无下标)

for(Object obj : collection){ }

方法2:使用迭代器

//创建集合
Collection collection = new ArrayList();
collection.add("xx");//略
//iterator接口有以下三个方法:
//haNext(); 有没有下一个元素
//next(); 获取下一个元素
//remove(); 删除当前元素
Iterator it = collection.iterator();
while(it.hasNext()){String object = (String)it.next(); //注意别忘了Object到String要强转// 可以使用it.remove(); 进行移除元素}

注意不能用collection的remove方法移除,collection的其他方法也不能用,因为迭代器正在使用着集合中的元素,collection不能抢。否则会发生并发修改异常

  • 判断:

collection.contains(Object o); 检查此集合是否包含对象o
collection.isEmpty();判断此集合是否为空

3 List接口与实现类

List接口

  • 特点:有序、有下标、元素可重复
  • 创建List集合ArrayList对象:List list = new ArrayList<>();

举例说明

  • 添加元素:
    list.add(); 会对基本类型进行自动装箱

  • 删除元素:
    可以用索引 list.remove(0)
    当删除数字与索引矛盾时 对数字强转
    list.remove((Object) 10) 或 list.remove(new Integer(10))

  • 遍历:

使用for遍历

for(int i = 0; i < lise.size(); i++){sout(list.get(i)); 
}

使用增强for

for(Object list: collection){ }

使用迭代器

Iterator it = collection.iterator();
while(it.hasNext()){String object = (String)it.next(); //强转// 可以使用it.remove(); 进行移除元素// 不能用collection.remove(); 不能用collection其他方法 会发生并发修改异常
}

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

ListIterator li = list.listIterator();
while(li.hasNext()){System.out.println(li.nextIndex() + ":" + li.next()); //从前往后遍历
}while(li.hasPrevious()){System.out.println(li.previousIndex() + ":" + li.previous()); //从后往前遍历
}
  • 获取
    list.indexOf( );

  • 返回子集合
    sublist(x, y); 左闭右开
    List subList = list.subList(1, 3); 返回索引 1、2

List实现类

ArrayList 【重点】

  • 数组结构实现,必须要开辟连续空间,查询快、增删慢
  • jdk1.2版本,运行效率块、线程不安全

Vector

  • 数组结构实现,查询快、增删慢
  • jdk1.0版本,运行

LinkedList

  • 双向链表结构实现,无需开辟连续空间,增删快,查询慢

ArrayList

  • 创建ArrayList集合对象:ArrayList arrayList = new ArrayList<>();
  • 添加元素:
    arrayList.add();
  • 删除元素:
ArrayList arrayList = new ArrayList<>();
Student s1 = new Student("刘德华",17)
arrayList.add(s1);//添加元素
arrayList.remove(s1);//删除元素

【重点】在实际的业务需求中,或者逻辑上可以认为姓名和年龄等信息可以唯一确定某个人,所以可以尝试用以下代码对元素进行操作:

arrayList.remove(new Student("name", 10));

但是直接使用的话并不会将其删除,是因为这种方法是匹配内容,需要重写equals方法,因为ArrayList的remove、contains、indexOf等方法的源码中都调用了equals方法。

在Student类中重写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 不满足条件返回falsereturn false;
}
  • 【重点】遍历元素:

1.使用迭代器

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

2.使用列表迭代器

ListIterator li = arrayList.listIterator();
while(li.hasNext()){Student s = (Student)li.next(); //从前往后遍历
}while(li.hasPrevious()){Student s = (Student)li.previous();//从后往前遍历
}
  • 判断
    arrayList.contains(); 和 arrayList.isEmpty();
  • 查找
    arrayList.indexof();

源码分析
ArrayList源码中的常用常量:

DEFAULT_CAPACITY = 10; //默认容量
elementData//存放元素的数组
size//实际元素个数

注意:如果没有向集合中添加任何元素时容量为0,添加一个后,容量为10,每次扩容是原来的1.5倍

Vector

(开发中Vector不常用,了解一下即可)

  • 创建Vector集合对象:Vector vector = new Vector<>();
  • 增加、删除、判断同ArrayList
  • 遍历:(用枚举器遍历)
Enumeration en = vector.elements();
while(en.hasMoreElements()){String o = (String)en.nextElement();sout(o);
}

LinkedList

  • 创建LinkedList集合对象:LinkedList li = new LinkedList<>();
  • 常用方法与List一致

4 Set接口与实现类

Set接口

  • 特点:无序、无下标、元素不可重复(一个不包含重复元素的Collection)
  • 方法:全部继承自Collection中的方法
    增、删、遍历、判断与Collection一致

Set实现类

HashSet【重点】

  • 基于HashCode实现元素不重复
  • 当存入元素时,会调用equals确认其哈希码是否跟已有元素相同,如果为true,则拒绝存入

TreeSet

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

HashSet

  • (其本质就是HashMap,只使用HashMap的Key,add方法其实就是调用了HashMap的put方法)

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

  • 存储过程(重复依据):
    第一步:根据hashCode计算保存的位置,如果位置为空,直接保存,若不为空,进行第二步
    第二步:再执行equals方法,如果equals为true(通常要重写equals方法),则认为是重复,否则形成链表

  • 特点:基于HashCode计算元素存放位置

HashCode位置计算大致原理:
利用31这个质数,减少散列冲突
31提高执行效率 31 * i = (i << 5) - i 转为移位操作
当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入。
可以看看java/util/Arrays.java里面的hashCode源码:

public static int hashCode(Object a[]) {if (a == null)return 0;int result = 1;for (Object element : a)result = 31 * result + (element == null ? 0 : element.hashCode());return result;}

上面的element.hashCode()中的hashCode()方法是java/lang/Object.java里的本地方法,本地方法封存在JDK中,要下载JDK开源代码才能查看。源码的逻辑如下:
字符串对象的哈希码根据以下公式计算:

s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

使用 int 算法,这里 s[i] 是字符串的第 i 个字符的 ASCII 码,n 是字符串的长度,^ 表示求幂。空字符串的哈希值为 0。
对元素的操作(大同小异):

  • 新建集合:HashSet<T> hashSet = new HashSet<String>();
  • 添加元素:hashSet.add( );
  • 删除元素:hashSet.remove( );
  • 遍历操作:
    ​ 1. 增强for for( type type : hashSet)
    ​ 2. 迭代器 Iterator<String> it = hashSet.iterator( );
  • 判断:hashSet.contains( ); hashSet.isEmpty();
    需要注意:重写了hashCode和equals方法之后,remove(new Person("刘德华",20));contains(new Person("刘德华",20));等方法是可以成功删除或者输出的

TreeSet

(其本质就是TreeMap,只使用TreeMap的Key,add方法其实就是调用了TreeMap的put方法)

  • 特点
    基于排列顺序实现元素不重复
    实现SortedSet接口,对集合元素自动排序
    元素对象的类型必须实现Comparable接口,指定排序规则
    通过CompareTo方法确定是否为重复元素
  • 存储结构:红黑树
  • 创建集合 TreeSet<T> treeSet = new TreeSet<>()
  • 添加元素:treeSet.add();
  • 删除元素:treeSet.remove();
  • 遍历:1. 增强for 2. 迭代器
  • 判断:treeSet.contains();

补充:TreeSet集合的使用

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

// 重写compare,比较姓名和年龄(Person类属性有姓名和年龄)
@override
public int compare(Person o1, Person o2){int n1 = o1.getAge()-o2.getAge();int n2 = o1.getName().comareTo(o2.getName());return n1 == 0 ? n2 : n1;
}

5 Map接口与实现类

在这里插入图片描述

Map接口

作用和特点:

  • 用于存储任意键值对(key - value)
  • 键:无序、无下标、不允许重复(唯一)
  • 值:无序、无下标、允许重复

方法:

  • V put(K key, V value) 将对象存到集合中,关联键值。Key重复则覆盖键值。
  • V get(Object key) 根据键获得对应的值
  • Collection<V> values() 返回包含所有值的Collection集合
  • Set<K> keySet() 返回此Map中包含的键的Set视图。
  • Set<Map.Entry<K,V>> entrySet() 返回此Map中包含的映射的Set视图。

以HashMap为例说明:

//创建Map集合的HashMap对象Map<String, String> map = new HashMap<>();
// 1. 添加元素map.put("cn", "中国");map.put("uk", "英国");map.put("cn", "zhongguo"); // 会替换第一个 
// 2. 删除map.remove("uk");
// 3. 遍历
// 3.1 使用keySet()//Set<String> keyset = map.keySet();下一行的map.keyset已经有这行代码的含义
// 所有Key的set集合,尖括号中的是Key的数据类型for(String key : map.keySet()){sout(key + "---" + map.get(key));
}
// 3.2 使用entrySet()//Set<Map.Entry<String, String>> entries = map.entrySet();同理,下一行的map.entries已经表达for(Map.Entry<String, String> entry : map.entrySet()){sout(entry.getKey() + "---" + entry.getValue();
}

Map接口的内部接口Entry<K,V>

Interface Map.Entry<K,V>

  • Map键值对。 Map.entrySet方法返回Map的集合视图,其元素属于此类。

  • 获取对映射键值对的引用的唯一方法是从该集合视图的迭代器。 这些Map.Entry对象仅在迭代期间有效。

  • 如果在迭代器返回键值对之后已经修改了背景映射,则映射键值对的行为是未定义的,除非通过映射键值对上的setValue操作。

  • 常用方法:
    K getKey() 返回与此键值对相对应的键。
    V getValue() 返回与此键值对相对应的值。
    V setValue(V value) 用指定的值替换与该键值对相对应的值(可选操作)。 (写入地图。)

Map实现类

  • HashMap【重点】:
    JDK1.2版本,线程不安全,运行效率快。允许用null作为key或是value
  • Hashtable:
    线程安全,运行效率慢;不允许null作为key或是value
  • Properties(详见IO框架):
    Hashtable的子类,要求key和value都是string,通常用于配置文件的读取
  • TreeMap:
    实现了SortedMap接口(Map的子接口),可以对key自动排序

HashMap

  • 存储结构:哈希表(数组+链表+红黑树)
  • 使用key可使hashcode和equals作为重复
  • 增、删、遍历、判断与上面一致

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

TreeMap

6 泛型与工具类

泛型

  • 本质是参数化类型,把类型作为参数传递
  • 常见形式有泛型类、泛型接口、泛型方法
  • 语法:类名<T> 。T是类型占位符,表示一种引用类型,可以写多个,在尖括号里用逗号隔开<T,E,K,…>
  • 作用:1. 提高代码重用性;2. 防止类型转换异常,提高代码安全性
// 写一个泛型类
public class MyGeneric<T>{//使用泛型T//1 创建变量T t;//2 泛型作为方法的参数public void show(T t){System.out.println(t);}//3 泛型作为方法的返回值public T getT(){return t;}
}
// 使用泛型类
public class TestGeneric{public static void main(String[] args){//使用泛型类创建对象MyGeneric<String> myGeneric = new MyGeneric<String>();myGeneric.t = "hello";myGeneric.show("hello world!");//hello world!String string = myGeneric.getT();System.out.println(string);//helloMyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();myGeneric2.t = 100;myGeneric2.show(200);//200Integer integer = myGeneric2.getT();System.out.println(integer);//100}
}

注意: 1. 泛型只能使用引用类型
2. 不同泛型类型对象之间不能相互赋值

泛型接口

  • 语法:接口名<T>
  • 注意:不能创建泛型静态常量
//泛型接口
public interface MyInterface<T>{String name = "张三";//可以包含静态常量,但是不能用泛型来创建静态常量T server(T t);
}

泛型接口实现有两种途径:
一是创建实现类的时候就把泛型类型定义好;二是泛型接口的实现类仍然是泛型,这种的话在创建对象时必须定义好泛型的类型

//泛型接口实现类1
//创建实现类的时候就把泛型类型定义好
public class MyInterfaceImpl implements MyInterface<String>{@Overridepublic String server(String t){//方法体return t;}
}
//泛型接口实现类2
//泛型接口的实现类仍然是泛型
public class MyInterfaceImpl2<T> implements MyInterface<T>{@Overridepublic T server(T t){//方法体return t;}
}

第二种途径在创建对象时要声明泛型类型:

MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>();
impl2.server();

泛型方法

  • 语法:<T> 返回值类型

例:

public <T> void show(T t){}
public <T> T show(T t){//方法体return t;}

调用

MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("字符串");// show方法返回值类型自动变为字符串
myGenericMethod.show(200);// integer类型
myGenericMethod.show(3.14);// double类型

因此在调用泛型方法的时候,数据的类型不用传递,传递的数据决定了数据的类型

泛型集合

Java允许使用泛型集合类的时候不传递泛型(即使那个类是泛型类),这时就是Object类,如LinkedList li = new LinkedList();。意味着可以添加任何类型的数据,因为Object是所有类的父类。

但是存在的弊端就是,当传递的数据类型很多,到时要对Object类型强转,那么就会容易在强转的时候出错。而且如果一个集合里面有多种数据类型的时候就会容易出现异常。

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

确定集合的数据类型就会避免上述问题产生,也不存在要对Object类型强转的情况了。如LinkedList<String> li = new LinkedList<String>();

Collections工具类

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

  • 其他方法 :
    copy复制、reverse反转、shuffle打乱
    直接二分查找int i = Collections.binarySearch(list, x); 成功返回索引

补充:

// list转成数组
Integer[] arr = list.toArray(new Integer[0]);//当数组长度小于list长度时,数组长度自动变为list的长度,即0自动变为list的长度
sout(arr.length);
sout(Array.toString(arr));// 数组转成集合
// 此时为受限集合,不能 添加和删除!
String[] name = {"张三","李四","王五"};
List<String> list2 = Arrays.asList(names);// 把基本类型数组转为集合时,需要修改为包装类
Integer[] nums = {100, 200, 300, 400, 500};
List<Integer> list3 = Arrays.asList(nums);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/425670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CLOSE_WAIT状态的原因与解决方法

这个问题之前没有怎么留意过&#xff0c;是最近在面试过程中遇到的一个问题&#xff0c;面了两家公司&#xff0c;两家公司竟然都面到到了这个问题&#xff0c;不得不使我开始关注这个问题。说起CLOSE_WAIT状态&#xff0c;如果不知道的话&#xff0c;还是先瞧一下TCP的状态转移…

html:(32):字体,字号,颜色

文字排版--字体 我们可以使用css样式为网页中的文字设置字体、字号、颜色等样式属性。下面我们来看一个例子&#xff0c;下面代码实现&#xff1a;为网页中的文字设置字体为宋体。 body{font-family:"宋体";} 这里注意不要设置不常用的字体&#xff0c;因为如果用…

html:(33):文字排版粗体和斜体

文字排版--粗体 我们还可以使用css样式来改变文字的样式&#xff1a;粗体、斜体、下划线、删除线&#xff0c;可以使用下面代码实现设置文字以粗体样式显示出来。 p span{font-weight:bold;} 在这里大家可以看到&#xff0c;如果想为文字设置粗体是有单独的css样式来实现的&…

[剑指offer][JAVA]面试题第[14-1、2]题[剪绳子][Leetcode][第343题][整数拆分][数学][动态规划][背包]

【问题描述】[中等] 给你一根长度为 n 的绳子&#xff0c;请把绳子剪成整数长度的 m 段&#xff08;m、n都是整数&#xff0c;n>1并且m>1&#xff09;&#xff0c;每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少&#xff1f;…

Java学习笔记4——I/O框架

目录1 流的概念2 流的分类3 字节流文件字节流FileInputStreamFileOutputStream字节缓冲流BufferedInputStreamBufferedOutputStream对象流ObjectOutputStreamObjectInputStream注意事项5 字符流文件字符流FileReaderFileWriter字符缓冲流BufferedReaderBufferedWriter转换流Inp…

snappy

参考From <https://dirtysalt.github.io/snappy.html> Snappy API From <https://www.npmjs.com/package/snappy> Snappy 是一个 C 的用来压缩和解压缩的开发包&#xff0c;其目标不是较大限度压缩&#xff0c;而且不兼容其他压缩格式。Snappy 旨在提供高速压缩速…

html:(34):下划线和删除线

文字排版--下划线 有些情况下想为文字设置为下划线样式&#xff0c;这样可以在视觉上强调文字&#xff0c;可以使用下面代码来实现&#xff1a; p a{text-decoration:underline;}<p>三年级时&#xff0c;我还是一个<a>胆小如鼠</a>的小女孩。</p> &…

设计模式--职责链模式

实验15&#xff1a;职责链模式 本次实验属于模仿型实验&#xff0c;通过本次实验学生将掌握以下内容&#xff1a; 1、理解职责链模式的动机&#xff0c;掌握该模式的结构&#xff1b; 2、能够利用职责链模式解决实际问题。 [实验任务]&#xff1a;财务审批 某物资管理系统…

[剑指offer]面试题第[66]题[构建乘积数组][Leetcode][JAVA][第238题][除自身以外数组的乘积][数组]

【问题描述】[中等] 给你一个长度为 n 的整数数组 nums&#xff0c;其中 n > 1&#xff0c;返回输出数组 output &#xff0c;其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。示例:输入: [1,2,3,4] 输出: [24,12,8,6]提示&#xff1a;题目数据保证数组之中任…

centos 6.5 安装redis

1. 下载redis&#xff0c;编译安装 下载地址&#xff1a;https://redis.io/download&#xff08;建议大家都选择稳定版本&#xff09; 下载到本地&#xff0c;然后上传到集群 当然也可以通过命令行直接在线下载 $ wget http://download.redis.io/releases/redis-5.0.3.tar.gz $…

[剑指offer][JAVA]面试题第[29]题[顺时针打印矩阵][数组]

【问题描述】[中等] 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a;输入&#xff1a;matrix [[1,2,3,4],[5,6,7,…

玩转oracle 11g(48):oracle命令窗口执行sql语句

在plsql里面找到command window&#xff0c;用命令窗口打开

POJ-2407 欧拉函数

本题题意就是要对输入的任意一个1e9内的数字求出其欧拉函数值 根据 欧拉函数 编辑对正整数n&#xff0c;欧拉函数是小于n的正整数中与n互质的数的数目&#xff08;φ(1)1&#xff09;而互质指的是公因数为只有1的两个数&#xff0c;任何数与1都互质根据欧拉公式通式&#xff1…

模块导入以及书写规则

转载于:https://www.cnblogs.com/www-qcdwx-com/p/10419162.html

并发编程面试题

目录并发编程的优缺点为什么要使用并发编程&#xff08;并发编程的优点&#xff09;并发编程有什么缺点并发编程三要素是什么&#xff1f;在 Java 程序中怎么保证多线程的运行安全&#xff1f;并行和并发有什么区别&#xff1f;什么是多线程&#xff0c;多线程的优劣&#xff1…

html:(35):缩进和行高

段落排版--缩进 中文文字中的段前习惯空两个文字的空白&#xff0c;这个特殊的样式可以用下面代码来实现&#xff1a; p{text-indent:2em;} <p>1922年的春天&#xff0c;一个想要成名名叫尼克卡拉威&#xff08;托比?马奎尔Tobey Maguire 饰&#xff09;的作家&#x…

new/delete与malloc/free

C语言中使用malloc/calloc/realloc用来在堆上分配空间&#xff0c;free将申请的空间释放掉。 malloc&#xff1a; 原型&#xff1a;extern void *malloc(unsigned int num_bytes)。 功能&#xff1a;分配长度为num_bytes字节的内存块。 1 int *p(int*)malloc(sizeof(int));…

Java学习笔记5-1——多线程

目录前言核心概念线程创建继承Thread类实现Runnable接口上述两个方法小结实现Callable接口并发问题简介静态代理模式线程状态线程停止&#xff08;stop&#xff09;线程休眠&#xff08;sleep&#xff09;线程礼让&#xff08;yield&#xff09;线程强制执行&#xff08;join&a…

[Leedcode][JAVA][第128题][最长连续序列][Hash]

【问题描述】[困难] 给定一个未排序的整数数组&#xff0c;找出最长连续序列的长度。要求算法的时间复杂度为 O(n)。示例:输入: [100, 4, 200, 1, 3, 2] 输出: 4 解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。【解答思路】 1. SortCompare 先排序&#xff0c;题意要求连…