集合概述
Java集合概览集合的由来集合与数组的区别如何选用集合?为什么要使用集合? Collection集合
Collection集合的方法 List
List接口的实现类ArrayList与linkedList区别?ArrayList的自动扩容机制List接口的方法 Set
Set接口的实现类
HashSetlinkedHashSetTreeSet
集合概述 Java集合概览Java集合,也叫做容器,主要是由两大接口派生而来:
一个是Collection接口,主要用于存放单一元素;下面也有三个主要的子接口:List、Set,Queue。另一个是Map接口,主要用于存放键值对。
Java集合框架如下图:
集合的由来Java是面对对象的语言,我们在编程的时候自然需要存储对象的容器,数组可以满足这个需求,但是数组初始化时长度是固定的,但是我们需要一个长度可变化的容器,因此,集合诞生了。
集合与数组的区别长度区别:集合长度可变,数组长度固定。内容区别:集合可存储不同类型元素,数组存储只可单一类型元素。元素区别:集合只能存储引用类型元素,数组可存储引用类型,也可存储基本类型。 如何选用集合?
主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用 Map 接口下的集合,需要排序时选择 TreeMap,不需要排序时就选择 HashMap,需要保证线程安全就选用 ConcurrentHashMap。
当我们只需要存放元素值时,就选择实现Collection 接口的集合,需要保证元素唯一时选择实现 Set 接口的集合比如 TreeSet 或 HashSet,不需要就选择实现 List 接口的比如 ArrayList 或 linkedList,然后再根据实现这些接口的集合的特点来选用。
为什么要使用集合?当我们需要保存一组类型相同的数据的时候,我们应该是用一个容器来保存,这个容器就是数组,但是,使用数组存储对象具有一定的弊端, 因为我们在实际开发中,存储的数据的类型是多种多样的,于是,就出现了“集合”,集合同样也是用来存储多个数据的。
数组的缺点是一旦声明之后,长度就不可变了;同时,声明数组时的数据类型也决定了该数组存储的数据的类型;而且,数组存储的数据是有序的、可重复的,特点单一。 但是集合提高了数据存储的灵活性,Java 集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据。
Collection集合 Collection集合的方法Collection接口是单列集合的的最顶层接口,拥有如下的方法。
public class CollectionTest01 { public static void main(String[] args) { //创建一个集合对象 //Collection c = new Collection(); 接口是抽象的,无法实例化。 Collection c = new ArrayList(); c.add(1200); //自动装箱,实际上是放进去了一个对象的内存地址。 //Integer x = new Integer(1200) c.add(new Object()); c.add(3.14); c.add(true);//自动装箱 System.out.println(c.remove(1200));//true System.out.println("集合中元素的个数是:"+c.size());//3 c.clear(); System.out.println("集合中元素的个数是:"+c.size()); //0 c.add("钢铁侠"); c.add("蜘蛛侠"); c.add("美国队长"); System.out.println(c.contains("钢铁侠"));//true System.out.println(c.contains("蜘蛛侠"));//true System.out.println(c.isEmpty());//false c.clear(); System.out.println(c.isEmpty());//true c.add("abc"); c.add("def"); c.add(100); Object[] objs=c.toArray(); for(int i=0;iIterator:迭代器,它是Java集合的顶层接口(不包括 map 系列的集合,Map接口 是 map 系列集合的顶层接口)
public class CollectionTest02 { public static void main(String[] args) { //创建集合 Collection c=new ArrayList(); //如果没有重新获取,调用next()方法时会发生异常:java.util.ConcurrentModificationException //添加元素 c.add(1); c.add(2); c.add(3); //获取迭代器 Iterator it=c.iterator(); while (it.hasNext()){ Object obj=it.next(); System.out.println(obj); //1 2 3 } } }List List接口的实现类List接口是有序列表,允许存放重复的元素。
List接口的三个典型实现:
List list1 = new ArrayList(); List list2 = new Vector(); List list3 = new linkedList();List接口实现类 ArrayList linkedList Vector 底层数据结构Object[ ]数组双向链表Object[ ]数组 查询速度快慢快 查询效率高高低 增删速度慢快慢 线程安全性不安全不安全安全 可否存储重复元素可以可以可以 ArrayList与linkedList区别?数组可以理解为:
被编号站成一排的人,找第10个人很容易,根据编号就很快找到。但是插入、删除慢,因为在任何一个位置插入或删除后,在此位置之后的人编号都需要改变。
链表可以理解为:
手牵手站成一个圈的人,找第10个人不容易,必须从第1个人一个个的数过去。但是插入、删除快。插入或删除任意位置的时候只需要解开对于位置的俩个人的手即可。
是否保证线程安全: ArrayList 和 linkedList 都是不同步的,也就是不保证线程安全。底层数据结构: Arraylist 底层使用的是 Object 数组;linkedList 底层使用的是 双向链表 数据结构。是否支持快速随机访问: linkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 linkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。List接口的方法插入和删除是否受元素位置的影响:
ArrayList的自动扩容机制ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述 *** 作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的 *** 作。linkedList 采用链表存储,所以,如果是在头尾插入或者删除元素不受元素位置的影响(add(E e)、addFirst(E e)、addLast(E e)、removeFirst() 、 removeLast()),近似 O(1),如果是要在指定位置 i 插入和删除元素的话(add(int index, E element),remove(Object o)) 时间复杂度近似为 O(n) ,因为需要先移动到指定位置再插入。
待定完成
List接口的方法public class ListTest { public static void main(String[] args) { //创建List类型集合 //List mylist = new Vector(); //List mylist = new linkedList(); List mylist = new ArrayList(); //添加元素 mylist.add("A"); mylist.add("B"); mylist.add("C"); mylist.add("D"); mylist.add("D"); mylist.add(1,"Weirdo"); //迭代 Iterator it = mylist.iterator(); while (it.hasNext()){ Object elt = it.next(); System.out.println(elt); } Object firstObj = mylist.get(0); System.out.println(firstObj); System.out.println(mylist.indexOf("Weirdo"));//1 System.out.println(mylist.lastIndexOf("D"));//输出结果:5 mylist.remove(0); System.out.println(mylist); //[Weirdo, B, C, D, D] mylist.set(1,"zhn"); System.out.println(mylist);//[Weirdo, zhn, C, D, D] } }Set Set接口的实现类Set接口是无序集合,不允许存放重复的元素,允许使用null元素。
HashSetSetset = new HashSet (); for(int i= 0;i<5;i++){ set.add(i+""); } set.add("4"); //重复数据,不会写入 set.add(null); //可以写入空数据 Iterator iter = set.iterator(); while(iter.hasNext()){ System.out.println(iter.next()); //输出是无序的 } linkedHashSetHashSet注意点:
HashSet中不能出现重复数据,元素唯一。HashSet中可以出现空数据,即null。HashSet中的数据是无序的。
Setset = new linkedHashSet (); for(int i= 0;i<5;i++){ set.add(i+""); } set.add("4"); //重复数据,不会写入 set.add(null); //可以写入空数据 Iterator iter = set.iterator(); while(iter.hasNext()){ System.out.println(iter.next()); //输出是有序的 } TreeSetlinkedHashSet注意点:
linkedHashSet不同于HashSet,linkedHashSet是有序的linkedHashSet在迭代访问Set中全部元素时,性能比HashSet好,但是插入时就差于HashSet
public class TreeSetTest01 { public static void main(String[] args) { TreeSettreeSet = new TreeSet<>(); treeSet.add(90); treeSet.add(83); treeSet.add(45); treeSet.add(50); treeSet.add(78); treeSet.add(45); //重复元素只会输出一次 //treeSet.add(null); //不可以写入空元素 treeSet.add(24); treeSet.add(27); for (Integer integer : treeSet) { System.out.println(integer); } } } 上述代码中,集合的元素唯一且进行了排序
使用TreeSet集合进行元素的自然排序,对元素有一定要求,并且这个元素必须实现Comparable接口并重写comparseTo方法,上诉代码为什么没有实现Comparable接口?因为Inreger类实现了该接口,并且重写了里面的方法,如果是自定义类那么必须重写该接口。
//Integer类的源码,里面重写了Comparable接口 public final class Integer extends Number implements Comparable//TreeSet中的部分源码 public TreeSet(Comparator super E> comparator) { this(new TreeMap<>(comparator)); } 上面,我们实现了自然排序的方式,接下来我们来看看实现自定义排序:
public class TreeSetTest02 { public static void main(String[] args) { //按照学生的年龄大小来排序 Student s1 = new Student("张三", 21); Student s2 = new Student("张三", 21); Student s3 = new Student("张三3", 25); Student s4 = new Student("张三4", 25); Student s5 = new Student("张三5", 23); Student s6 = new Student("张三6", 25); Student s7 = new Student("张三7", 26); Student s8 = new Student("李四1", 28); Student s9 = new Student("李四2", 28); Student s10 = new Student("李四3", 25); TreeSettreeSet = new TreeSet<>(); treeSet.add(s1); treeSet.add(s2); treeSet.add(s3); treeSet.add(s4); treeSet.add(s5); treeSet.add(s6); treeSet.add(s7); treeSet.add(s8); treeSet.add(s9); treeSet.add(s10); for (Student student : treeSet) { System.out.println(student); } } } class Student implements Comparable { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + ''' + ", age=" + age + '}'; } @Override public int compareTo(Student s) { //比较按照 年龄大小来排序 int result1 = this.age - s.age; //如果年龄相同,不能说明是一个对象,在比较下姓名 int result2 = result1 == 0 ? this.name.compareTo(s.name) : result1; return result2; } } 上述代码,我们自定义了一个Student类,并且实现了Comparable接口,还重写了compareTo方法。
TreeSet底层实现是二叉树(红黑树),那么是如何存储元素的呢?
待定完成
简单理解一下TreeSet的特点:
不能写入空数据写入数据是有序的不会写入重复元素
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)