ArrayList、LinkedList、Vector和Stack是List的四个实现类,其中Vector是基于JDK1.0,虽然实现了同步,但是效率低,已经不用了,Stack继承与Vector,所以不再赘述。
LinkedList是个双向链表,它同样可以被当作栈、队列或双端队列来使用。
collection
在类中重写tostring方法,可以在该类对象println时输出字符值而不是地址值(因为类的积累object包含tostring方法),println在输出对象时默认调用tostring方法
集合可以存储不同类型元素,集合只能存储对象,集合长度可变。
collection是集合的顶层接口,他的子体系有list(有序的)(有序是指插入顺序和取出顺序一样),有set(不能重复的)等等,list下有arrylist vector linkedlist等,set下有hashset treeset等
arrylist底层是数组,查询快,增删慢。线程不安全,效率高
vect底层数据结构是数组,查询快,增删慢。线程安全,效率低
linkedlist底层数据结构是链表,查询慢,增删快。线程不安全,
collection常用方法
removeall只要有一个元素移出就返回true
retainall求两个集合交集,谁调用谁就被改变。返回值返回的是调用的集合有没有发生改变
iterator迭代器使用
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class StudentDemo {
public static void main(String[] args) {
Collection c=new ArrayList(); /创建集合
Student S1=new Student("何艳莹",18);
Student S2=new Student("羊亚红",18);
Student S3=new Student("小羊",19);
Student S4=new Student("羊亚ya红",18);
Student S5=new Student("小xiao羊",19);
c.add(S1);
c.add(S2);
c.add(S3);
c.add(S4);
c.add(S5);
Iterator it=c.iterator(); 获取迭代器对象
while (it.hasNext()){
// System.out.println(it.next());
// Exception in thread "main" java.util.NoSuchElementException 不要多次使用it.next,出现这个错误是因为next类似指针每次。next都往后移动
// at java.util.ArrayList$Itr.next(ArrayList.java:862) 偶数不会报错,奇数报错
// at StudentDemo.main(StudentDemo.java:21)
System.out.println(((Student) it.next()).getName()+"-----"+((Student) it.next()).getAge());
}
}
}
报错:Exception in thread “main” java.util.NoSuchElementException
原因如注释
注意:迭代器是接口不是类。
List
List是有序可重复的collection,此接口使用户可以对列表每个元素的插入位置进行精准控制
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class StudentDemo {
public static void main(String[] args) {
List list = new ArrayList();
//向上转型
list.add("hello");
list.add("world");
list.add("heyanying");
list.add("beaf");
list.add("hello"); //可重复
Iterator it = list.iterator();
while (it.hasNext()) {
// String s = (String) ita.next(); 想要自定义输出形式就要向下转型
System.out.println((String)it.next());
}
}
}
为啥要把arrylist向上转型成list
比如写一个方法,参数要求传递List类型,你就可以用List list = new ArrayList()中的list传递,但是你写成ArrayList list = new ArrayList()是传递不进去的。尽管方法处理时都一样。另外,方法还可以根据你传递的不同list(ArrayList或者LinkList)进行不同处理。
list常用方法
add
get 获取元素
ListIterator 列表迭代器
ListIterator(int index)获取指定位置的迭代器
remove 删除
set (int index,object elemen)修改指定位置元素
listlterator用法展示
import javax.swing.text.html.HTMLDocument;
import java.util.*;
public class StudentDemo {
public static void main(String[] args) {
List lista = new ArrayList();
Collection list=new ArrayList();
//向上转型
list.add("11");
list.add("22");
list.add("33");
lista.add("hello");
lista.add("world");
lista.add("heyanying");
lista.add("beaf");
lista.add("hello"); //可重复
lista.remove(0);
lista.set(0, "hahaha");
// System.out.println("get:"+lista.get(2));
// Iterator it = list.iterator();
// while (it.hasNext()) {
String s = (String) ita.next(); 想要自定义输出形式就要向下转型
// System.out.println((String) it.next());
// }
Iterator it=list.iterator();
while (it.hasNext()){
System.out.println((String)it.next());
}
System.out.println("--------------------");
ListIterator ita=lista.listIterator(); //实现了iterator接口,list特有,可以往前移动
while (ita.hasNext()){
System.out.println((String)ita.next());
}
System.out.println("--------------------");
while (ita.hasPrevious()){
System.out.println((String)ita.previous());
}
// 11
// 22
// 33
// --------------------
// hahaha
// heyanying
// beaf
// hello
// --------------------
// hello
// beaf
// heyanying
// hahaha
//
}
}
Exception in thread “main” java.util.ConcurrentModificationException
at java.util.ArrayList
I
t
r
.
c
h
e
c
k
F
o
r
C
o
m
o
d
i
f
i
c
a
t
i
o
n
(
A
r
r
a
y
L
i
s
t
.
j
a
v
a
:
909
)
a
t
j
a
v
a
.
u
t
i
l
.
A
r
r
a
y
L
i
s
t
Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList
Itr.checkForComodification(ArrayList.java:909)atjava.util.ArrayListItr.next(ArrayList.java:859)
at StudentDemo.main(StudentDemo.java:18)
并发修改异常产生原因
import javax.swing.text.html.HTMLDocument;
import java.util.*;
public class StudentDemo {
public static void main(String[] args) {
List list=new ArrayList();
//向上转型
list.add("11");
list.add("22");
list.add("33");
Iterator it=list.iterator();
while (it.hasNext()){
if("33".equals(it.next())) //集合增加元素而迭代器不知
list.add("success");
System.out.println((String)it.next());
}
}
}
解决方法
a:让迭代器修改元素
b: 集合遍历,集合修改
import javax.swing.text.html.HTMLDocument;
import java.util.*;
public class StudentDemo {
public static void main(String[] args) {
List list=new ArrayList();
//向上转型
list.add("11");
list.add("22");
list.add("33");
// Iterator it=list.iterator();
// while (it.hasNext()){
// if("22".equals(it.next()))
// list.add("success");
// System.out.println((String)it.next());
// }
ListIterator lit=list.listIterator();
while (lit.hasNext()){
if("".equals(lit.next()))
lit.add("success"); // list.add("success")
}
System.out.println((list));
}
}
// [11, 22, success, 33]
//集合遍历可插在最后
iterator和listiterator区别
一、ListIterator有add()方法,可以向List中添加对象,而Iterator不能。
二、ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历。但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
三、ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator 没有此功能。
四、都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。
ArryList
ArrayList类是一个特殊的数组–动态数组。来自于System.Collections命名空间;通过添加和删除元素,就可以动态改变数组的长度。
优点:
1、支持自动改变大小
2、可以灵活的插入元素
3、可以灵活的删除元素
局限:
比一般的数组的速度慢一些;
用法
一、初始化:
1、不初始化容量
ArrayList arr1 = new ArrayList(); //不初始化刚开始的数组容量,当数组容量满时数组会自动一当前数组容量的2倍扩容
2、初始化容量
ArrayList arr2 = new ArrayList(3);//初始容量为3
3、用一个集合或数组初始化
ArrayList arr3 = new ArrayList(a); //a为集合或数组
ArrayList list = new ArrayList(Arrays.asList(-10,-3,0,5,9));
LinkedList
Java的LinkedList是一种常用的数据容器,与ArrayList相比,LinkedList的增删操作效率更高,而查改操作效率较低。
LinkedList是个双向链表,它同样可以被当作栈、队列或双端队列来使用
LinkedList 实现了List 接口,能对它进行列表操作。
LinkedList 实现了Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,能克隆。
LinkedList 实现了java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
构造方法
- LinkedList() 用于创建一个新的空linkedList;
- LinkedList(Collection<? extends E> c) 使用一个集合创建一个新的linkedList。
public class Main {
public static void main(String[] args) {
LinkedList<String> linkedList1 = new LinkedList<>();
System.out.println(linkedList1);
String[] arr = {"H", "E", "L", "L", "O"};
LinkedList<String> linkedList2 = new LinkedList<>(Arrays.asList(arr));
System.out.println(linkedList2);
}
}
Set
package cn.itcast_01;
/*
collection:
list有序是指存储顺序和取出顺序一致,可重复
set无序是指存储顺序和取出顺序不一致,唯一
hashset不保证set迭代顺序,不能保证该顺序恒久不变
linkedhashset底层是hash表和链表(存储和取出顺序一致)
*/
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set<String> set=new HashSet<String>();
set.add("hello");
set.add("java");
set.add("ee");
set.add("java");
set.add("ee");
for(String i :set){
System.out.println(i);
}
}
}
/*
元素唯一且无序
ee
java
hello
*/
HashSet
的唯一性是通过hashcode和equals实现的,其实是哈希表结构,元素hash值相同并且元素值相同不会加入。
注意string类重写了hashcode和equals方法所以可以比较出相同,如果不重写一般不相同。如下
package cn.itcast_01;
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set<Student> set=new HashSet<Student>();
Student s1=new Student("小红",18);
Student s2=new Student("小黄",18);
Student s3=new Student("小红",20);
Student s4=new Student("小黑",18);
Student s5=new Student("小红",18);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
for( Student i :set){
System.out.println(i.toString());
}
}
}
/*
元素重复
Student{name='小红', age=20}
Student{name='小红', age=18}
Student{name='小黄', age=18}
Student{name='小红', age=18}
Student{name='小黑', age=18}
*/
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
Student{name=‘小黄’, age=18}
Student{name=‘小红’, age=18}
Student{name=‘小红’, age=20}
Student{name=‘小黑’, age=18}
没有重复了
TreeSet
能够按照某种顺序给元素排序(选哪个取决于用哪个构造方法)
A:自然排序 -------实现compareable接口重写compareto方法
B:比较器排序 (常见)
无参构造默认自然排序
自然排序 -------实现compareable接口重写compareto方法
package cn.itcast_01;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
TreeSet<Integer> ts=new TreeSet<>(); //无参构造默认自然排序
ts.add(3);
ts.add(1);
ts.add(23);
ts.add(15);
ts.add(15);
for( Integer i :ts){
System.out.println(i);
}
}
}
/*
1
3
15
23
*/
public class SetDemo {
public static void main(String[] args) {
TreeSet<Student> set=new TreeSet<Student>();
Student s1=new Student("小红",18);
Student s2=new Student("小黄",18);
Student s3=new Student("小红",20);
Student s4=new Student("小黑",18);
Student s5=new Student("小红",18);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
for( Student i :set){
System.out.println(i.toString());
}
}
}
/*
报错:lang.ClassCastException: cn.itcast_01.Student cannot be cast to java.lang.Comparable
类要实现自然排序就必须实现自然排序接口
*/
类要实现自然排序就必须实现自然排序接口,重写的compareto方法要自己写
public int compareTo(Student o) {
// return 0; 因为底层是红黑树,比根节点小往左子树大往右子树,所以比较得0认为相同大小不会插树 只存进去一个根节点 Student{name='小红', age=18}
// return 1; 同理,怎么进怎么出
// return -1; 按输入顺序倒着输出
//实际应该按照排序规则返回
/* int num=this.age-o.age;
return num;
结果:年龄相同名字相同的也无法存进来
Student{name='小红', age=18}
Student{name='小红', age=20}
*/
int num1=this.age-o.age;
int num=num1==0?this.name.compareTo(o.name):num1; //字符串自带compareto
return num;
}
按照名字比较只需改写类的compareto
@Override
public int compareTo(Student o) {
int num1=this.name.length()-o.name.length();
int num=num1==0?this.name.compareTo(o.name) :num1;
return num;
}
public static void main(String[] args) {
TreeSet<Student> set=new TreeSet<Student>();
Student s1=new Student("小红",18);
Student s2=new Student("小黄黄黄黄黄",18);
Student s3=new Student("小红红",20);
Student s4=new Student("小黑黑黑黑",18);
Student s5=new Student("小红",19);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
for( Student i :set){
System.out.println(i.toString());
}
/*
Student{name='小红', age=18}
Student{name='小红红', age=20}
Student{name='小黑黑黑黑', age=18}
Student{name='小黄黄黄黄黄', age=18}
实现从高到底排序只需要交换是this o
*/
但是这样名字一样并且长度一样的人年龄不同也不一定是一个人,比如19岁的小红没加进去
@Override
public int compareTo(Student o) {
int num1=this.name.length()-o.name.length();
int num2=(num1==0?this.name.compareTo(o.name) :num1);
int num3=(num2==0?this.age-o.age:num2);
return num3;
}
/*
Student{name='小红', age=18}
Student{name='小红', age=19}
Student{name='小红红', age=20}
Student{name='小黑黑黑黑', age=18}
Student{name='小黄黄黄黄黄', age=18}
*/
比较器排序
public class MyComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
int num1=o1.getName().length()-o2.getName().length();
int num2=(num1==0?o1.getName().compareTo(o2.getName()) :num1);
int num3=(num2==0?o1.getAge()-o2.getAge():num2);
return num3;
}
}
public static void main(String[] args) {
// TreeSet<Student> set=new TreeSet<Student>();
TreeSet<Student> set=new TreeSet<Student>(new MyComparator()); //接口类型的参数传一个实现该接口的类的实例
Student s1=new Student("小红",18);
Student s2=new Student("小黄黄黄黄黄",18);
Student s3=new Student("小红红",20);
Student s4=new Student("小黑黑黑黑",18);
Student s5=new Student("小红",19);
实现从高到底排序只需要交换是s1 s2
只用一次就造个类很浪费,匿名内部类正好解决
public static void main(String[] args) {
// TreeSet<Student> set=new TreeSet<Student>();
TreeSet<Student> set=new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num1=o1.getName().length()-o2.getName().length();
int num2=(num1==0?o1.getName().compareTo(o2.getName()) :num1);
int num3=(num2==0?o1.getAge()-o2.getAge():num2);
return num3;
}
});
Student s1=new Student("小红",18);
Student s2=new Student("小黄黄黄黄黄",18);
Student s3=new Student("小红红",20);
Student s4=new Student("小黑黑黑黑",18);
Student s5=new Student("小红",19);
匿名内部类格式
new类名或接口名,大括号里面重写方法(此例子中接口是泛型)
一定要注意,给了排序标准后还要考虑潜在的
比如按总分排序,那总分一样的并不一定是一个人,还要看语数英等
Integer.parseint()可以把string类型转换成int类型