foreach循环:
//方式1:普通for循环
// for (int i = 0;i < arr.length;i++){
// arr[i]="GG";
// }
// for (int i = 0; i < arr.length; i++) {
// System.out.println(arr[i]);输出:GG GG GG
// }
//方式2:增强for循环
for(String s : arr){
s = "GG";
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}//输出:MM MM MM
}
}
List接口
// ----List接口:存储有序,可重复的数据。“动态数组”
// ----ArrayList:作为List接口的主要实现类,线程不安全,效率高,底层使用Object[] elementData存储
// ----LinkedList:对于频繁的插入,删除操作,但是遍历,查找效率不高。使用此类效率比ArrayList高。底层使用双向链表存储
// ----Vector:作为List接口的古老实现类,线程安全,效率低,底层使用Object[] elementData存储
// 面试题:三者的异同
// 同:都实现了List接口,存储数据特点相同
// 不同:在上面有所体现
ArrayList的源码分析
jdk7.0情况下
ArrayList list = new ArrayList();//底层创建了长度是10的Object数组elementData
List.add(123);//elementData[0]=new Integer(123)
...
list.add(11)//如果此次添加导致底层elementData数组容量不够,则进行扩容
默认情况下,扩容为原来的1.5倍,同时需要将原有的数据复制到新的数组中
结论:建议开发中使用带参的构造器:Arrayslist list = new ArrayList(int capacity)
jdk8.0情况下的变化:
ArrayList list = new ArrayList();//此时底层Object[]elementData初始化为{},并没有创建长度为10的数组
list.add(123)//此时才创建了底层长度为10的数组,并将数据123添加到elementData[0]
...
后续的添加与扩容与jdk7.0相同
小结:jdk7中ArraysList的对象的创建类似于单例模式中的饿汉式。
jdk8中ArraysList的对象的创建相当于懒汉式,延迟了数组的创建,节省了内存
*/
LinkedList源码分析
LinkedList list = new LinkedList();//内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象
其中Node定义为:双向链表
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;
}
public void test(){
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);
//1.void add(int index,Object ele):在index位置插入ele元素
list.add(1,"BB");
//2.boolean addAll(int index,Collection eles):从index位置开始将eles中所有元素添加到
List list1 = Arrays.asList(1, 2, 3);
list.addAll(list1);
System.out.println(list.size());//9
//3.Object get(int index):获取指定index位置的元素
System.out.println(list.get(0));//123
}
}
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");
list.add(new Person("Tom", 12));
list.add(456);
//4.int indexOf(Object obj):返回obj在集合中首次出现的位置,如果不存在,返回-1
int index = list.indexOf(456);
System.out.println(index);//1
//5.int lastIndexOf(Object obj):返回obj在集合中末次出现的位置,如果不存在,返回-1
int index1 = list.lastIndexOf(456);
System.out.println(index1);//4
//6.Object remove(int index):移除指定位置的元素,并返回该元素
Object remove = list.remove(0);
System.out.println(remove);//123
System.out.println(list);//[456, AA, Person{name='Tom', age=12}, 456]
//7.Object set(int index,Object ele):设置指定index位置的元素为ele
list.set(1,"CC");
System.out.println(list);//[456, CC, Person{name='Tom', age=12}, 456]
//8.subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的左闭右开区间的子集合
List list1 = list.subList(2, 4);
System.out.println(list1);//[Person{name='Tom', age=12}, 456]
}
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接口
七上八下:jdk7时新在上,jdk8时新在下
1.Set中没有定义新的方法,使用的都是Collection中声明过的方法
2.要求:向Set中添加的数据,其所在的类一定要重写hashCode()和equals()
要求:重写的hashCode()和equals()尽可能保持一致性
一丶Set:存储无序的,不可重复的数据
以HashSet为例说明:
1.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的
2.不可重复性:保证添加的元素按照equals()判断时,不能返回true 即:相同的元素只能添加一个
而自定义类需要重写equals()方法
二丶添加元素的过程:以HashSet为例说明
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode方法,计算a的哈希值
此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置)
判断数组此位置上是否已经有元素,
如果此位置上没有其他元素,则a添加成功--->添加成功的情况1
如果此位置上有其他元素b(或者以链表形式存在的多个元素),则比较a与b的哈希值:
如果哈希值不相同,则a添加成功。--->添加成功的情况2
如果哈希值相同,进而调用a所在类的equals方法
equals返回true,表明a添加失败
equals返回false,则a添加成功--->添加成功的情况3
对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上数据以链表方式存储
jdk7:a放到数组中,指向原来的元素
jdk8:原来的元素在数组中,指向a
总结:七上八下
HashSet底层:数组+链表
*/
LinkedList
//LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据后一个数据
//对于频繁的遍历操作,LinkedHashSet效率高于HashSet
public void test1(){
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 set = new TreeSet();
//失败:不能添加不同类的对象
// set.add(123);
// set.add(456);
// set.add("AA");
// set.add(new Person("TOM",12));
//举例1:
// set.add(34);
// set.add(-34);
// set.add(43);
// set.add(11);
// set.add(8);
//举例2:
set.add(new User("TOM",12));
set.add(new User("JERRY",32));
set.add(new User("MIKE",2));
set.add(new User("JIM",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());
}
}
Class User{
//按照姓名从大到小排列,年龄从小到大排序
public int compareTo(Object o) {
if(o instanceof User){
User user = (User) o;
int compare = -this.name.compareTo(user.name);
if(compare!=0){
return compare;
}else{
return Integer.compare(this.age,user.age);
}
}else {
throw new RuntimeException("输入的类型不匹配");
}
}
}
Comparator com = new Comparator() {
//按照年龄从小到大排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User&&o2 instanceof User){
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else{
throw new RuntimeException("输入的类型不匹配");
}
}
};
TreeSet set = new TreeSet(com);
set.add(new User("TOM",12));
set.add(new User("JERRY",32));
set.add(new User("MIKE",2));
set.add(new User("JIM",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());
}
}
}
4个注意点
1.向TreeSet中添加的数据,要求是相同类的对象
2.两种排序方式:自然排序(实现Comparable接口)和定制排序
3.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals方法
4.定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals方法