
集合概述
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;i
Iterator:迭代器,它是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[ ]数组 查询速度快慢快 查询效率高高低 增删速度慢快慢 线程安全性不安全不安全安全 可否存储重复元素可以可以可以
数组可以理解为:
被编号站成一排的人,找第10个人很容易,根据编号就很快找到。但是插入、删除慢,因为在任何一个位置插入或删除后,在此位置之后的人编号都需要改变。
链表可以理解为:
手牵手站成一个圈的人,找第10个人不容易,必须从第1个人一个个的数过去。但是插入、删除快。插入或删除任意位置的时候只需要解开对于位置的俩个人的手即可。
ArrayList与linkedList区别?
是否保证线程安全: ArrayList 和 linkedList 都是不同步的,也就是不保证线程安全。底层数据结构: Arraylist 底层使用的是 Object 数组;linkedList 底层使用的是 双向链表 数据结构。是否支持快速随机访问: linkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 linkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。List接口的方法插入和删除是否受元素位置的影响:
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) ,因为需要先移动到指定位置再插入。
ArrayList的自动扩容机制
待定完成
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元素。
HashSet
Set set = 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()); //输出是无序的
}
HashSet注意点:
HashSet中不能出现重复数据,元素唯一。HashSet中可以出现空数据,即null。HashSet中的数据是无序的。
linkedHashSet
Set set = 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()); //输出是有序的
}
linkedHashSet注意点:
linkedHashSet不同于HashSet,linkedHashSet是有序的linkedHashSet在迭代访问Set中全部元素时,性能比HashSet好,但是插入时就差于HashSet
TreeSet
public class TreeSetTest01 {
public static void main(String[] args) {
TreeSet treeSet = 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);
TreeSet treeSet = 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条)