Day15集合值框架
数组:部分集合的底层是用数组写的;
基本数据类型存储的是值,
引用数据类型 中存储的不是对象,是对象的地址值。
数组与集合的区别:
1. 数组 可以存储基本数据类型,也可以存储引用数据类型,基本数据类型存储值,引用数据类型存储地址值。
集合只能存储引用数据类型(对象)。集合中也可以存储基本数据类型,但是在存储的时候会自动装箱成对象。
2. 数组的长度是固定的,不能自动增长;
集合的长度是可变的。可以随着元素的增加而增长;
什么情况下使用数组或者集合:
如果元素的个数是固定的使用数组(效率高);
如果元素的个数是变化的使用集合。
Collection(单列集合的跟接口)
List集合: 有序(存和取是有序的),有序列,可以存储重复元素
1. ArrayList 集合:数组实现。 查询块,修改也快,增删慢
2. LinkedList集合:链表实现。查询慢,修改也慢,增删快
Set集合:无序(存和取是无序的) ,无序列,不能存储重复元素。
1. HashSet集合:哈希算法,
2. TreeSet集合:二叉树算法,
Collection集合
add(E e)方法
Collection c = new ArrayList();
boolean b1 = c.add("abc");
boolean b2 = c.add(true);
boolean b3 = c.add(100);
boolean b4= c.add(new Student(23,"zs" ));
//add方法如果是List集合一直都返回ture;因为List集合是可以存储重复元素的;
//add方法如果是set集合当存储重复元素的时候,就会返回false;
//ArrayList的爷爷类重写toString方法,所以在打印对象引用的时候,输出的结果不是Object类中的toString结果;
remove(Object o)方法 、 clear()方法 、 contains()方法 、 isEmpty()方法 、size()方法
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.remove("b"); //删除指定元素
System.out.println(c); //输出 : [a, c]
System.out.println(c.contains("b")); // 判断是否包含 输出: true
c.clear(); //清空集合
System.out.println(c); //输出: []
System.out.println(c.isEmpty()); //判断是否为空 空返回 true,非空返回false
System.out.println(c.size()); //判断集合的个数
集合转换成数组
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Object[] array = c.toArray(); //将集合转换成数组
for (int i = 0; i < array.length; i++) { //遍历数组
System.out.println(array[i]);
}
Collection c = new ArrayList();
c.add( new Student(23,"zs")); //相当于 Object obj = new Student();
c.add( new Student(24,"zs")); //自动向上转型,类型提升
c.add( new Student(25,"zs"));
Object[] arr = c.toArray(); //将对象转换成数组,
for(int i=0; i< arr.length; i++){ //遍历
Student s = (Student)arr[i]; //在向下转型 多态的缺点 不能使用子类特有的属性或方法
System.out.println(s.getName()+"--"+s.getAge());
}
Collection 的 add()方法 和 addAll() 方法区别
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c.addAll(c1); // 将c1中的每一个元素添加到c中 输出: [a, b, c, a, b, c]
c.add(c1); //把c1集合看成一个对象 添加到c中 输出: [a, b, c, [a, b, c]]
System.out.println(c);
removeAll()方法 删除的交集 containsAll()方法 判断是否包含传入的集合
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
boolean b = c.removeAll(c1); //从c中删除 c1,删除的交集
boolean b = c.containsAll(c1); //判断是否包含传入的集合
System.out.println(b);
System.out.println(c); //输出 [c]
retainAll()方法 取交集
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
boolean b = c.retainAll(c1); //取交集, 把c1付给c 就看调用的集合是否改变
//取交集, 如果调用的交集改变就返回true , 如果调用的集合没改变就返回false
System.out.println(b); //false
System.out.println(c); //[a, b, c]
集合的迭代器遍历 Iterator
迭代器概述:集合是用来存储元素的,存储元素就需要查看,那么就需要迭代(遍历)
hasNext()方法 //判断是否有元素,如果有就返回true。
next()方法 返回迭代的下一个元素。重复调用此方法直到 hasNext() 方法返回 false
Collection c = new ArrayList();
c.add(new Student(23,"张三"));
c.add(new Student(24,"张三"));
c.add(new Student(25,"张三"));
Iterator it = c.iterator();
while(it.hasNext()){
Student s = (Student)it.next();
System.out.println(s.getName()+"--"+s.getAge());
}
List集合特有的 功能概述
add()方法:
List l = new ArrayList();
l.add("a");
l.add("b");
l.add("c");
l.add(5,"d"); //index = 0,否则会报下标越界异常
System.out.println(l); //输出: IndexOutOfBoundsException
remove()方法
List l = new ArrayList();
l.add(111);
l.add(222);
l.add(333);
l.add(444);
l.remove(111); //删除指的是下标 , 不是指的对象 把111看成了下标 不是对象
System.out.println(l); //IndexOutOfBoundsException 不会自动装箱
get()方法
List l = new ArrayList();
l.add(111);
l.add(222);
l.add(333);
l.add(444);
Object obj = l.get(8); //get(下标) :下标不能大于size,否则报下标越界异常
System.out.println(obj);
for (int i = 0; i < l.size(); i++) {
System.out.println(l.get(i)); // 通过索引获取每一元素
}
set()方法
List l = new ArrayList();
l.add(111);
l.add(222);
l.add(333);
l.add(444);
l.set(1,666);
System.out.println(l); //输出: [111, 666, 333, 444]
ListIterator() 方法的使用
List l = new ArrayList();
l.add("a"); //自动类型提升object
l.add("world"); //相当于 Object obj = new String();
l.add("f");
l.add("b");
/* Iterator it = l.iterator();
while(it.hasNext()){ //判断集合中是否有元素
String str = (String) it.next(); //强制类型转换String
if(str.equals("world")){
l.add("javaee"); //在遍历的同时添加元素,并发修改
}
}
System.out.println(l);//输出:并发修改异常 ConcurrentModificationException*/
listIterator()方法 可以实现在遍历的同时添加元素
ListIterator lit = l.listIterator(); //利用listIterator特有的方法可以实现
while(lit.hasNext()){ //判断集合中是否有元素
String str = (String) lit.next(); //强制类型转换String
if(str.equals("world")){
lit.add("javaee"); //在遍历的同时添加元素,并发修改
}
}
System.out.println(l);//输出:[a, world, javaee, f, b]
集合框架数据结构之数组和链表
List的三个子类的特点: 存储的都是对象的地址值;
ArrayList: 底层数据结构是数组,查询块,修改也快,增删慢。线程不安全,效率高
查询和修改快的原因:底层是数组,直接通过下标找值,所以非常快,数组最大值是 size - 1,
增删慢的原因:在某个位置添加元素,后面的其他所有元素需要向后移动下标,过程比较复杂, 所以
添加 较慢,当删除某个元素的时候,其后面的所有元素需要向前移动下标,所以删除较慢。
图形讲解原理图:
Vector: 底层数据结构是数组,查询块,增删慢,线程安全,效率低。
LinkedList:底层数据结构是链表,查询慢,修改也慢,增删快,线程不安全,效率高
查询和修改慢的原因:底层是链表结构,需要一个一个的去查找(从前向后或者从后向前),率相对较低,
增删快的原因:在某个位置添加元素,直接在两个元素中间断开插入后在两两相互连接即可,所以较快。
删除某个元素即前后连接断开后移除,之后相邻的元素在连接即可。所以较快
图形讲解原理图:
size >> 1 代表除以2, size 的 一次幂; 如图所示
Day16List集合框架
去除ArrayList集合中的重复字符串元素方式
ArrayList l = new ArrayList(); //创建旧集合
l.add("a");
l.add("a");
l.add("b");
l.add("b");
l.add("v");
l.add("v");
ArrayList li = getlist(l); //调用新集合
System.out.println(li);
}
public static ArrayList getlist(ArrayList l){
ArrayList newlist = new ArrayList(); //创建集合
Iterator it = l.iterator(); //根据传入的集合(旧集合)获取迭代器
while(it.hasNext()){ //遍历旧集合
Object obj = it.next(); //记录每一个集合
if(!newlist.contains(obj)){ //判断新集合是否包含旧集合
newlist.add(obj); //向新集合添加元素
}
}
return newlist;
}
contains() 方法: 判断是否包含,底层依赖的是equals方法;
remove() 方法: 判断是否删除,底层依赖的是equals方法
LinkedList() 的特有功能
LinkedList l = new LinkedList(); //dcbaw
l.addFirst("a"); //从第一个位置添加,每次添加都是从第一个位置添加
l.addFirst("b");
l.addFirst("c");
l.addFirst("d");
l.addLast("w"); //从最后一个位置添加,每次添加都是从最后一个位置添加
System.out.println(l); //输出:[d, c, b, a, w]
System.out.println(l.getFirst()); //获取第一个元素 d
System.out.println(l.getLast()); //获取最后一个元素 w
System.out.println(l.removeFirst()); //移除第一个元素 d
System.out.println(l.removeLast()); //移除最后一个元素 w
System.out.println(l);//输出 : [c, b, a]
//dcbaw
System.out.println(l.get(2)); //输出: a
泛型
泛型的概述:
泛型基本使用 :
<>中放的必须是引用数据类型
泛型的好处:
1、提高安全性(将运行期的错误转换到编译期)
2、省去强转的麻烦
泛型什么时候赋值
非静态方法在创建对象的时候,静态方法在调用静态方法的时间赋值
案例:
//不加泛型
ArrayList l = new ArrayList();
l.add(100);
l.add(true);
l.add(new Student(23,"张三"));
Iterator it= l.iterator();
while(it.hasNext()){
Student obj =(Student)it.next(); //向下强制 转型 会报类转换异常 ClassCastException
System.out.println(obj);
}*/
//加泛型
//int[] arra = new int[5]; //数组要保证前后数据类型一致。
ArrayList l = new ArrayList(); //集合的泛型要保证前后的数据类型一致;
// l.add(100); //添加泛型后编译不同过,报错
// l.add(true);
l.add(new Student(23,"张三"));
l.add(new Student(24,"李四"));
Iterator it= l.iterator();
while(it.hasNext()){
Student obj = it.next(); //不用强砖
System.out.println(obj.getName()+"--"+obj.getAge());
// System.out.println(it.next().getName()+"--"+it.next().getAge()); //输出:错误的值 张三--24
// next()方法只能调用一次,如果调用多次会将指针向后移动多次;
}
泛型的基本使用:
泛型使用的注意事项:
//int[] arra = new int[5]; //数组要保证前后数据类型一致。
ArrayListStudent> l = new ArrayListStudent>(); //集合的泛型要保证前后的数据类型一致;
ArrayListObject> ls = new ArrayList<>();//1.7版本新特性,菱形泛型, 泛型最好不要定义成Object,没有意义
向泛型中添加对象 : Person
泛型方法的概述和使用 :
public class ToolQ> {
private Q q;
public Q getQ() {
return q;
}
public void setQ(Q q) {
this.q = q;
}
public void show(Q q){ //Q q在创建对象的时候才有值,即new的过程。
System.out.println(q); //方法泛型最好与类的泛型一致
}
public void show1(T t){ //如果不一致,需要在方法上声明该泛型
System.out.println(t);
}
public static void show2(W w){//q在调用静态方法的时候才会赋值
//因为静态方法时随着类加载而创建,所以静态必须声明自己的泛型
System.out.println(w);
}
泛型接口的概述和使用
interface Inter{ //定义一个接口
public void show(T t);
}
class demo implements Inter{ //实现这个接口
@Override
public void show(String t) {
System.out.println(t);
}
}
泛型高级之通配符:
//* B:? extends E, B是子类、 E是父类 向下限定,E及其子类
public static void main(String[] args) {
List l = new ArrayList();//当左边的泛型是不确定时,左边可以指定为?
增强for循环:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
因为底层是迭代器实现:所以增强for循环不能删除,只能遍历。要是删除会出现 并发修改异常 快捷键输入 fore Art+/
三种遍历方式能否删除
ArrayList list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
普通for循环 当两个元素相邻时,要删除这些元素要通过索引 --来完成
for(int i = 0; i < list.size(); i++) {
if("b".equals(list.get(i))) {
list.remove(i--); //通过list集合的索引删除元素
}
}
//2,迭代器删除
Iterator it = list.iterator();
while(it.hasNext()) {
if("b".equals(it.next())) {
//list.remove("b"); //不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
it.remove();//只能通过迭代器自身的remove方法
}
}
//3,增强for循环,增强for循环不能删除,只能遍历
for (String string : list) {
if("b".equals(string)) {
list.remove("b");
}
}
System.out.println(list);
}
Day17Set集合框架
HashSet hs = new HashSet();
boolean add = hs.add("a"); //不能存储重复元素
boolean add2 = hs.add("a");
System.out.println(hs); //输出:[a]
hs.add("a");
hs.add("b");
hs.add("c"); //是无序的
System.out.println(hs); //输出:[b, c, a]
迭代器遍历
for (String string : hs) {
System.out.println(string); //只要能用迭代器迭代的,就可以使用增强for循环遍历。
}
只有HashCode方法一样的时候才会调用equals方法。
HashCode方法里面的常量为什么是31
/*
* 为什么是31;
* 1.31是质数 。只能被1和本身整除
* 2.31既不大也不小,大了 计算有可能超过int取值范围,小了 重复概率就大了。
* 3.31这个数好计算,2的5次方减1,2向左移动5位
*/
@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;
}
LinkedHashSet()方法 的概述和使用:
底层是链表实现的,是set集合唯一一个能保证怎么存就怎么取的集合对象;
因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样
TreeSet()集合:
TreeSet集合是用来对象元素进行排序的,也可以保证元素唯一的。
TreeSet()集合基本没怎么学,有时间重新学;
day18MAP集合
map集合概述和特点:
map是双列的,coolection是单列的,
map的键是唯一的,Coolection的字体系set是唯一的;
map集合的数据结构值针对有效,跟值无关,Collection集合的数据结构是真对元素有效的
Set的底层依赖的是Map
Map集合的功能类概述:
map底层是Hash算法,不能保证怎么存的怎么取,
Map集合的添加方法put()
Map m = new HashMap<>();
m.put("张三", 23); //map底层是Hash算法,不能保证怎么存的怎么取,
m.put("李四", 24);
m.put("王五", 25);
m.put("王五", 26); //相同的键不存储,值被覆盖。
System.out.println(m);
remove()删除方法
Integer remove = m.remove("张三"); //根据键删除元素,返回对应的值
System.out.println(remove);
containsKey()方法 判断是否包含传入的键
boolean containsKey = m.containsKey("张三");
System.out.println(containsKey); //判断是否包含传入的键
containsValue()方法 判断是否包含传入的值
boolean containsValue = m.containsValue(23);
System.out.println(containsValue); //判断是否包含传入的值
isEmpty()方法 判断是否包为空
boolean empty = m.isEmpty();
System.out.println(empty); //判断是否包为空。是空返回true,非空返回false
values()方法获取集合的所有值
Collection values = m.values();
System.out.println(values); // values()方法获取集合的所有值
System.out.println(m.size()); //返回集合中的键值对的个数
map集合是不能直接迭代的, map集合的遍历
Map m = new HashMap<>();
m.put("张三", 23);
m.put("李四", 24);
m.put("王五", 25);
m.put("周六", 26);
//用迭代器遍历
Set keySet = m.keySet(); //获取所有的键 把键存储到set集合中
Iterator it = keySet.iterator(); //获取迭代器
while(it.hasNext()){ //判断集合中是否有元素
String key = it.next(); //获取每一个键
Integer integer = m.get(key); //根据键获取值
System.out.println(integer);
}
//通增强for遍历
for (String key : m.keySet()) { //m.keySet()是所有键的集合
Integer value = m.get(key); //根据键获取值
System.out.println(key+"=="+value);
}
map集合的第二种遍历方式; 根据键值对的对象 获取键和值
Map map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("周六", 26);
迭代器遍历
//Map.Entry(K,V); Entry是Map接口里面的子接口 ,
//将键和值封装成Entry对象,(类似于Person对象),并存储在Set集合中
Set> entrySet = map.entrySet(); //将键和值封装成对象
Iterator> it = entrySet.iterator(); //获取迭代器,获取每一个对象
while(it.hasNext()){ //判断集合中是否有对象
// Map.Entry next1 = it.next(); //记录每一对象, 父类引用指向子类对象
Entry next = it.next(); //记录每一对象, 直接获取的是子类对象
//Entry 继承并重写了 Map.Entry,
String key = next.getKey(); //获取键
Integer value = next.getValue(); //获取值
System.out.println(key+"==="+value);
}
增强For循环遍历
for(Map.Entry ma : map.entrySet() ){
System.out.println(ma.getKey()+"==="+ma.getValue());
}
练习: 案例演示
* 需求:统计字符串中每个字符出现的次数
String str = "aaaabbbcccccccccc";
char[] arr = str.toCharArray(); //将字符串转换成字符数组
HashMap hm = new HashMap<>(); //创建双列集合存储键和值
for(char c : arr) { //遍历字符数组
/*if(!hm.containsKey(c)) { //如果不包含这个键
hm.put(c, 1); //就将键和值为1添加
}else { //如果包含这个键
hm.put(c, hm.get(c) + 1); //就将键和值再加1添加进来
}*/
hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1); //使用三元运算符,简单
}
for (Character key : hm.keySet()) { //遍历双列集合
System.out.println(key + "=" + hm.get(key));
}
HashMap 和 HashTable 的区别
共同点: 底层都是哈希算法,都是双列集合;
区别: 1、HashMap是线程不安全的,效率高;Hashtable是线程安全的,效率低
2、HashMap可以有空键空值;hashtable不可以存储空键和空值。
集合框架 Collections工具类;
Collections成员方法
public static void sort(List list) //排序
public static int binarySearch(List list,T key) //二叉法
public static T max(Collection coll) //先默认排序,再获取最大值
public static void reverse(List list) //反转输出
public static void shuffle(List list) //随机置换,可以用来洗洗牌。
代码如下:
Day15集合值框架
数组:部分集合的底层是用数组写的;
基本数据类型存储的是值,
引用数据类型 中存储的不是对象,是对象的地址值。
数组与集合的区别:
1. 数组 可以存储基本数据类型,也可以存储引用数据类型,基本数据类型存储值,引用数据类型存储地址值。
集合只能存储引用数据类型(对象)。集合中也可以存储基本数据类型,但是在存储的时候会自动装箱成对象。
2. 数组的长度是固定的,不能自动增长;
集合的长度是可变的。可以随着元素的增加而增长;
什么情况下使用数组或者集合:
如果元素的个数是固定的使用数组(效率高);
如果元素的个数是变化的使用集合。
Collection(单列集合的跟接口)
List集合: 有序(存和取是有序的),有序列,可以存储重复元素
1. ArrayList 集合:数组实现。 查询块,修改也快,增删慢
2. LinkedList集合:链表实现。查询慢,修改也慢,增删快
Set集合:无序(存和取是无序的) ,无序列,不能存储重复元素。
1. HashSet集合:哈希算法,
2. TreeSet集合:二叉树算法,
Collection集合
add(E e)方法
Collection c = new ArrayList();
boolean b1 = c.add("abc");
boolean b2 = c.add(true);
boolean b3 = c.add(100);
boolean b4= c.add(new Student(23,"zs" ));
//add方法如果是List集合一直都返回ture;因为List集合是可以存储重复元素的;
//add方法如果是set集合当存储重复元素的时候,就会返回false;
//ArrayList的爷爷类重写toString方法,所以在打印对象引用的时候,输出的结果不是Object类中的toString结果;
remove(Object o)方法 、 clear()方法 、 contains()方法 、 isEmpty()方法 、size()方法
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.remove("b"); //删除指定元素
System.out.println(c); //输出 : [a, c]
System.out.println(c.contains("b")); // 判断是否包含 输出: true
c.clear(); //清空集合
System.out.println(c); //输出: []
System.out.println(c.isEmpty()); //判断是否为空 空返回 true,非空返回false
System.out.println(c.size()); //判断集合的个数
集合转换成数组
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Object[] array = c.toArray(); //将集合转换成数组
for (int i = 0; i < array.length; i++) { //遍历数组
System.out.println(array[i]);
}
Collection c = new ArrayList();
c.add( new Student(23,"zs")); //相当于 Object obj = new Student();
c.add( new Student(24,"zs")); //自动向上转型,类型提升
c.add( new Student(25,"zs"));
Object[] arr = c.toArray(); //将对象转换成数组,
for(int i=0; i< arr.length; i++){ //遍历
Student s = (Student)arr[i]; //在向下转型 多态的缺点 不能使用子类特有的属性或方法
System.out.println(s.getName()+"--"+s.getAge());
}
Collection 的 add()方法 和 addAll() 方法区别
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c.addAll(c1); // 将c1中的每一个元素添加到c中 输出: [a, b, c, a, b, c]
c.add(c1); //把c1集合看成一个对象 添加到c中 输出: [a, b, c, [a, b, c]]
System.out.println(c);
removeAll()方法 删除的交集 containsAll()方法 判断是否包含传入的集合
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
boolean b = c.removeAll(c1); //从c中删除 c1,删除的交集
boolean b = c.containsAll(c1); //判断是否包含传入的集合
System.out.println(b);
System.out.println(c); //输出 [c]
retainAll()方法 取交集
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
boolean b = c.retainAll(c1); //取交集, 把c1付给c 就看调用的集合是否改变
//取交集, 如果调用的交集改变就返回true , 如果调用的集合没改变就返回false
System.out.println(b); //false
System.out.println(c); //[a, b, c]
集合的迭代器遍历 Iterator
迭代器概述:集合是用来存储元素的,存储元素就需要查看,那么就需要迭代(遍历)
hasNext()方法 //判断是否有元素,如果有就返回true。
next()方法 返回迭代的下一个元素。重复调用此方法直到 hasNext() 方法返回 false
Collection c = new ArrayList();
c.add(new Student(23,"张三"));
c.add(new Student(24,"张三"));
c.add(new Student(25,"张三"));
Iterator it = c.iterator();
while(it.hasNext()){
Student s = (Student)it.next();
System.out.println(s.getName()+"--"+s.getAge());
}
List集合特有的 功能概述
add()方法:
List l = new ArrayList();
l.add("a");
l.add("b");
l.add("c");
l.add(5,"d"); //index <= size && index >= 0,否则会报下标越界异常
System.out.println(l); //输出: IndexOutOfBoundsException
remove()方法
List l = new ArrayList();
l.add(111);
l.add(222);
l.add(333);
l.add(444);
l.remove(111); //删除指的是下标 , 不是指的对象 把111看成了下标 不是对象
System.out.println(l); //IndexOutOfBoundsException 不会自动装箱
get()方法
List l = new ArrayList();
l.add(111);
l.add(222);
l.add(333);
l.add(444);
Object obj = l.get(8); //get(下标) :下标不能大于size,否则报下标越界异常
System.out.println(obj);
for (int i = 0; i < l.size(); i++) {
System.out.println(l.get(i)); // 通过索引获取每一元素
}
set()方法
List l = new ArrayList();
l.add(111);
l.add(222);
l.add(333);
l.add(444);
l.set(1,666);
System.out.println(l); //输出: [111, 666, 333, 444]
ListIterator() 方法的使用
List l = new ArrayList();
l.add("a"); //自动类型提升object
l.add("world"); //相当于 Object obj = new String();
l.add("f");
l.add("b");
/* Iterator it = l.iterator();
while(it.hasNext()){ //判断集合中是否有元素
String str = (String) it.next(); //强制类型转换String
if(str.equals("world")){
l.add("javaee"); //在遍历的同时添加元素,并发修改
}
}
System.out.println(l);//输出:并发修改异常 ConcurrentModificationException*/
listIterator()方法 可以实现在遍历的同时添加元素
ListIterator lit = l.listIterator(); //利用listIterator特有的方法可以实现
while(lit.hasNext()){ //判断集合中是否有元素
String str = (String) lit.next(); //强制类型转换String
if(str.equals("world")){
lit.add("javaee"); //在遍历的同时添加元素,并发修改
}
}
System.out.println(l);//输出:[a, world, javaee, f, b]
集合框架数据结构之数组和链表
List的三个子类的特点: 存储的都是对象的地址值;
ArrayList: 底层数据结构是数组,查询块,修改也快,增删慢。线程不安全,效率高
查询和修改快的原因:底层是数组,直接通过下标找值,所以非常快,数组最大值是 size - 1,
增删慢的原因:在某个位置添加元素,后面的其他所有元素需要向后移动下标,过程比较复杂, 所以
添加 较慢,当删除某个元素的时候,其后面的所有元素需要向前移动下标,所以删除较慢。
图形讲解原理图:
Vector: 底层数据结构是数组,查询块,增删慢,线程安全,效率低。
LinkedList:底层数据结构是链表,查询慢,修改也慢,增删快,线程不安全,效率高
查询和修改慢的原因:底层是链表结构,需要一个一个的去查找(从前向后或者从后向前),率相对较低,
增删快的原因:在某个位置添加元素,直接在两个元素中间断开插入后在两两相互连接即可,所以较快。
删除某个元素即前后连接断开后移除,之后相邻的元素在连接即可。所以较快
图形讲解原理图:
size >> 1 代表除以2, size 的 一次幂; 如图所示
Day16List集合框架
去除ArrayList集合中的重复字符串元素方式
ArrayList l = new ArrayList(); //创建旧集合
l.add("a");
l.add("a");
l.add("b");
l.add("b");
l.add("v");
l.add("v");
ArrayList li = getlist(l); //调用新集合
System.out.println(li);
}
public static ArrayList getlist(ArrayList l){
ArrayList newlist = new ArrayList(); //创建集合
Iterator it = l.iterator(); //根据传入的集合(旧集合)获取迭代器
while(it.hasNext()){ //遍历旧集合
Object obj = it.next(); //记录每一个集合
if(!newlist.contains(obj)){ //判断新集合是否包含旧集合
newlist.add(obj); //向新集合添加元素
}
}
return newlist;
}
contains() 方法: 判断是否包含,底层依赖的是equals方法;
remove() 方法: 判断是否删除,底层依赖的是equals方法
LinkedList() 的特有功能
LinkedList l = new LinkedList(); //dcbaw
l.addFirst("a"); //从第一个位置添加,每次添加都是从第一个位置添加
l.addFirst("b");
l.addFirst("c");
l.addFirst("d");
l.addLast("w"); //从最后一个位置添加,每次添加都是从最后一个位置添加
System.out.println(l); //输出:[d, c, b, a, w]
System.out.println(l.getFirst()); //获取第一个元素 d
System.out.println(l.getLast()); //获取最后一个元素 w
System.out.println(l.removeFirst()); //移除第一个元素 d
System.out.println(l.removeLast()); //移除最后一个元素 w
System.out.println(l);//输出 : [c, b, a]
//dcbaw
System.out.println(l.get(2)); //输出: a
泛型
泛型的概述:
泛型基本使用 :
<>中放的必须是引用数据类型
泛型的好处:
1、提高安全性(将运行期的错误转换到编译期)
2、省去强转的麻烦
泛型什么时候赋值
非静态方法在创建对象的时候,静态方法在调用静态方法的时间赋值
案例:
//不加泛型
ArrayList l = new ArrayList();
l.add(100);
l.add(true);
l.add(new Student(23,"张三"));
Iterator it= l.iterator();
while(it.hasNext()){
Student obj =(Student)it.next(); //向下强制 转型 会报类转换异常 ClassCastException
System.out.println(obj);
}*/
//加泛型
//int[] arra = new int[5]; //数组要保证前后数据类型一致。
ArrayList<Student> l = new ArrayList<Student>(); //集合的泛型要保证前后的数据类型一致;
// l.add(100); //添加泛型后编译不同过,报错
// l.add(true);
l.add(new Student(23,"张三"));
l.add(new Student(24,"李四"));
Iterator<Student> it= l.iterator();
while(it.hasNext()){
Student obj = it.next(); //不用强砖
System.out.println(obj.getName()+"--"+obj.getAge());
// System.out.println(it.next().getName()+"--"+it.next().getAge()); //输出:错误的值 张三--24
// next()方法只能调用一次,如果调用多次会将指针向后移动多次;
}
泛型的基本使用:
泛型使用的注意事项:
//int[] arra = new int[5]; //数组要保证前后数据类型一致。
ArrayList<Student> l = new ArrayList<Student>(); //集合的泛型要保证前后的数据类型一致;
ArrayList<Object> ls = new ArrayList<>();//1.7版本新特性,菱形泛型, 泛型最好不要定义成Object,没有意义
向泛型中添加对象 : Person
泛型方法的概述和使用 :
public class Tool<Q> {
private Q q;
public Q getQ() {
return q;
}
public void setQ(Q q) {
this.q = q;
}
public void show(Q q){ //Q q在创建对象的时候才有值,即new的过程。
System.out.println(q); //方法泛型最好与类的泛型一致
}
public <T> void show1(T t){ //如果不一致,需要在方法上声明该泛型
System.out.println(t);
}
public static <W> void show2(W w){//q在调用静态方法的时候才会赋值
//因为静态方法时随着类加载而创建,所以静态必须声明自己的泛型
System.out.println(w);
}
泛型接口的概述和使用
interface Inter<T>{ //定义一个接口
public void show(T t);
}
class demo implements Inter<String>{ //实现这个接口
@Override
public void show(String t) {
System.out.println(t);
}
}
泛型高级之通配符:
//* B:? extends E, B是子类、 E是父类 向下限定,E及其子类
public static void main(String[] args) {
List<?> l = new ArrayList<String>();//当左边的泛型是不确定时,左边可以指定为?
增强for循环:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
因为底层是迭代器实现:所以增强for循环不能删除,只能遍历。要是删除会出现 并发修改异常 快捷键输入 fore Art+/
三种遍历方式能否删除
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
普通for循环 当两个元素相邻时,要删除这些元素要通过索引 --来完成
for(int i = 0; i < list.size(); i++) {
if("b".equals(list.get(i))) {
list.remove(i--); //通过list集合的索引删除元素
}
}
//2,迭代器删除
Iterator<String> it = list.iterator();
while(it.hasNext()) {
if("b".equals(it.next())) {
//list.remove("b"); //不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
it.remove();//只能通过迭代器自身的remove方法
}
}
//3,增强for循环,增强for循环不能删除,只能遍历
for (String string : list) {
if("b".equals(string)) {
list.remove("b");
}
}
System.out.println(list);
}
Day17Set集合框架
HashSet<String> hs = new HashSet<String>();
boolean add = hs.add("a"); //不能存储重复元素
boolean add2 = hs.add("a");
System.out.println(hs); //输出:[a]
hs.add("a");
hs.add("b");
hs.add("c"); //是无序的
System.out.println(hs); //输出:[b, c, a]
迭代器遍历
for (String string : hs) {
System.out.println(string); //只要能用迭代器迭代的,就可以使用增强for循环遍历。
}
只有HashCode方法一样的时候才会调用equals方法。
HashCode方法里面的常量为什么是31
/*
* 为什么是31;
* 1.31是质数 。只能被1和本身整除
* 2.31既不大也不小,大了 计算有可能超过int取值范围,小了 重复概率就大了。
* 3.31这个数好计算,2的5次方减1,2向左移动5位
*/
@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;
}
LinkedHashSet()方法 的概述和使用:
底层是链表实现的,是set集合唯一一个能保证怎么存就怎么取的集合对象;
因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样
TreeSet()集合:
TreeSet集合是用来对象元素进行排序的,也可以保证元素唯一的。
TreeSet()集合基本没怎么学,有时间重新学;
day18MAP集合
map集合概述和特点:
map是双列的,coolection是单列的,
map的键是唯一的,Coolection的字体系set是唯一的;
map集合的数据结构值针对有效,跟值无关,Collection集合的数据结构是真对元素有效的
Set的底层依赖的是Map
Map集合的功能类概述:
map底层是Hash算法,不能保证怎么存的怎么取,
Map集合的添加方法put()
Map<String,Integer> m = new HashMap<>();
m.put("张三", 23); //map底层是Hash算法,不能保证怎么存的怎么取,
m.put("李四", 24);
m.put("王五", 25);
m.put("王五", 26); //相同的键不存储,值被覆盖。
System.out.println(m);
remove()删除方法
Integer remove = m.remove("张三"); //根据键删除元素,返回对应的值
System.out.println(remove);
containsKey()方法 判断是否包含传入的键
boolean containsKey = m.containsKey("张三");
System.out.println(containsKey); //判断是否包含传入的键
containsValue()方法 判断是否包含传入的值
boolean containsValue = m.containsValue(23);
System.out.println(containsValue); //判断是否包含传入的值
isEmpty()方法 判断是否包为空
boolean empty = m.isEmpty();
System.out.println(empty); //判断是否包为空。是空返回true,非空返回false
values()方法获取集合的所有值
Collection<Integer> values = m.values();
System.out.println(values); // values()方法获取集合的所有值
System.out.println(m.size()); //返回集合中的键值对的个数
map集合是不能直接迭代的, map集合的遍历
Map<String,Integer> m = new HashMap<>();
m.put("张三", 23);
m.put("李四", 24);
m.put("王五", 25);
m.put("周六", 26);
//用迭代器遍历
Set<String> keySet = m.keySet(); //获取所有的键 把键存储到set集合中
Iterator<String> it = keySet.iterator(); //获取迭代器
while(it.hasNext()){ //判断集合中是否有元素
String key = it.next(); //获取每一个键
Integer integer = m.get(key); //根据键获取值
System.out.println(integer);
}
//通增强for遍历
for (String key : m.keySet()) { //m.keySet()是所有键的集合
Integer value = m.get(key); //根据键获取值
System.out.println(key+"=="+value);
}
map集合的第二种遍历方式; 根据键值对的对象 获取键和值
Map<String,Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("周六", 26);
迭代器遍历
//Map.Entry(K,V); Entry是Map接口里面的子接口 ,
//将键和值封装成Entry对象,(类似于Person对象),并存储在Set集合中
Set<Map.Entry<String,Integer>> entrySet = map.entrySet(); //将键和值封装成对象
Iterator<Map.Entry<String,Integer>> it = entrySet.iterator(); //获取迭代器,获取每一个对象
while(it.hasNext()){ //判断集合中是否有对象
// Map.Entry<String, Integer> next1 = it.next(); //记录每一对象, 父类引用指向子类对象
Entry<String, Integer> next = it.next(); //记录每一对象, 直接获取的是子类对象
//Entry<String, Integer> 继承并重写了 Map.Entry<String, Integer>,
String key = next.getKey(); //获取键
Integer value = next.getValue(); //获取值
System.out.println(key+"==="+value);
}
增强For循环遍历
for(Map.Entry<String,Integer> ma : map.entrySet() ){
System.out.println(ma.getKey()+"==="+ma.getValue());
}
练习: 案例演示
* 需求:统计字符串中每个字符出现的次数
String str = "aaaabbbcccccccccc";
char[] arr = str.toCharArray(); //将字符串转换成字符数组
HashMap<Character, Integer> hm = new HashMap<>(); //创建双列集合存储键和值
for(char c : arr) { //遍历字符数组
/*if(!hm.containsKey(c)) { //如果不包含这个键
hm.put(c, 1); //就将键和值为1添加
}else { //如果包含这个键
hm.put(c, hm.get(c) + 1); //就将键和值再加1添加进来
}*/
hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1); //使用三元运算符,简单
}
for (Character key : hm.keySet()) { //遍历双列集合
System.out.println(key + "=" + hm.get(key));
}
HashMap 和 HashTable 的区别
共同点: 底层都是哈希算法,都是双列集合;
区别: 1、HashMap是线程不安全的,效率高;Hashtable是线程安全的,效率低
2、HashMap可以有空键空值;hashtable不可以存储空键和空值。
集合框架 Collections工具类;
Collections成员方法
public static <T> void sort(List<T> list) //排序
public static <T> int binarySearch(List<?> list,T key) //二叉法
public static <T> T max(Collection<?> coll) //先默认排序,再获取最大值
public static void reverse(List<?> list) //反转输出
public static void shuffle(List<?> list) //随机置换,可以用来洗洗牌。