JAVASE总结--集合
来源:互联网 发布:matlab矩阵归一化函数 编辑:程序博客网 时间:2024/06/06 02:49
java中万事万物皆对象。所以容器也是对象。
首先将容器抽象成一个接口collection,它里面有两个比较重要的子接口:
list 和 set。
list和set有自己的子实现类。
类是用来存放任意类型的数据,而容器只能存放引用类型的数据(泛型)
collection是容器的根接口,提供了好多容器访问的方式,其中容器中每一个值都被称为元素。
java中,绝大部分容器都是由数组来实现的,极个别由链表和树来实现。
容器的底层就是一个数组,Object[],它什么都可以放
每当容器中数组容量不够的时候,就会自动扩容,扩容时创建新数组,并将之前的数据拷贝,大小为之前的1.5倍。
_______________________________________________
collection(接口)
list(接口)数据对象有顺序且可以重复
ArrayList(动态增长和缩减的索引序列)
LinkedList(可以在任何位置进行高效的插入和删除操作的有序序列)
set(接口)数据对象没有顺序且不可重复
HashSet(没有重复元素的无序集合)
Map(接口) key-value键值对
_______________________________________________
//创建一个容器对象
Collection c1=new ArrayList();
Collection只是接口不能实例化对象,只能通过子类来实例。
========================================================================
Collection常用方法
add-------------添加
c1.add("bj01");
c1.add("bj02");
c1.add("bj03");
addAll------------添加
Collection c2=new ArrayList();
c2.add("bj01");
c1.addAll(c2);
clear-----------------清空数据将数组长度变为0
c1.clear();
remove-------如果存在,移除单个元素
removeAll-------如果存在,移除整个指定collection在此的数据
contains---------------------包含
c1.contains("bj01");//true
containsAll------------------包含
c1.containsAll(c2);//true
retainAll-------取出两个容器的交集
size------------返回当前容器的元素数
hashCode------------返回此collection的哈希码值
toArray-----以正确顺序返回包含此列表中所有元素的数组。(见下)
isEmpty----------当前collection是否有数据
equals------------------逻辑相等
在ArrayList中找不到equals时,去父类AbstractList中查找。源码如下:
public boolean equals(Objecto) {
if (o ==this)//引用同一个对象---true
return true;
if (!(o instanceof List))//o不是List的对象---返回false
return false;
ListIterator<E>e1 = listIterator();//迭代器e1
ListIterator<?>e2 = ((List<?>)o).listIterator();//迭代器e2
while (e1.hasNext() &&e2.hasNext()) {//遍历
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ?o2==null :o1.equals(o2)))//( 如果o1不为空且o1.equals(o2) 或者o1为空、o2为空) 否则返回false
return false;
}
return !(e1.hasNext() ||e2.hasNext());
}
x? y:z x是一个boolean类型,若x为true,结果显示y,若x为false,则结果显示z.
toArray
c1.toArray(array);
System.out.println(c1.toString());
for(int i=0;i<array.length;i++){
System.out.println(array[i]);
}
虽然容器只能存储引用数据类型,但是存入基本数据类型不会出错,是因为自动装箱。
例如:
collection.add(new Integer(1));
collection.remove(1);
容器也可以存储自定义对象。但是一定要重写 toString、equals、hashCode。
toString
快捷键为:Shift+Alt+S +S
object:打印出来的就是当前类的信息@地址信息的hash值
vo类中:打印出来当前类所包含所有属性的信息
equals
快捷键为:Shift+Alt+S +H
object:两个对象比较的是地址,强调的是物理地址的相等,相当于==
普通对象中:两个对象逻辑上是否相等,比较的是两个对象的属性
hashCode
一个对象会有一个唯一的hash值,然后不同对象hash值相等的概率几乎为0
使用快捷键生成的方法一般不会出现问题。
代码:
public class Student {
private Stringsname;
private Stringgender;
private Stringidnumber;
private int age;
public Student() {
}
public Student(Stringsname, Stringgender, Stringidnumber, int age) {
this.sname =sname;
this.gender =gender;
this.idnumber =idnumber;
this.age =age;
}
}
/****************自定义对象*******************/
Student s1 =new Student("zhangsan","1", "999", 18);
Student s2 =new Student("zhangsan","1", "999", 18);
collection.add(s1);
collection.remove(s2);
源码:
add
//真正保存数据的数组
private transient Object[] elementData; //arrayList的实际元素数量
private int size;
首先确定这个容器是不是空的,是的话将大小定为10.
同时将内容存至实际存储的元素数量的位置,之后size+1。
remove
输入字符串,判断输入的是否为空字符串,
是的话,遍历,找到值为空的,快速删除,size-1
不是的话,遍历找到与其逻辑地址相等的值,快速删除,size-1
========================================================================
List
常用方法:(以及collection的方法)
add(index,Object)-----将内容插入到指定的位置,后面的全体向后移
get-----获取指定位置的值
set----覆盖掉指定位置的原来的值
indexOf-----查看是否包含输入的内容
remove(index,Object)---将指定位置的值删除
输入下标,首先检查传入的下标是否越界,将数组从删除位后一位开始到拷贝到删除位置,之后size-1
========================================================================
* ArrayList
底层代码分析:
* 成员变量
* private int size;
* 默认初始化为0
* private Object[] elementData;
* 在list内部有一个私有的数组,而且这个数组只能装引用类型
* 这个对象什么类型的数据都可以存放
* 创建对象的时候,直接给成员变量赋值了一个空数组
* this.elementData = EMPTY_ELEMENTDATA;
*
* 为什么api上面说构造一个初始容量为 10的空列表。
* JDK5的时候创建数组长度默认为10
* JDK7的时候创建数组长度为0,而且不管创建再多的arrayList,其实就是一个对象
*当我们添加数据的时候
* ensureCapacityInternal(size+1);
* 当我们第一次使用的时候,默认创建一个大小为10的数组
* elementData[size++] = e;
* 让size位置存放数据,并且size自增,size存放的是当前数组的实际长度
* 当数组的长度不满足当前需求的时候,每次就会扩容1/2
* 当我们删除数据的时候
* 循环比例数据,如果知道equals的,获取当前数据的索引,让数组后面的数据整体前移
* 并且将最后一个数据赋值为null
* size就是实际存放数据的多少
* 当我们调用数组长度方法的时候,直接返回size
* get方法的原理
* elementData[index]
* remove的时候
* 获取当前数据的索引,让数组后面的数据整体前移
* 并且将最后一个数据赋值为null
版本差异
1.5的时候,创建数据每次都创建一个长度为10的数组
1.7的时候,每次都指向同一个静态空数组。
========================================================================
LinkedList
* 链表
* 在内存中是不连续的空间,直接通过节点的next,previous属性访问
* 链表添加数据就是添加Node节点,让节点的next,previous分别指向对应的节点
* 所以连接表的插入和删除操作比较快捷
* 链表只记录一个开始和结尾 first和last
*
* 数组
* 在内存中是连续的空间,可以按照索引访问
* 支持随机访问
* 所以数据的get(index)速度较快
*创建对象
* 直接创建一个空对象
* int size = 0;
* Node first = null;
* Node last = null;
* add新增数据
* 默认将数据拼接到链表的末尾
* 创建一个新节点,新节点指向上个节点,原来的最后一个节点指向新节点,last指向新节点
* remove删除数据
* 根据索引遍历数据,只需要遍历链表的一 半
* 获取到指定节点
* 根据节点的位置改变pre next first last的指向
* set修改数据
* 循环到指定的节点
* 修改值
* get查询数据
* 循环到指定的节点,返回节点数据
*get方法做了微小的优化,如果索引大于size()/2就从列表尾端开始搜索信息的操作。
========================================================================
collections工具类(类似于Arrays)
java.utils包下
//填充List
Collections.fill(list, "bjsxt");
//返回最大值和最小值
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
//替换指定元素
Collections.replaceAll(list, "bjsxt", "sxtly");
//逆序
Collections.reverse(list);
//随机排序
Collections.shuffle(list);
Collections.shuffle(list, new Random());
//排序
Collections.sort(list);
Collections.reverse(list);
//折半查找折半查找的前提是有序
Collections.sort(list);
System.out.println(Collections.binarySearch(list, "bjsxt9"));
========================================================================
遍历List
//声明并初始化了一个List
List<String>list = new ArrayList<String>();
for (int i = 0; i < 20;i++) {
list.add("bjsxt" +i);
}
List<String>linked = new LinkedList<String>();
for (int i = 0; i < 20;i++) {
linked.add("bjsxt" +i);
}
*第一种方式for
//第一种遍历方式(当我们要使用索引值的时候,必须使用第一种)
for (int i = 0; i < list.size(); i++) {
System.out.println("list中的第" + (i + 1) + "个元素的值为:" + list.get(i));
}
* 第二种方式增强for循环
//第二种方式(如果只需要获取list中的值,效率较高)
for (String string : list) {
System.out.println(string);
}
* 迭代器
* Iterator(通过光标/游标对数据进行访问的一种方式)
* hasNext
* 判断当前光标位置是否有数据
* next
* 取出当前位置的数据,并且光标向后移动一位
* 使用的时候需要注意不要随意的去调用next方法,会导致跳过部分内容
* 在使用next的时候我们必须要保证hasNext返回true
//第三种容器自带的迭代器
Iterator<String>iterator = list.iterator();
//开始遍历
while (iterator.hasNext()) {
String string =iterator.next();
System.out.println(string);
}
return iterator;
}
========================================================================
Map
* Map是一个键值对结构的数据类型
* key:我们要通过key去找我们对应的值
* value:我们存放的具体信息
* 我们存储的信息都是以key作为标识,所以key不能重复
* 如果key信息重复,后面会把前面的给覆盖掉
public class HelloMap {
public static void main(String[]args) {
//创建对象
Map<String,Object>map = new HashMap<>();
//如何添加值
map.put("zhangsan", 1234567);
map.put("lisi","HelloMoto");
map.put("lisi","HelloKitty");
map.put("stu",new Student("zhangsan", 18));
//删除值
map.remove("lisi");
//取值
System.out.println(map.get("zhangsan"));
System.out.println(map.get("lisisi"));//键不存在时,输出null
//查看map的长度(即,存了几组值)
System.out.println(map.size());
//获取所有的key
Set keySet =map.keySet();
Collection collection =map.values();
//是否包含指定的key
System.out.println(map.containsKey("stu"));
//是否包含指定的值
System.out.println("包含值:" +map.containsValue(new Student("zhangsan", 18)));
//clear清空
map.clear();
System.out.println(map);
}
底层代码分析:
*创建对象
* //默认的初始容量16
* static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
* //默认的使用的大小是总大小的75%
* static final float DEFAULT_LOAD_FACTOR = 0.75f;
* //map中数组可用的大小
* int threshold;
* //map中数组存放数据大小
* int size;
* //创建对象的时候默认创建一个空的entry数组,因为存储的内容都存放在 了entry当中
* transient Entry[] table = (Entry[]) EMPTY_TABLE;
* 存放数据
* 第一次存放数据
* 首先检查数组是不是默认的,如果是第一次需要创建一个新的
* 新创建的数组是entry类型的,大小为16,可用为12
* 计算key的hash值,相对是唯一的
* 然后根据数组的大小计算当前key所应该处于的索引位置(hash值&数组大小)
* 然后创建新的entry将数据存放至数组
* 第一次之后加入数据(即,)
* 首先计算key对应的hash值,算出对应的位置索引
* 判断当前key有没有指定值,
* 如果已经存在值
* 就会把原来的值返回,并且新的value覆盖掉原来的值
* 如果已经不存在值
* 我们还需要判断当前数组容量是否足够
* 扩容大小为原来的两倍,可用的大小也为原来的两倍,总大小的0.75
* 最后将其存放至容器
* 取出数据
* 首先判断map是否为空,为空直接null
* 不为空,计算当前key的hash值,然后计算索引值
* 取出map的数组中指定位置的entry,然后进行比较
* 比较当前对象,如果当前对象不equals,开始比较单向链表中的entry
* 比较的时候先比较hash &&如果hash都不一样,对象肯定不一样,提高效率
*
* 为什么map数组的大小只允许使用75%
* 假如数组用满,他并不是将数组的每个索引全部占用
* 当我们用对象的hash值去&数组大小的时候,不可避免会产生相同的索引
* 这样就会导致一个索引有可能存放两个不同key,这个时候使用单向链表解决
* 首先数组索引指向新创建的entry,新entry有一个next属性会指向原来的entry对象,形成一个单向链表。
* 其实如果使用单向链表存储数据的时候,已经违背了map设计的思想
* 所以我们最好重写每一个对象的hashcode方法
* 当我们的map里面的数组进行扩容的时候,当扩容完毕,首先散列我们现有存储的对象,尽量把存在链表的地方给分开,提高查询效率
*
* Entry:记录
* 我们map为了存放数据,所以专门创建的一个静态内部类
* 类似于我们数组中的一个元素
* entry里面有两个属性
* key
* value
* 另外为了避免一些问题:不同hash算出相同index
* next:
* 另外为了查找更加的快捷,专门记录了key的hash值
* hash:比较的时候线比较hash值
如何遍历Map
public static void main(String[]args) {
//如何遍历map
Map<String,String>map = new HashMap<>();
//存放数据
for (int i = 0; i < 20;i++) {
map.put("bjsxt" +i, "sxt" +i);
}
//获取map中所有的key,遍历所有的key
Set<String>set = map.keySet();
for (String key :set) {
System.out.println(map.get(key));
}
}
=======================================================================
Set
set接口中的元素是没有顺序的,而且是不能重复的。
*创建过程
* private static final Object PRESENT = new Object();
* private transient HashMap<E,Object> map;
* map = new HashMap();
* set的底层就是一个map
* 添加数据
* map.put(e, PRESENT)
* 其实就是向map中添加了一个Object对象
* set中绝对不会有重复的值,会覆盖
* 因为set就相当于map的key,key是不会有重复的,所以set不会重复,相同的值只会保留一份
*删除数据
* map.remove(o)
//创建
Set<String>set = new HashSet<>();
//添加
for (int i = 0; i < 20;i++) {
set.add("bjsxt" +i);
}
//删除
set.remove("bjsxt1");
//只能迭代获取判断有无,不能直接获取
//set的遍历
//for (String string : set) {
//System.out.println(string);
//}
//迭代器
Iterator<String>iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
================================================================================================
comparable
作用:排序
我们从list中存储数据时数据是根据哈希值以及数组长度计算的索引值,所以取出时是无序的。
list排序使用collections.sort()方法。
该方法可以对字符串进行排序,但是当需要排序的内容不止一个字符串时,会报错。
打开String源码,
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
发现String实现了Comparable接口。
因此想要按照一定顺序进行输出需要在具体类实现comparable接口,重写其方法compareTo,在方法中进行排序。代码:
@Override
public int compareTo(Studento) {
//首先获取年龄差
int flag =this.getAge() -o.getAge();
//按照年龄进行排序
if (flag == 0) {
//开始按照姓名排序
flag =this.getName().compareTo(o.getName());
if (flag == 0) {
//如果名字也一样 按照学号排序
flag =this.getSno().compareTo(o.getSno());
}
}
return flag;
}
尤其是当传入的是组合时。Comparable接口就显得尤为重要。
代码:
package com.bjsxt.ly;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestComparable {
public static void main(String[] args) {
}
private static void testCar() {
//创建一个容器对象
List<Car> list = new ArrayList<>();
//遍历并向其中添加数据
for (int i = 0; i < 10; i++) {
list.add(new Car("bjsxt" + (int) (Math.random() * 9), new Engine("sxt" + (int) (Math.random() * 9), (int) (Math.random() * 9)), new Interior("java" + (int) (Math.random() * 9)), new Tyre("ly" + (int) (Math.random() * 9))));
}
//排序
Collections.sort(list);
//对list进行排序
System.out.println(list);
}
private static void testStudent() {
//创建一个容器对象
List<Student> list = new ArrayList<>();
//遍历并向其中添加数据
for (int i = 0; i < 10; i++) {
list.add(new Student("sxt" + (int) (Math.random() * 9 + 1), "201601" + i, (int) (Math.random() * 11)));
}
//对list进行排序
Collections.sort(list);
System.out.println(list);
}
}
car:
package com.bjsxt.ly;
public class Carimplements Comparable<Car> {
private String type;
private Engineengine;
private Interiorinteriorl;
private Tyretyre;
public Car() {
}
public Car(String type, Engine engine, Interiorinteriorl, Tyretyre) {
super();
this.type =type;
this.engine =engine;
this.interiorl =interiorl;
this.tyre =tyre;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type =type;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engineengine) {
this.engine =engine;
}
public Interior getInteriorl() {
return interiorl;
}
public void setInteriorl(Interiorinteriorl) {
this.interiorl =interiorl;
}
public Tyre getTyre() {
return tyre;
}
public void setTyre(Tyretyre) {
this.tyre =tyre;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result =prime * result + ((engine ==null) ? 0 :engine.hashCode());
result =prime * result + ((interiorl ==null) ? 0 :interiorl.hashCode());
result =prime * result + ((type ==null) ? 0 :type.hashCode());
result =prime * result + ((tyre ==null) ? 0 :tyre.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;
Car other = (Car)obj;
if (engine ==null) {
if (other.engine !=null)
return false;
} else if (!engine.equals(other.engine))
return false;
if (interiorl ==null) {
if (other.interiorl !=null)
return false;
} else if (!interiorl.equals(other.interiorl))
return false;
if (type ==null) {
if (other.type !=null)
return false;
} else if (!type.equals(other.type))
return false;
if (tyre ==null) {
if (other.tyre !=null)
return false;
} else if (!tyre.equals(other.tyre))
return false;
return true;
}
@Override
public String toString() {
return "Car [type=" +type +", engine=" +engine + ", interiorl=" + interiorl + ", tyre=" +tyre + "]";
}
@Override
public int compareTo(Caro) {
//先比较车的牌子
int flag =this.getType().compareTo(o.getType());
if (flag == 0) {
//开始比较发动机
flag =this.getEngine().compareTo(o.getEngine());
if (flag == 0) {
//继续比较轮胎
flag =this.getTyre().compareTo(o.getTyre());
if (flag == 0) {
//继续比较内饰
flag =this.getInteriorl().compareTo(o.getInteriorl());
}
}
}
return flag;
}
}
算了,需要时看代码吧,太多了。
Testttttt/com.bjsxt.ly.comparable。
- JavaSe集合总结
- JAVASE总结--集合
- JavaSE集合框架总结
- JavaSE总结 -集合框架collection
- JavaSE总结-集合框架-List
- JavaSe总结-15- 集合框架
- JavaSE--12--集合的总结
- 黑马程序员--javaSE--java集合容器总结
- javaSE(12)(集合大总结)
- JavaSe总结-16- 集合框架(2)
- JavaSe总结-17- 集合框架(3)
- JavaSe总结-18- 集合框架(4)
- JavaSE基础知识总结--Collection、Map集合
- javaSe-集合
- javase集合
- JavaSe总结-19- 集合总结(5)&异常&文件操作
- 黑马程序员——JavaSE之集合框架总结二
- javase总结
- MongoDB 安装以及使用
- 内联函数与宏的区别
- 124.leetcode Binary Tree Maximum Path Sum(hard)[先序遍历]
- 自己动手实现优先级队列
- Console命令详解,让调试js代码变得更简单
- JAVASE总结--集合
- UNITY之背包管理
- PHP 短信验证功能模块
- NGUI和可视化添加按钮注册事件效果相同的代码
- 如何使用多功能影像测量系统测量瓷片长宽尺寸
- MFC 不要让Cdialog子窗体位于最前,取消子窗体位于父窗体前面,取消非模态对话框最前面
- 小地图制作
- Apriori算法延伸出来的字符串统计+匹配问题
- No service of type Factory available in ProjectScopeServices