集合
-
什么是集合?
一种引用数据类型,可以存储多个数据
-
为什么要学习集合?
数组的缺点:
(1)空间长度不可以改变。
(2)没办法获得数组中真实的元素个数。
(3)增加,删除 操作复杂 。
(4)不能去重;数组没有做功能的封装
------------不同点
(1)可以存储基本数据类型,也可以存储引用数据类型
(2)只能存储相同数据类型
(3)数组肯定有下标
集合的好处:
(1)空间长度可以改变
(2)有一个属性可以获得真实的元素个数
(3)增,删,改,查 操作都很方便
(1)又去重功能,有排序功能,有方法的封装。。。
----------不同点
(1)只能存储应用数据类型
(2)可以存储多种类型,但不推荐使用
(3)有的集合类型有下标,有的集合类型没有下标
一,“两个图” 集合的分类
-
一个一个存储的(大爷家)
有序---》下标有序---存和取的顺序一致
Collection( 无序的,可重复)
List(有序,可重复) Set(无序,去重)
ArrayList Vector LinkedList TreeSet(有序,去重) HashSet(无序,去重)
-
一对一对存储的(二大爷家)
Map (key 无序,不可重复 - value 无序,可以重复)
TreeMap HashMap
二,七个接口
-
Collection (无序,可重复)
单列集合的祖宗接口,它的功能全部单列集合都可以继承
实现类---ArrayList
-
增加:add(); addAll();
Collection collection = new ArrayList();collection.add("123");Collection collection1 = new ArrayList();collection1.addAll(collection); //将另一个集合添加进来
-
删除:clear(); removeAll(); remove();
collection1.clear();//清空Collection collection = new ArrayList(); collection.add("1238"); collection.add("195647"); collection.remove("1238");//删除元素 System.out.println(collection);
-
修改:
-
查询:size();
Collection collection = new ArrayList(); System.out.println(collection.size());//获得真实的元素个数
-
判断:isEmpty(); contains(); containsAll();
collection1 = new ArrayList(); System.out.println("isEmpty:" + collection1.isEmpty());//没有元素 System.out.println("判断1123是否存在:" + collection1.contains(1234));
-
遍历:iterator(){迭代器}----
专门用来循环遍历Collection集合类型的
6.单列集合和数组可以用增强for来遍历
Iterator iterator = collection1.iterator(); //Iterator 迭代器: 用于循环遍历集合while(iterator.hasNext()){//判断有没有下一个元素System.out.println(iterator.next());//如果有:获得下一个元素}//循环遍历 for (Object obj : collection1) {System.out.println(obj);}System.out.println("===========================");
7.转换:toArray() (转换--将集合转换成数组)
Collection collection = new ArrayList();System.out.println(collection.toArray());
-
List(有序,可重复)
-
增加:add(2,"张三");add(2,list);
List list = new LinkedList();list.add(0, "张三");list.add("李四");list.add(2, "张三");
-
删除:list.remove(0)(会返回被删除的元素);
list.remove(0);//删除下标为0的元素
-
修改:list.set(0,"往五");
list.set(0, "王五");//下标0的元素改成王五
-
查询:lastIndexOf("李四");indexOf("李四");list.get(0)
System.out.println(list.lastIndexOf("李四"));// 查找 从后往前list.indexOf("李四");//查找 从前往后System.out.println(list.get(0));//查照下标为0的元素是什么
-
截取:subList(1,3);
List list = new LinkedList();list.add(0, "张三");list.add("李四");list.add(2, "张三");System.out.println(list.subList(1, 3));//截取下标[1,3)的元素
-
排序:list.sort(); 元素内容排序
LIst 遍历(三种)
//遍历 list 1Iterator<StuEntry> iterator = list.iterator();while (iterator.hasNext()) {StuEntry next = iterator.next();System.out.println(next);} ================================================================//遍历list 2for (StuEntry stuEntry : list) {System.out.println(stuEntry);}================================================================//遍历list 3for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}
-
LinkedList (双向链表)()
-
增加 addFirst(E e) addLast(E e) offer(E e) offerFirst(E e) offerLast(E e)
LinkedList<String> list = new LinkedList<>();list.add("fffff");list.addFirst("jj");//添加元素在开头list.addLast("hh");//添加元素在尾端list.offer("kk");//添加元素在尾端list.offerFirst("pp");//添加元素在开头list.offerLast("rr");//添加元素在尾端System.out.println(list);//LinkedList可以添加重复数据
-
删除 poll() pollFirst() pollLast() ---》JDK1.6以后新出的方法,提高了代码的健壮性 removeFirst() removeLast()
LinkedList<String> list = new LinkedList<>();list.add("fffff");list.addFirst("jj");//添加元素在开头list.addLast("hh");//添加元素在尾端list.offer("kk");//添加元素在尾端list.offerFirst("pp");//添加元素在开头list.offerLast("rr");//添加元素在尾端System.out.println(list);//LinkedList可以添加重复数据System.out.println(list.poll());//删除头上的元素并且将元素输出System.out.println(list.pollFirst());//删除头上的元素并将元素输出System.out.println(list.pollLast());//删除尾端的元素并将元素输出System.out.println(list.removeFirst());//删除头上的元素并将元素输出System.out.println(list.removeLast());//删除尾端的元素并将元素输出System.out.println(list);//LinkedList可以添加重复数据
-
修改
-
查询 element() getFirst() getLast() peek() peekFirst() peekLast()
LinkedList<String> list = new LinkedList<>();list.add("fffff");list.addFirst("jj");//添加元素在开头list.addLast("hh");//添加元素在尾端list.offer("kk");//添加元素在尾端list.offerFirst("pp");//添加元素在开头list.offerLast("rr");//添加元素在尾端System.out.println(list);//LinkedList可以添加重复数据System.out.println(list.element());//查询第一个元素System.out.println(list.getFirst());//查询第一个元素System.out.println(list.getLast());//查询尾端的元素System.out.println(list.peek());//查询第一个元素System.out.println(list.peekFirst());//查询第一个元素System.out.println(list.peekLast());//查询尾端的元素
-
判断
-
简要底部原理图
-
Vector
Vector和ArrayList的区别和联系
实现原理相同,功能相同,都是长度可变的数组结构,很多情况下可以互用
两者的主要区别如下
- Vector是早期JDK接口,ArrayList是替代Vector的新接口
- Vector线程安全,ArrayList重速度轻安全,线程非安全
- 长度需增长时,Vector默认增长一倍,ArrayList增长50%
-
Set(无序,不可重复)
Set 遍历 (两种)
//遍历 Set 1Iterator<Book> iterator = set1.iterator();while (iterator.hasNext()){Book next = iterator.next();System.out.println(next);} ============================================================//遍历 Set 2for (Book book : set1) {System.out.println(book);}
-
TreeSet()(无序,不重复) ------ Comparable Comparator
排序和去重原理:借助比较器接口,重写比较方法
比较器接口:(1)内部比较器 Comparable (在Book类中进行方法重写)
public class Book implements Comparable<Book> @Overridepublic int compareTo(Book o) {//compare 能比较,能去重/* if (this.price > o.price){return 1;} else if (this.price==o.price) {return 0;}else {return -1;}*/if (!this.id.equals(o.getId())){return this.price.compareTo(o.getPrice());}else {return 0;//代表重复,不能存储}
(2)外部比较器 Comparator 更灵活,推荐使用 (创建了一个新的类,重写方法,作为外部比较器)
1.新增比较策略的时候,不用改原码
public class BookCompoter implements Comparator<Book> {@Overridepublic int compare(Book o1, Book o2) {if (o1.getId().equals(o2.getId())){return 0;}else {return o1.getPrice().compareTo(o2.getPrice());}}
TreeSet<Book>setbooks = new TreeSet<>(new BookCompoter());
setbooks.add(new Book("001", "西游记",32.4 , "清华出版社"));
setbooks.add(new Book("002", "红楼梦", 52.5, "清华出版社"));
setbooks.add(new Book("003", "三国演义", 72.2, "清华出版社"));
setbooks.add(new Book("004", "水浒传", 62.4, "清华出版社"));
System.out.println(setbooks);
System.out.println(setbooks.size());
-
HashSet(无序,不重复)
存储无序,不重复的数据。
1.去重原理:重写Object类中的HashCode()+equals()
因为Object类中的equals() 比较地址;HashCode()根据内存地址获得哈希值;
现在我们需要equals() 比较 属性值;HashCode()根据属性值获得哈希值;
2.简要原理图
@Overridepublic boolean equals(Object o) {/* if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Book book = (Book) o;return Objects.equals(id, book.id) && Objects.equals(name, book.name) && Objects.equals(price, book.price) && Objects.equals(publisher, book.publisher);*/if(this==o){return true;}if(!(o instanceof Book)){return false;}Book book=(Book) o;if(this.getId().equals(book.getId()) &&this.getPrice().equals(book.getPrice()) &&this.getPublisher().equals(book.getPublisher()) &&this.getName().equals(book.getName())){return true;}else{return false;}}@Overridepublic int hashCode() {return (int)(this.getId().hashCode()+this.getName().hashCode()+this.getPublisher().hashCode()+this.getPrice());}
HashSet<String> set=new HashSet<>();
set.add("张三");HashSet<Book> set1=new HashSet<>();
set1.add(new Book("001", "西游记",32.4 , "清华出版社"));
set1.add(new Book("002", "红楼梦", 52.5, "清华出版社"));
set1.add(new Book("003", "三国演义", 72.2, "清华出版社"));
set1.add(new Book("004", "水浒传", 62.4, "清华出版社"));
System.out.println(set1.size()+";"+set1);
}
-
Map:一对一对存储数据
原因:
- 把常用到的,能唯一代表当前对象的属性,单独存放,就是key(无序,唯一);
- 把不常用到的,大而全的对象属性,存放在value(无序,可重复的)里。
- ---绝大部分情况下,直接使用key就可以;极少部分需要通过key获得value,来解决问题。
1.遍历
public static void main(String[] args) {Map<String, Book> map = new TreeMap<>();Book b1 = new Book("124", "红楼梦", 52.1, "吉林出版社");Book b2 = new Book("123", "西游记", 52.1, "吉林出版社");Book b3 = new Book("125", "水浒传", 52.1, "吉林出版社");map.put(b1.getId(), b1);//添加元素map.put(b2.getId(), b2);map.put(b3.getId(), b3);/* map.get("123");//取出元素 根据key去拿valuemap.size();//个数查询map.remove("125");//删除元素 根据key去删除valuemap.containsKey("125");//判断key是否存在map.replace("123",b3);//替换 根据key去替换value*///循环遍历Map//方式一System.out.println("遍历集合Map,方式一");Collection<Book> values = map.values();for (Book boo :values) {System.out.println(boo);}//方式二System.out.println("遍历集合Map,方式二");Iterator<Book> iterator = map.values().iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}//方式三System.out.println("遍历集合Map,方式三");Set<String> strings = map.keySet();for (String k:strings) {System.out.println(map.get(k));}//方式四System.out.println("遍历集合Map,方式四");Iterator<String> iterator1 = map.keySet().iterator();while (iterator.hasNext()) {Book boo=map.get(iterator1.next());System.out.println(boo);}//方式五System.out.println("遍历集合Map,方式五");Set<Map.Entry<String, Book>> entries = map.entrySet();Iterator<Map.Entry<String, Book>> iterator2 = entries.iterator();while (iterator2.hasNext()){Map.Entry<String, Book> next = iterator2.next();System.out.println(next.getValue());}//方式六System.out.println("遍历集合Map,方式六");Set<Map.Entry<String, Book>> entries1 = map.entrySet();for (Map.Entry<String,Book> entry:entries1){System.out.println(entry.getValue());}}
2.部分结构图
-
HashMap(无序,去重)
-
TreeMap(有序,去重)
-
泛型集合
Collection<Integer> collection = new ArrayList<>();
---泛型集合 只作用在编译期,运行期没有泛型集合!
---反射可以验证:反射在运行期起作用!
---Collection<E>, List<E>, ArrayList<E> 这个<E>就是类型参数,即泛型。
1.泛型类和泛型接口
(1)泛型的实例化
//运行
class Test{//这是main方法,程序的入口public static void main(String[] args) {//GenericTest进行实例化://(1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型GenericTest gt1 = new GenericTest();gt1.a("abc");gt1.a(17);gt1.a(9.8);gt1.b(new String[]{"a","b","c"});//(2)实例化的时候指定泛型:---》推荐方式GenericTest<String> gt2 = new GenericTest<>();gt2.sex = "男";gt2.a("abc");gt2.b(new String[]{"a","b","c"});}
}
=========================================================
//准备
package com.msb.test02;
/*** @author : msb-zhaoss* GenericTes就是一个普通的类* GenericTest<E> 就是一个泛型类* <>里面就是一个参数类型,但是这个类型是什么呢?这个类型现在是不确定的,相当于一个占位* 但是现在确定的是这个类型一定是一个引用数据类型,而不是基本数据类型*/
public class GenericTest<E> {int age;String name;E sex;public void a(E n){}public void b(E[] m){}
}
(2)继承情况
a.父类指定泛型:
class SubGenericTest extends GenericTest<Integer>{}class Demo{//这是main方法,程序的入口public static void main(String[] args) {//指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用SubGenericTest sgt = new SubGenericTest();sgt.a(19);}
}
b.父类不指定泛型:
如果父类不指定泛型,那么子类也会变成一个泛型类,那这个E的类型可以在创建子类对象的时候确定。
class SubGenericTest2<E> extends GenericTest<E>{}class Demo2{//这是main方法,程序的入口public static void main(String[] args) {SubGenericTest2<String> s = new SubGenericTest2<>();s.a("abc");s.sex = "女";}
}
(3)应用场合
(4)细节
a.泛型类可以定义多个参数类型
b.泛型类的构造器的写法
c.不同的泛型的引用类型不可以相互赋值
d.泛型如果不指定,那么就会被擦除,反应对应的类型为Object类型
e.反省类中的静态方法不能使用类的泛型
f.不能直接使用E[]的创建
2.泛型方法
package com.jr.test04;/*** @author : jr-mayang* 1.什么是泛型方法:* 不是带泛型的方法就是泛型方法* 泛型方法有要求:这个方法的泛型的参数类型要和当前的类的泛型无关* 换个角度:* 泛型方法对应的那个泛型参数类型 和 当前所在的这个类 是否是泛型类,泛型是啥 无关* 2.泛型方法定义的时候,前面要加上<T>* 原因:如果不加的话,会把T当做一种数据类型,然而代码中没有T类型那么就会报错* 3.T的类型是在调用方法的时候确定的* 4.泛型方法可否是静态方法?可以是静态方法*/public class TestGeneric<E> {//不是泛型方法 (不能是静态方法)public static void a(E e){}//是泛型方法public static <T> void b(T t){}}
==================================================================
class Demo{//这是main方法,程序的入口public static void main(String[] args) {TestGeneric<String> tg = new TestGeneric<>();tg.a("abc");tg.b("abc");tg.b(19);tg.b(true);}
}
3. 泛型参数存在继承关系的情况
4.通配符
(1)没有通配符时
//下面的a方法,相当于方法的重复定义,报错
public class Test {/*public void a(List<Object> list){}public void a(List<String> list){}public void a(List<Integer> list){}*/
}
(2)引入通配符
public class Demo {//这是main方法,程序的入口public static void main(String[] args) {List<Object> list1 = new ArrayList<>();List<String> list2 = new ArrayList<>();List<Integer> list3 = new ArrayList<>();List<?> list = null;list = list1;list = list2;list = list3;}
}
-----发现: A 和 B是子类父类的关系,G<A>和G<B>不存在子类父类关系,是并列的
加入通配符?后,G<?>就变成了 G<A>和G<B>的父类
(2)使用通配符
public class Test {/*public void a(List<Object> list){}public void a(List<String> list){}public void a(List<Integer> list){}*/public void a(List<?> list){//内部遍历的时候用Object即可,不用?for(Object a:list){System.out.println(a);}}
}
==============================================================class T{//这是main方法,程序的入口public static void main(String[] args) {Test t = new Test();t.a(new ArrayList<Integer>());t.a(new ArrayList<String>());t.a(new ArrayList<Object>());
细节:
public class Test {public void a(List<?> list){//1.遍历:for(Object a:list){System.out.println(a);}//2.数据的写入操作 ://list.add("abc");-->出错,不能随意的添加数据list.add(null);//3.数据的读取操作:Object s = list.get(0);}
}
=================================================================class T{//这是main方法,程序的入口public static void main(String[] args) {Test t = new Test();t.a(new ArrayList<Integer>());t.a(new ArrayList<String>());t.a(new ArrayList<Object>());}
}
5.泛型受限
public class Test {//这是main方法,程序的入口public static void main(String[] args) {//a,b,c三个集合是并列的关系:List<Object> a = new ArrayList<>();List<Person> b = new ArrayList<>();List<Student> c = new ArrayList<>();/*开始使用泛型受限:泛型的上限List<? extends Person>:就相当于:List<? extends Person>可以是List<Person>的类型,也可以是List<Person的子类>类型*/List<? extends Person> list1 = null;/*list1 = a;// 报错list1 = b; list1 = c;*//*开始使用泛型受限:泛型的下限List<? super Person>就相当于:List<? super Person>可以是List<Person>的类型,也可以是List<Person的父类>类型*/List<? super Person> list2 = null;list2 = a;list2 = b;list3 = c;//报错}
}
三,一个类
-
Collections
Collection和Collections的区别
Collection是Java提供的集合接口,存储一组不唯一,无序的对象。它有两个子接口List和Set。
Java中还有一个Collections类,专门用来操作集合类 ,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
public static void main(String[] args) {//Collections不支持创建对象,因为构造器私有化了/*Collections cols = new Collections();*///里面的属性和方法都是被static修饰,我们可以直接用类名.去调用即可://常用方法://addAll:ArrayList<String> list = new ArrayList<>();list.add("cc");list.add("bb");list.add("aa");Collections.addAll(list,"ee","dd","ff");Collections.addAll(list,new String[]{"gg","oo","pp"});System.out.println(list);//binarySearch必须在有序的集合中查找:--》排序:Collections.sort(list);//sort提供的是升序排列System.out.println(list);//binarySearchSystem.out.println(Collections.binarySearch(list, "cc"));//copy:替换方法ArrayList<String> list2 = new ArrayList<>();Collections.addAll(list2,"tt","ss");Collections.copy(list,list2);//将list2的内容替换到list上去System.out.println(list);System.out.println(list2);//fill 填充Collections.fill(list2,"yyy");System.out.println(list2);
集合总结:
“两个图”:Collecton ;map
“7个接口”:Collecton list set map Iterator Comparable,Comparator
“1个类”:Collections
“两个去重原理”: TessSet(比较器) HashSet(hashCode + equals)
"3种map遍历": Values() keySet() entrySet()
例题
功能1:定义方法public void listToMap( )将List中Student元素封装到Map中
z使用构造方法Student(int id,String name,int age,String sex )创建多个学生信息并加入List
- 遍历List,输出每个Student信息
- 将List中数据放入Map,使用Student的id属性作为key,使用Student对象信息作为value
- 遍历Map,输出每个Entry的key和value
package set.homework;import org.omg.CORBA.INTERNAL;import java.util.Objects;public class Student implements Comparable<Student> {//a.创建Student类,private Integer id;private String name;private Integer age;public Student() {}public Student(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';} //按照年龄从大到小排序@Overridepublic int compareTo(Student o) {return this.age-o.age;} }
package listmap;import java.util.*;public class ListToMap {public static void main(String[] args) {List<Student1> list = new ArrayList<>();list.add(new Student1(1, "张三", 15, "男"));list.add(new Student1(2, "李四", 16, "男"));list.add(new Student1(3, "王五", 17, "男"));list.add(new Student1(4, "唐六", 18, "男"));list.add(new Student1(5, "蒋七", 19, "女"));for (Student1 s: list) {System.out.println(s);}System.out.println("=====================");Map<Integer, Student1> map = new TreeMap<>();Iterator<Student1> it = list.iterator();while(it.hasNext()){Student1 stu = it.next();map.put(stu.getId(), stu);}Set<Map.Entry<Integer, Student1>> entries = map.entrySet();Iterator<Map.Entry<Integer, Student1>> iterator2 = entries.iterator();while (iterator2.hasNext()){Map.Entry<Integer, Student1> next = iterator2.next();System.out.println(next.getValue());}} }