Java 08集合
集合
Collection
接口,不可以创建对象add
clear
remove
contains(Object obj);判断是否存在
isEmpty 空返回为true
size
ArrayList
Collection<String> c=new ArraryList<>();
以多态的方法创建集合对象,调用单列集合中的共有方法
编译看接口,运行看实现类对象
*注意或者说提醒一下,需要先看父亲有没有这个类
remove
对于基础数据类型,之间删除即可
如果是对象放入进行删除,那么我们需要重写一下equals方法,因为之前的,我是通过地址进行删除的
contain
同理,也需要重写equals方法;因为也需要判断一相等时怎么进行判断的
集合通用的遍历方式
迭代器遍历
Collection<student> c=newArrayList<>();
c.add("","");
Iterator<student> it=c.iterator();
it.next();//获取下一个对象//遍历的方法,如下
student s1=it.next();
//next方法会将指针指向下一位
while(it.hasNext()){student s=it.next();System.out.println(s);
}
也可以是下面这种
警告
next一定要仅仅调用一次,因为调用一次,指针就会向下移动一个
增强for循环
for(元素的数据类型 变量名:数组或者数据){}
for(student it:c){
//这样就可以进行遍历了
}
foreach循环
c.foreach();
c.foreach(@Overridepublic void accept(Student stu){}
)
List
存储有序
有索引
可以储存重复的
ArrayList
LinkedList;
一些API
add
add(int index ,E 对象)
remove
remove(int index);删除下标
也可以手动装箱
remove(Integer.valueof(111));
set
set(int index,E 对象);设置某个地方的元素为指定的对象
get
get(int index);获取某个地方的返回值
遍历
除了Collection那几个以外;
还可以for(int i=0;i<arr.size();i++){int x=arr.get(i);
}
ListIterator<String> it=arr.listIterator();
while(){
//即可}特殊的,我也可以进行逆向遍历
while(it.hasPrevious()){
int x=it.precious();
}
//需要注意的一点,由于刚产生的指针指向的是最前面,所以如果想倒序遍历的化,需要先来个正序遍历使得指针指向最后
并发修改异常
使用迭代器遍历集合的过程中,调用了集合对象的添加,删除方法,就会出现此异常解决方式:使用迭代器自己的删除和添加的方法,it.remove();
//添加方法只有list独有!!!!!Listiterator
it.add("asw");即可倒数第二个删除没事,原因自己想想即可
数据结构
一种计算机底层存储、组织数据的方式,是指数据相互之间是以什么方式排列在一起的
栈
跟c++一样
后进先出
队列
后进后出,
先进先出
数组
查询速度快
增删效率低
链表
增删相对快因为只需要改地址
查询慢一点
树
二叉查找树
又称之为二叉排序树或者是二叉搜索树
左子树上的值都小于当前节点
右子树上的值都大于当前节点存入数据的时候,大的存到右边,小的存到左边弊端:如果是一个递增的序列,存入的时候就会成为单链,就成为了瘸子树
平衡二叉树
任意节点的左右子树的高度差不超过1
当你传入一个数据的时候,他不再是平衡二叉树,就会进行旋转,
旋转
从添加的节点开始,不断往父亲节点找到不平衡的节点
左左
当根节点的左子树有节点插入,导致二叉树不平衡,
就需要进行右旋转
左右
当根节点的左子树的右子树有节点插入,导致二叉树不平衡
先局部左旋,再进行右旋
右右
同理
右左
同理
红黑树
自平衡的一类二叉查找树,
每一个节点可以是黑色或者红色,红黑树不是高度平衡的,他的平衡是通过红黑规则进行实现的
特点规则
不写了,累的上
添加节点的规则
默认是红色存入,在进行颜色的改变,效率更高
ArrayList
原理
底层是数组写过,就是扩容1.5倍
当然,如果我光创建了ArrayList但是没有添加任何元素,那么实际上底层就是长度为0
说一下,是底层代码扩容,实际上的length是没有进行改变的
LinkedList
原理
底层是链表
有一点点像c++中的双端队列删除增加比较简单,但是查询的时候是从头遍历或者从尾巴遍历;
get
泛型
jdk5版本进行引入,可以在编译阶段约束操作的数据类型,并且进行检查
泛型的默认的类型是obje
好处
1.统一数据类型
2.将运行期的错误提升到了编译期
ArrayList<String>arr=new ArrayList<>();
ArrayList brr=new ArrayList();//相当于object,可以加入任意类型·
泛型类
常见的泛型标识符号E V K T
E:Element
T:Type
K:Key
V:Value
当你不知道想要什么数据类型的时候,就可以写个泛型,让使用对象自己去判断什么时候确定为什么类呢:当你创建对象的时候
泛型方法
1.非静态方法:内部的泛型,会根据类的泛型去进行匹配
2.静态的方法:因为static需要在创建对象的时候就会进行创建,那么就得去提前申请出自己的类型,例如:
调用方法,传入具体参数的时候就会确定类型
public static<T> void printadd(T []arr){}
泛型接口
接口也可以进行创建泛型
例如
interface Inter<T>{}
1.实现类,实现接口的时候确定具体的类型
2.实现类实现接口,但是没有确定具体的类型,就让接口的泛型,跟着类的泛型去匹配
泛型通配符
?
问号就是通配符
例如传入ArrayList<?> list;
?:任意类型
?extends E :指的是E和E的所有的子类
?super E:指的是E和E的所有的父类
可以使用?继承e,也就是可以传入e和e的子类
也可以传入super,需要传入他自己或者他的父亲类
TreeSet
排序,去重,
底层红黑树操作
操作
TreeSet<String> ts=new TreeSet<>();
ts.add("sdfa");
自定义对象排序加去重
public class student implements Comparable<student> {//@Overridepublic int compareTo(student o) {//0 只有一个数据if(o.id==this.id){return 0;}//1 正序排列if(o.id>this.id){return 1;}//-1 倒叙排列return -1;//****也可以return this.id-o.id;//升序排列this-o}
}首先需要继承Comparable接口,
该接口需要带着需要的实现类,加入需要比较的实现类即可
重写里面的compareTo方法,进行比较即可
就是自定义比较排序即可
但是需要注意的是,一定要进行比较才可以
String
对于String而言
String a="a";
String b="b";
a.compareTo(b);
比较器排序
构造方法中,传入一个Compartor接口
构造器的优先级要高于自然排序
对于数组进行操作的的时候,对于int而言,应该写他的对象Integer进行排序才可以
仅限于这样创建的数组
HashSet
采取hash表存数据
HashSet<student> arr=new HashSet<>();
哈希表是一种对增删改查数据性能都比较好的结构
去重
要想进行去重,需要重写hashCode和equals才可以
原理
首先存入的数据,会调用对象的hashCode方法计算出一个应该存在的索引位置,查看该位置上是否存在元素
不存在:直接存
存在:调用equals方法,比较数据的内容,放在他的下面所以我们需要尽量让hashCode的返回值尽量不同,否则时间复杂度就到达了n方
可以这样Object.hash(age,ss)
只能让hash值的重复值降低,但是不能完全避免完全不一样,所以需要调用equals方法进行比较才可以
底层原理
jdk7即之前
jdk8及之后
1.创建HashSet集合,内部回存在一个长度为16个大小的数组
public HashSet(){map= new HashMap<>();//默认创建因子为0.75;
}
2.调用集合的添加方法,会调用对象的hash值去取余数组的长度及16
为什么要进行右移16位呢,因为将hash值转化为2进制之后,会发现最后几位的值相同的比较多,所以我们会右移16位进行hash扰动,在对之前的值进行异或操作,进行二次hash,那么的道德hash值的答案就会比较散,就不会出现大部分数据储存到一个下表的情况
这俩结果算出来是一样的
因为并运算的效率会更高
如何提高性能呢?
1.扩容数组
A:当数组的元素个数到达了16*0.75(加载因子)=12;
扩容到原数组的2倍的大小//是两倍!!
B:链表一个上面挂着的元素超过了8(阈值)个,并且数组长度没有超过64;
**注意哈,实际上就是他底层代码自己改变2.链表转红黑树
链表的长度超过了64了,并且挂着的元素超过了8个
LinkedHashSet
特点
去重,并且包装存储数据顺序,没有索引
LinkedHashSet<String> arr=new LinkedHashSet<>();
原理
依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的孙旭
Collection工具类
可变参数
例如
public static int getSum(int ... nums){//这边的nums实际上就是个数组int sum=0;for(int a:nums){sum=sum+a;}return sum;
}注意一下,可变参数需要放到最后,否则处于他前面的数据就会被全部吃掉
作用
并不属于集合,是用来操作集合的工具
Collection是对象
Collections是工具
双链集合
TreeMap
HashMap
LinkedHashMap
Map接口
Map集合是一种双列集合,每个元素包含两个数据
Map集合的元素的格式key=velue(键值对元素)
key键:不允许重复
velue值:允许重复
键和值是一一对应的,每个键只能找到自己的对应的值
key+value这个整体,我们称之为键值对或者是键值对对象
在Java中使用Entry对象表示
常用的API
Map<Integer,Integer> map = new HashMap<>();
get
get(Key);
获取key下面的值
put
map.put(1,2);//也可以进行修改,返回值是之前的value
map.put(key,value);
remove
map.remove(key);//根据键值删除数据,返回的也是之前这个键值对应的value
clear
map.clear();//清空map
containsKey
map.containsKey(Object key);
查看是否存在这个数据
containsValue
map.containsValue(Object Value);
查看是否存在这个值
isEmpty
判断集合是否为空
size
返回键值对的个数
集合的常用的遍历
1.通过键找值
HashMap<String,String> map=new HashMap<>();
Set<String>keyset=map.keySet();
//获得所有的键
for(String now:keyset){String x=map.get(now);
}
2.通过键值对对象遍历
Set< Map.Entry<String,String> > arr = map.entrySet();
//拿到了所有的对象
for( Map.Entry<String,String> now:arr){String x1=now.getKey();String x2=now.getValue();//这样就可以获得了
}
3.通过foreach方法
map.foreach(new BiComsumer<String,String>(){@Overridepublic void accept(String key,Strign value){//获得了key和value}})
HashMap
哈希表
键唯一
需要重写HashCode和equals方法
TreeMap
红黑树
键排序
需要自定义Comparator或者是implements Comparable接口(重写compareTo方法)
LinkedHashMap
哈希表+双向链表
键唯一,可以保证存取顺序
也需要重写HashCode和equals方法