day12-集合框架(上)
-
集合入门
-
Collection接口
-
List
-
Set
-
Map
集合入门
集合(Conllection),集合即一种容器,是数据结构在Java应用中的 一种体现,早在jdk1.0的版本中就存在一些集合相关类:Stack,Properties,Vector,Dictionary;但是由于上述结构均为类,不利于扩展,并且无统一标准;因此,在JDK1.2之后Java就引入了集合框架,其中包括Collection,List,Set,Deque(JDK1.6),Map等接口.
Collection
Collection是集合框架的顶层接口,大多数的集合类,接口都是直接或者间接从Collection继承或者实现
List接口
List接口直接从Collection接口继承而来,List集合是一个有序集合(元素在集合中的存储顺序是有序的,获取的时候根据存储的位置获取),List允许重复元素,List接口包含三个比较常用的实现类:ArrayList、LinkedList、Vector(jdk1.0)
public static void main(String[] args) { List list = new ArrayList(); // List list = new LinkedList(); // List list = new Vector(); list.add(new String("abc")); list.add("hello"); list.add(123); list.add(new User()); //向指定的索引处插入元素 list.add(1, true); //替换指定 索引出的元素 list.set(1, true); //移除指定索引处的元素,并返回该被移除的元素对象 // Object obj = list.remove(1); // boolean result = list.remove(new String("abc")); // System.out.println(result); List list2 = new ArrayList(); list2.add(123); list2.add("hello"); //从当前集合中删除子集 boolean result = list.removeAll(list2); System.out.println(result); System.out.println(list); //向当前集合添加子集合 list.addAll(list2); System.out.println(list); }
ArrayList,LinkedList,Vector区别?
ArrayList基于可变长度的数组实现,内部通过数组拷贝原理实现容量扩展,ArrayList每次扩展为源数组的一半,ArrayList进行元素查询时相对LinkedList快(每个元素都有一个索引,可以直接根据索引获取元素),ArrayList是线程不同步的实现(效率高,不安全)
LinkedList基于链表的实现,内部元素之间通过首尾指针关联,在进行元素修改时(比如新增元素),相对ArrayList会更方便(只需要修改元素的首尾指针指向即可),但是在进行查询时链表的查询效率是低于数组的
Vector基于可变长度的数组实现,Vector每次扩展为原来长度的一倍(ArrayList是一半),Vector是线程同步的实现(效率低,安全)
Set集合
Set集合也是从Collection接口继承而来,set集合是一个无序集合(存储顺序与元素的添加顺序无关),set集合不允许出现重复元素(重复元素会覆盖第一次出现的元素),不允许存在e1.equals(e2)的情况(针对HashSet的实现),set集合中的元素无法通过索引获取;Set集合有两个常用的实现类:HashSet、TreeSet
基于HashSet的实现
public static void main(String[] args) { Set set = new HashSet(); set.add("hello"); set.add("rose"); set.add("jack"); set.add("admin"); set.add("true"); set.add("admin"); // for (Object o : set) { // System.out.println(o); // } Iterator it = set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } }
基于TreeSet的实现
首先被作为元素的对象必须实现Comparable接口并实现接口中的compareTo方法
public class Student implements Comparable<Student>{ private int age; public Student(int age) { this.age = age; } //实现对比方法 @Override public int compareTo(Student o) { return this.age - o.age; } @Override public String toString() { return "Student [age=" + age + "]"; } }
测试类:
public class TreeSetDemo { public static void main(String[] args) { Set set = new TreeSet(); // set.add(10); // set.add(20); set.add(new Student(28)); set.add(new Student(16)); set.add(new Student(18)); set.add(new Student(18)); // set.add(new String("hello"));//ClassCastException System.out.println(set); } }
HashSet和TreeSet区别?
HashSet元素添加到集合中之后,元素的存储顺序,基于散列算法(计算获取对象在内存中的唯一地址)实现的元素排序,HashSet是线程不同步的实现;
TreeSet基于二叉树中红黑树算法实现,TreeSet内部的元素存储顺序跟元素实现的Comparable接口中compareTo方法有关,所以TreeSet要求所有元素所对应的类必须实现Comparable接口(TreeSet要求内部存储的元素必须是相同的数据类型),TreeSet也是线程不同步的实现;
Map集合
Map集合是一种键值对结构,不同与List与Set;Map集合中的元素通常由key-value构成,一个键可以指向一个值,但是键不允许重复,但是值可以,Map集合的出现是为了取代老式的Dictionary类,Map集合常用的两个实现类:HashMap,TreeMap
public static void main(String[] args) { Map<String,Integer> map = new HashMap<>(); map.put("一号", 100); map.put("二号", 100); map.put("三号", 80); map.put("四号", 70); map.put("五号", 60); System.out.println(map); //获取map集合中的所有键集 Set<String> keys = map.keySet(); //获取map集合的值集 Collection<Integer> c = map.values(); for(String k:keys){ //根据键获取值 int i = map.get(k); System.out.println(k+":"+i); } }
HashMap、TreeMap、Hashtable,ConcurrentHashMap的区别
HashMap基于散列表实现的Map(jdk1.2)接口,内部的元素存储顺序根据元素中键的Hash值排序,每个元素都存在一个独一无二的hash地址,所以不允许出现重复的键,允许空键值,此实现是线程不同步的。
TreeMap基于红黑树的实现,内的元素存储顺序默认按照元素的自然顺序排序,或者根据给定的比较器(Comparator)进行排序,集合中键必须是同一种数据类型,键对应的类型必须实现Comparable接口,并实现比较的方法(compareTo(T t))
Hashtable基于散列表的从老式Dictionary(jdk1.0)类继承,Hashtable不允许空键值存在,Hashtable是线程安全的实现(线程同步)
哈希算法:
https://blog.csdn.net/asdzheng/article/details/70226007
完成一个通讯录需求:1.添加联系人(联系人:编号,姓名,电话,QQ)2.联系人查询(输入姓名或电话查询)3.显示联系人列表(要求按照姓名拼音字典顺序排序:中文排序)4.根据编号删除指定联系人
Jsoup 爬虫插件
day13-集合框架(下)
-
Collections类
-
Comparable(内部比较器)&Comparator(外部比较器)
-
泛型(Generic)
-
*集合流式处理(JDK8+)
Collections类
jdk1.2引入集合框架后,同时也新增了一些类用于方便的对集合进行处理(排序,查找等),这些功能主要包含在java.util.Collections类中,Collections类中的所有方法都是静态方法,所以调用起来比较简单
public class CollectionsDemo { public static void main(String[] args) { List<User> list = new ArrayList<User>() { { add(new User("james", 22)); add(new User("tom", 28)); add(new User("kobe", 62)); add(new User("curry", 19)); add(new User("wade", 55)); add(new User("rose", 42)); add(new User("zhangsanfeng", 42)); } }; // 获取集合中最大(根据元素自然顺序-Comparable接口中compareTo方法的实现)的元素 User max = Collections.max(list); // 若集合中的元素未实现Comparable接口时,可以单独使用比较器(Comparator)比较 Lambda表达式 max = Collections.max(list, (u1, u2) -> u1.getAge() - u2.getAge()); System.out.println(max); // 反转集合 Collections.reverse(list); // 对集合顺序随机打乱(洗牌) Collections.shuffle(list); // 排序,根据集合中元素实现的Comparable接口 Collections.sort(list); // 根据提供的比较器排序 Collections.sort(list, (u1, u2) -> u1.getAge() - u2.getAge()); for (User user : list) { System.out.println(user); } } }
泛型
jdk1.5之后新增参数化类型,即将一个类型作为参数进行传递,这样可以将类型检查提前到编译期间,从而避免了在运行时进行类型检查(造成编程困难),具体使用如下 :
BaseManager.java
//设置参数化类型 public interface BaseManager<T> { public boolean add(T obj); public boolean del(T obj); public boolean update(T obj); public T findOne(T obj); public List<T> findAll(); }
DeptImpl.java
public class DeptImpl implements BaseManager<Dept>{ @Override public boolean add(Dept obj) { // TODO Auto-generated method stub return false; } @Override public boolean del(Dept obj) { // TODO Auto-generated method stub return false; } @Override public boolean update(Dept obj) { // TODO Auto-generated method stub return false; } @Override public Dept findOne(Dept obj) { // TODO Auto-generated method stub return null; } @Override public List<Dept> findAll() { // TODO Auto-generated method stub return null; } }
EmpImpl.java
public class EmpImpl implements BaseManager<Emp> { @Override public boolean add(Emp obj) { // TODO Auto-generated method stub return false; } @Override public boolean del(Emp obj) { // TODO Auto-generated method stub return false; } @Override public boolean update(Emp obj) { // TODO Auto-generated method stub return false; } @Override public Emp findOne(Emp obj) { // TODO Auto-generated method stub return null; } @Override public List<Emp> findAll() { // TODO Auto-generated method stub return null; } }
对于以上如果有多个参数化类型可以在声明时指定:
public interface BaseManager<T1,T2> { public boolean add(T1 t1,T2 t2); public boolean del(T1 t); public boolean update(T1 t); public T1 findOne(T1 t); public List<T1> findAll(); }
或者在方法中单独设定:
public <E> boolean add(T obj,E e);
JDK8流式处理集合
JDK8引进了新的用于对集合处理的解决方案-流式处理,可以通过链式编程,函数式接口,lambda表达式简单便捷的对集合完成,过滤,排序,截取等操作。
public class StreamDemo { /** * 集合流式处理机制 * @param args */ public static void main(String[] args) { List<User> list = new ArrayList<>(); list.add(new User("jackson", 22)); list.add(new User("jack", 32)); list.add(new User("aoteman", 40)); list.add(new User("tom", 43)); list.add(new User("atom", 22)); list.add(new User("bob", 23)); list.add(new User("jackson", 12)); list.add(new User("rose", 62)); list.add(new User("rose", 62)); list.add(new User("kobe", 17)); list.add(new User("curry", 16)); list = list.stream() .filter(user -> user.getAge() > 18) //过滤掉所有年龄小于等于18的用户 .sorted((u1,u2) -> u1.getAge() - u2.getAge()) //排序 .distinct() //去除重复(以hashcode为准:重写equals和hashcode) .skip(3) //跳过指定行 .limit(5) //显示指定行 .collect(Collectors.toList()); //收集数据 //统计 long count = list.stream().count(); System.out.println("符号条件的数据行数:"+count); //forEach遍历 list.stream().forEach(u->System.out.println(u)); //获取所有用户的用户名,并拼接为字符串输出 jack,aoteman,tom,rose String s = list.stream().map(User::getName).collect(Collectors.joining(",")); System.out.println(s); } }