每日一考
1.类中的对象的个数是确定的,有限个
2.private static final
1.对现有的注解进行解释说明的注解
2.Retention:指明所修饰的注解的生命周期
Target:的作用是限定注解可作用的元素
1.throw生成一个异常对象,并抛出。使用在方法内部,自动抛出异常对象
2.throws处理异常的方式,使用在方法声明处的末尾
1.同步监视器:俗称锁,任何一个类的对象都可以充当锁,所有线程必须共用同一个锁
2.共享数据:需要使用同步机制将操作共享数据的代码包起来。不能包多了,也不能包少了。
复习
day22的学习内容
集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库等)
数组在存储多个数据方面的特点:
一旦初始化以后,其长度就确定了
数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了
数组在存储多个数据方面的缺点:
①一旦初始化以后,其长度就不可修改。
②数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高
③获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
④数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足
//常用的接口和实现类
|----Collection接口:单列集合,用来存储一个一个的对象
|----List接口:存储有序的、可重复的数据
|----ArrayList、LinkedList、Vector
|----Set接口:存储无序的、不可重复的数据
|----HashSet、LinkedHashSet、TreeSet
|----Map接口:双列集合,用来存储一对(key - value)一对的数据
|----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
Collection coll = new ArrayList();
//add(Object e):将元素e添加到集合coll中
coll.add("AA");
coll.add("BB");
coll.add(123);//自动装箱
coll.add(new Date());
//addAll(Collection coll1):将coll1集合中的元素添加到当前的集合中
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add("CC");
coll.addAll(coll1);
System.out.println(coll.size());
coll.clear();
System.out.println(coll.isEmpty());
//contains(Object obj)
boolean contains = coll.contains(123);
System.out.println(contains);
System.out.println(coll.contains(new String("Tom")));
//containsAll(Collection coll1)
Collection coll1 = Arrays.asList(123, 4567);
System.out.println(coll.containsAll(coll1));
coll.remove(new Person("Jerry", 20));
System.out.println(coll);
Collection coll1 = Arrays.asList(123, 456);
coll.removeAll(coll1);
System.out.println(coll);
Collection coll1 = Arrays.asList(123,456,789);
coll.retainAll(coll1);
System.out.println(coll);
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add(123);
coll1.add(new Person("Jerry", 20));
coll1.add(new String("Tom"));
coll1.add(false);
System.out.println(coll.equals(coll1));
Object[] arr = coll.toArray();
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
System.out.println(coll.hashCode());
Iterator iterator = coll.iterator();
Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素
GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生
Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建Iterator 对象,则必须有一个被迭代的集合
集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
注意:
Iterator可以删除集合的元素,但是是遍历过程中通过迭代器对象的remove方法,不是集合对象的remove方法
如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException
//遍历集合
iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//删除集合中"Tom"
Iterator iterator = coll.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if ("Tom".equals(obj)) {
iterator.remove();
}
}
一、list接口框架
|----Collection接口:单列集合,用来存储一个一个的对象
|----List接口:存储有序的、可重复的数据。 -->“动态”数组,替换原有的数组
|----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
|----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
|----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储
二、ArrayList的源码分析
① jdk 7情况下
ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData
list.add(123);//elementData[0] = new Integer(123);
...
list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容
默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中
结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
② jdk 8中ArrayList的变化:
ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没有创建长度为10的数组
list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]
...
后续的添加和扩容操作与jdk 7 无异
③ 小结:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存
三、LinkedList的源码分析
LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象。
其中,Node(LinkedList的内部类)定义为:体现了LinkedList的双向链表的说法
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
四、Vector的源码分析
jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组;在扩容方面,默认扩容为原来的数组长度的2倍
面试题:ArrayList、LinkedList、Vector三者的异同?
同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
不同:参考list接口框架
五、List接口中的常用方法
//boolean add(E e):在末尾插入e
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");
list.add(new Person("Tom", 12));
list.add(456);
System.out.println(list);
//void add(int index, E element):在index位置插入element元素
list.add(1, "BB");
System.out.println(list);
//boolean addAll(Collection extends E> c):将c中的所有元素添加进来
List list1 = Arrays.asList(1, 2, 3);
list.addAll(list1);
System.out.println(list.size());
//boolean addAll(int index, Collection extends E> c):在index处加入c中的所有元素
System.out.println(list.get(0));
int index = list.indexOf(4567);
System.out.println(index);
System.out.println(list.lastIndexOf(456));
Object obj = list.remove(0);
System.out.println(obj);
System.out.println(list);
list.set(1, "CC");
System.out.println(list);
List subList = list.subList(2, 4);
System.out.println(subList);
System.out.println(list);
总结:常用方法
增:add(Object obj)
删:remove(int index) / remove(Object obj)
改:set(int index, Object ele)
查:get(int index)
插:add(int index, Object ele)
长度:size()
遍历:① Iterator迭代器方式 ② 增强for循环 ③ 普通的循环
一、Set接口的框架
|----Collection接口:单列集合,用来存储一个一个的对象
|----Set接口:存储无序的、不可重复的数据 -->高中讲的“集合”
|----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
|----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历
对于频繁的遍历操作,LinkedHashSet效率高于HashSet
|----TreeSet:可以按照添加对象的指定属性,进行排序
二、Set接口的概述
Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法
向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()
要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值
三、Set的特点
存储无序的、不可重复的数据
以HashSet为例说明:
四、添加元素的过程
以HashSet为例:
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过
某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:
如果此位置上没有其他元素,则元素a添加成功 --->情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
如果hash值不相同,则元素a添加成功 --->情况2
如果hash值相同,进而需要调用元素a所在类的equals()方法:
equals()返回true,元素a添加失败
equals()返回false,则元素a添加成功 --->情况3
对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储
五、jdk版本的差异
jdk 7 :元素a放到数组中,指向原来的元素
jdk 8 :原来的元素在数组中,指向元素a
HashSet底层:数组+链表的结构
六、使用方法举例
Set set = new HashSet();
set.add(456);
set.add(123);
set.add(123);
set.add("AA");
set.add("CC");
set.add(new User("Tom", 12));//重写方法后才会去重
set.add(new User("Tom", 12));
set.add(129);
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
七、LinkedHashSet的使用
LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据
优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
Set set = new LinkedHashSet();
set.add(456);
set.add(123);
set.add(123);
set.add("AA");
set.add("CC");
set.add(new User("Tom", 12));
set.add(new User("Tom", 12));
set.add(129);
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
八、TreeSet的使用
//User类中实现Comparable接口(按名字排序),就会按序输出
set.add(new User("Tom", 12));
set.add(new User("Jerry", 32));
set.add(new User("Jim", 2));
set.add(new User("Mike", 65));
set.add(new User("Jack", 33));
set.add(new User("Jack", 56));
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
//com是Comparator接口的实现类,可以匹配相应的构造器进行传参
TreeSet set = new TreeSet(com);
set.add(new User("Tom", 12));
set.add(new User("Jerry", 32));
set.add(new User("Jim", 2));
set.add(new User("Mike", 65));
set.add(new User("Mary", 33));
set.add(new User("Jack", 33));
set.add(new User("Jack", 56));
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
jdk 5.0 新增了foreach循环(增强for循环),用于遍历集合、数组
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);
//for(集合元素的类型 局部变量 : 集合对象)
//内部仍然调用了迭代器
for (Object obj : coll) {
System.out.println(obj);
}
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
//for(数组元素的类型 局部变量 : 数组对象)
for (int i : arr) {
System.out.println(i);
}