集合类的由来:
当我们需要把很多的对象存储起来时,并且不知道具体数量,就使用集合进行存储。
集合的特点:
- 用于储存对象的容器。
- 集合的长度可变
- 集合中不可以存储基本数据类型
集合与数组的区别:
- 数组长度是不可变的,集合可以。
- 数组可一存储基本数据类型和对象,集合只能存储对象
集合框架的构成:
Collection接口
Clooection接口是List、set的父接口,在该接口里定义的方法既可以操作List集合,也可以操作Set集合。Clooection抽取他们的共同特点。
clooection的常见方法:
1、添加:
boolean add(Object obj);
boolean addAll(Clolection coll) ;
2、删除:
boolean remove(Object obj) ;
boolean removeAll(Colection col) ;
void Clear() ;
3、判读:
boolean contains(Object obj) ;
boolean containsAll(Collection coll) ;
boolean isEmpty() ;判断集合中是否有元素。
4、获取
int size() ;
Iterator iterator() ;
取出元素的工具:迭代器
迭代器是依赖于具体容器的,迭代器是容器的内部类。因为每个容器的存储数据的结构不同,Iterator在每个容器中的实现方式都不一样。
对于使用容器来说,具体的实现并不重要,我也只要通过itrator()方法拿到Iterator对象就可以了。
Iterator的hasNext() 判断是否有下一个元素,next()拿到元素。
5、其他
boolean retainAll(Collection coll) ;取交集
Array toArray() ;讲集合转换成数组。
public class CollectonTest {
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<String>();
Collection<String> c2 = new ArrayList<String>();
c1.add("aaa");
c1.add("bbb");
c1.add("ccc");
System.out.println(c1);
//添加单个元素,添加在末尾
c2.add("ccc") ;
//将一个集合整个添加进去
c2.addAll(c1) ;
System.out.println(c2);
c1.remove("aaa");
//移除c2集合中包含c1中的元素
c2.removeAll(c1);
System.out.println(c1);
System.out.println(c2);
System.out.println("isEmpty:"+c1.isEmpty()+c1.size());
//将整个集合的元素清空
c1.clear();
c2.clear();
c1.add("a");
c1.add("b");
c2.add("a");
c2.add("c");
//取交集,c1保存结果
c1.retainAll(c2);
System.out.println(c1);
System.out.println(c2);
}
}
使用Iterator遍历集合中的元素:
public class IteratorTest {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>() ;
c.add("aaaa1");
c.add("aaaa2");
c.add("aaaa3");
c.add("aaaa4");
System.out.println(c);
//使用Iterator迭代器遍历集合中的元素
Iterator<String> iterator = c.iterator();
while(iterator.hasNext()){
String s = iterator.next();
System.out.println(s);
}
//使用for循环,Iterator作为局部变量,for结束后Iterator就可以被回收了
//更节约内存
for(Iterator<String> i =c.iterator();i.hasNext();){
System.out.println(i.next());
}
}
}
结果:
List、set:
List和set是Collection的一级子接口
List:存入的元素有顺序,每个元素都有索引角标,允许元素重复。
Set:元素不能重复,没有顺序。
List的常见方法:
1、添加:
void add(index,element) ;
void add(index,collection) ;
2、删除
Object remove(index) ;
3、修改:
Object set(index ,element)
4、获取:
Object get(index) ;
int indexOf(Object) ;
int lastIndex(Object)
List subList(form ,to) ;
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>() ;
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
list.remove(3);
System.out.println(list);
list.set(2, "ABC3") ;
System.out.println(list);
//根据角标,拿到对于的元素
System.out.println("NO.1 is"+list.get(0));
//得到元素对应的角标
System.out.println("abc2 no is "+list.indexOf("abc2")) ;
list.add("abc2");
//lastindexOf :这个元素最后出现位置的角标。
System.out.println("abc lastIndex is"+list.lastIndexOf("abc2"));
System.out.println(list);
//form开始,to之前结束
List<String> subList = list.subList(1, 3);
System.out.println(subList);
//List遍历集合的另一种方式
//根据角标来进行,类似于数组。
for(int i=0 ;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
结果:
使用Iterator修改集合:
public class ListIteratorTexst {
public static void main(String[] args) {
List<String> list = new ArrayList<String>() ;
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
Iterator<String> iter = list.iterator();
//使用Itertar修改集合
while(iter.hasNext()){
if(iter.next().equals("abc4"))
iter.remove();
}
System.out.println(list);
}
}
注意:当使用Iterator遍历时同时操作原集合,会报错
public class ListIteratorTexst {
public static void main(String[] args) {
List<String> list = new ArrayList<String>() ;
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
Iterator<String> iter = list.iterator();
//Iterator遍历时会操作list集合
//当遍历的元素是abc4时,list自己也在操作list集合
//这时两个对象同时操作一个资源,会发生java.util.ConcurrentModificationException
while(iter.hasNext()){
if(iter.next().equals("abc4"))
list.add("adbc");
}
System.out.println(list);
}
}
可以使用Iterator接口的子接口ListIterator来完成迭代过程中对元素的更多操作。
ListIterator是List类中特有的。
public class ListIteratorTexst {
public static void main(String[] args) {
List<String> list = new ArrayList<String>() ;
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
System.out.println(list);
//拿到ListIterator
ListIterator<String> iter = list.listIterator();
// iter.hasPrevious();判断前面有元素没有
// iter.previous();取出前一个元素
//
// iter.hasNext();判断有下一个元素没有
// iter.next();取出下一个元素
//
// iter.set(element); 修改指定的元素
//
// iter.remove();移除元素
while(iter.hasNext()){
if(iter.next().equals("abc4"))
iter.add("asd");
}
System.out.println(list);
}
}
结果:
Vector、ArrayList、LinkedList:
List:
|--Vector:内部是数组结构数据,是同步。增删、查询都很慢。
|--ArrayLiat: 内部是数组结构数据,不是同步的,替代Vector,查询速度很快。
|--LinkedList :内部是链表结构数据,不是同步的。增删元素很快,查询慢。
Vector里面有一个Enumeration,类似Iterator对象,也可以用来遍历集合。
public class VectorTest {
public static void main(String[] args) {
Vector<String> v = new Vector<String>() ;
v.add("abc1") ;
v.add("abc2") ;
v.add("abc3") ;
v.add("abc4") ;
v.add("abc5") ;
//使用Enumeration 遍历集合
Enumeration<String> enumeration = v.elements();
while(enumeration.hasMoreElements()){
System.out.print(enumeration.nextElement()+" ");
}
System.out.println("\n----------------------------");
//使用Iterator遍历集合
Iterator<String> iterator = v.iterator() ;
while(iterator.hasNext()){
System.out.print(iterator.next()+" ");
}
}
}
结果:
LinkedList:
方法:
addFirst(); 添加元素到最前面 。
addLast(); 添加元素到末尾。
getFirst() : 取得第一的元素。
getLast :取得最后一个元素。
使用LinkedList模拟一个堆栈和队列:
public class LinkedListTest {
public static void main(String[] args) {
MyStack<String> stack = new MyStack<String>() ;
stack.put("abc1");
stack.put("abc2");
stack.put("abc3");
System.out.println(stack);
while(!stack.isEmpty()){
System.out.println(stack.get());
}
MyQuence<String> quence = new MyQuence<String>() ;
quence.put("abc1");
quence.put("abc2");
quence.put("abc3");
System.out.println(quence);
while(!quence.isEmpty()){
System.out.println(quence.get());
}
}
}
/*
* 栈的特点是先进后出。
*/
class MyStack<T>{
private LinkedList<T> list ;
public MyStack(){
list = new LinkedList<T>();
}
//进栈方法,每次进来的元素只能添加在末尾
public void put(T t){
list.addLast(t);
}
//出栈方法,每次只能从末尾移除
public T get(){
return list.removeLast();
}
public boolean isEmpty(){
return list.isEmpty();
}
@Override
public String toString() {
return list.toString();
}
}
/*
* 队列:先进先出
*/
class MyQuence<E>{
LinkedList<E> list ;
MyQuence(){
list = new LinkedList<E>() ;
}
//每次进来,添加到末尾
public void put(E e){
list.addLast(e);
}
//每次取出时,取最前面的元素
public E get(){
return list.removeFirst();
}
public boolean isEmpty(){
return list.isEmpty();
}
@Override
public String toString() {
return list.toString();
}
}
结果:
set接口:
set:元素不可以重复,是无顺序的。
|--HashSet :内部数据结构是哈希表,是不同步的。
|--TreSet:可以对Set集合中的数据进行排序,是不同步的。
HashSet:
HashSet,是根据hashcode值和equals方法判读元素是不是重复的。
元素进来时,先计算出hashcode的值,如果hashcode值没有重复的就直接放进来,否则不妨进来。
当hashcode值相等时,判读equals方法,当相等时则视为同一个元素,不放进来;如果不相等,则放进来,并放在hashcode值相等的区域。
public class SetTest {
public static void main(String[] args) {
Set<Student> set = new HashSet<Student>() ;
Student stu1 = new Student("zhangsan",10) ;
Student stu2 = new Student("zhangsan",10) ;
Student stu3 = new Student("lisi",10) ;
set.add(stu1);
set.add(stu2);
set.add(stu3);
System.out.println(set);
}
}
class Student{
int age ;
String name ;
public Student(String name ,int age){
this.age = age ;
this.name = name ;
}
public String getname(){
return name;
}
@Override
public int hashCode() {
System.out.println(this.name+" hash code..");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println(this.name+"..equals.."+((Student) obj).getname());
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Student [age=" + age + ", name=" + name + "]";
}
}
结果:
第一个人张三进来时计算hashcode值,并将张三存到这个hashcode值得区域。
第二个人张三进来,计算hashcode值,然后和前面一比 相等,再用equals方法比较。
第三个人进来,计算hashcode值,没有重复值,直接存进来。
将一个集合中的重复元素去掉<span style="font-family:SimSun;font-weight: normal;">import java.util.*;
public class SingleElementTest {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
Student stu1 = new Student("zhangsan",10) ;
Student stu2 = new Student("zhangsan",10) ;
Student stu3 = new Student("lisi",10) ;
Student stu4 = new Student("wangwu",20) ;
list.add(stu1);
list.add(stu2);
list.add(stu3);
list.add(stu4);
List<Student> singElement =getSingleElement(list);
System.out.println(singElement);
}
public static <T> List<T> getSingleElement(List<T> pList) {
//新建一个容器,用于装结果。没从原来的集合中取出一个元素,都判断结构集合中是不有了
//如果有了就不放进来,没有则放进来。
List<T> list = new ArrayList<T>();
for(T t:pList){
//contains 方法其实也是通过equals方法比较是否相同的。
if(list.contains(t))
continue;
list.add(t) ;
}
return list ;
}
}</span>
结果:
<span style="font-family:SimSun;font-weight: normal;">import java.util.*;
public class SingleElementTest {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
Student stu1 = new Student("zhangsan",10) ;
Student stu2 = new Student("zhangsan",10) ;
Student stu3 = new Student("lisi",10) ;
Student stu4 = new Student("wangwu",20) ;
list.add(stu1);
list.add(stu2);
list.add(stu3);
list.add(stu4);
List<Student> singElement =getSingleElement(list);
System.out.println(singElement);
}
public static <T> List<T> getSingleElement(List<T> pList) {
//新建一个容器,用于装结果。没从原来的集合中取出一个元素,都判断结构集合中是不有了
//如果有了就不放进来,没有则放进来。
List<T> list = new ArrayList<T>();
for(T t:pList){
//contains 方法其实也是通过equals方法比较是否相同的。
if(list.contains(t))
continue;
list.add(t) ;
}
return list ;
}
}</span>
TreSet:
TreSet判断元素是否唯一的方式:
根据比较方法返回的结果是不是0,是0则视为相同元素,就不存。
TreeSet对元素进行排序的方式一:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法。
如果不按照元素自身的自然顺序排序,或是元素本身不具备比较性则使用下面的方式。
TreeSet第二种排序方式:
让集合自身具备比较性,定义一个实现了Comparator接口,覆盖compare放,将该类对象作为参数传递进集合的构造方法中。
public class TreeSetTest {
public static void main(String[] args){
TreeSet<Student> set = new TreeSet<Student>();
Student stu1 = new Student("zhangsan",10) ;
Student stu2 = new Student("zhangsan",11) ;
Student stu3 = new Student("lisi",10) ;
Student stu4 = new Student("wangwu",20) ;
set.add(stu1);
set.add(stu2);
set.add(stu3);
set.add(stu4);
for(Student stu :set){
System.out.println(stu);
}
System.out.println("---------------------------");
TreeSet<Student> set2 = new TreeSet<Student>(new MyComparator());
set2.add(stu1);
set2.add(stu2);
set2.add(stu3);
set2.add(stu4);
for(Student stu :set2){
System.out.println(stu);
}
}
}
/*
* 自定义的比较器类
* 实现Comparator接口,从写,conpare()方法
* 按年龄排序,年龄相同,按姓名排序
*/
class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2 ;
int temp = s1.getage()-s2.getage();
return temp==0?s1.getname().compareTo(s2.getname()):temp;
}
}
class Student implements Comparable{
int age ;
String name ;
public Student(String name ,int age){
this.age = age ;
this.name = name ;
}
public String getname(){
return name;
}
public int getage(){
return age;
}
//Student本身的比较方法
//先按姓名排序,姓名相同,按年龄排序
@Override
public int compareTo(Object o) {
System.out.println(this.name+"..compareTo.."+((Student) o).getname());
int temp = this.name.compareToIgnoreCase(((Student) o).getname());
return temp== 0?this.age-((Student) o).getage():temp;
}
@Override
public int hashCode() {
System.out.println(this.name+" hash code..");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println(this.name+"..equals.."+((Student) obj).getname());
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "[name=" + name + ",age=" + age + "]";
}
}
结果: