数组存对象
package CollectionTest; public class Student { //变量私有,给出get方法提供变量 //某些属性成员变量不要让外界任意访问 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; }
//也可以重写toString()方法
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
} }
public class ArrayDemo1 { public static void main(String[] args) { Student[] s = new Student[5]; Student s1 = new Student("zed1",1); Student s2 = new Student("zed2",2); Student s3 = new Student("zed3",3); Student s4 = new Student("zed4",4); Student s5 = new Student("zed5",5); s[0] = s1; s[1] = s2; s[2] = s3; s[3] = s4; s[4] = s5; //下面代码输出哈希码,数组存储的是对象 //for(int i = 0; i < s.length; i++){ // System.out.println(s[i]); //} for(int i = 0; i < s.length; i++){ Student ss = s[i]; System.out.println(ss.getName() + "---" + ss.getAge()); } } }
数组长度是固定的,所以有时候需要用到集合。
为什么出现集合类?
面向对象语言对事物体现都是以对象的形式,所以为了方便对多个对象的操作,java就提供了集合类。
数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的,集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
数组没有length方法,只有length属性。
字符串有length方法。
集合有size方法。
ECLIPSE复制粘贴代码很容易把包一下导过来了,所以要注意。
public class Student { //变量私有,给出get方法提供变量 //某些属性成员变量不要让外界任意访问 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; }
//如果要重写toString()方法,放掉注释 /* public String toString() { return "Student [name=" + name + ", age=" + age + "]"; }*/ }
添加对象到集合的三种方式:
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class CollectionTest2 { public static void main(String[] args) { Collection<Student> c = new ArrayList<>(); // 三种往集合中添加对象的方法 // 方法一 Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); c.add(s1); c.add(s2); //方法二 c.add(new Student("zed3", 3)); c.add(new Student("zed4", 4)); //方法三 使用类中setter方法 Student s5 = new Student(); Student s6 = new Student(); s5.setName("zed5"); s5.setAge(5); s6.setName("zed6"); s6.setAge(6); //如果对象所在类重写了toString()方法,可以直接输出,如果没有重写,输出的是哈希码 System.out.println(c); System.out.println("-----------------------------"); Iterator it = c.iterator(); while(it.hasNext()){ //强制转换成Student类型 Student s = (Student)it.next(); System.out.println(s.getName() + "-----" + s.getAge()); } } }
clear()清空元素
Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); Student s3 = new Student("zed3", 3); c1.add(s1); c1.add(s2); c1.add(s3); Iterator it = c1.iterator(); while(it.hasNext()){ //强制转换成Student类型 Student s = (Student)it.next(); System.out.println("c1" + s.getName() + "--未清空元素---" + s.getAge()); } //移除所有元素 c1.clear(); System.out.println("c1" + "--清空元素---"+ c1);
是否包含某元素contains:
Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); Student s3 = new Student("zed3", 3); c1.add(s1); c1.add(s2); c1.add(s3); Student s8 = new Student("zed8", 8); System.out.println("是否包含某元素: " + c1.contains(s8));//false System.out.println("是否包含某元素: " + c1.contains(s1));//true
判断集合是否为空:
//判断集合是否包含元素,空集合返回true System.out.println("集合中是否包含元素(未使用clear()方法): " + c1.isEmpty()); c1.clear(); System.out.println("集合中是否包含元素(已使用clear()方法): " + c1.isEmpty());
删除指定对象:
Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); Student s3 = new Student("zed3", 3); c1.add(s1); c1.add(s2); c1.add(s3); //删除指定元素 //未清空元素 [Student [name=zed1, age=1], Student [name=zed2, age=2], Student [name=zed3, age=3]] System.out.println("未清空元素 " + c1); c1.remove(s2); //清空元素s2之后 [Student [name=zed1, age=1], Student [name=zed3, age=3]] System.out.println("清空元素s2之后 " + c1);
集合大小size()方法和转换成数组toArray()方法:
Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); Student s3 = new Student("zed3", 3); c1.add(s1); c1.add(s2); c1.add(s3); //集合元素数量 System.out.println(c1.size()); //转换成数组 //强制转换成Student类型 //Student[] s = (Student)c1.toArray(); 这个转换是错误的 Object[] s =c1.toArray(); for(int i = 0; i < s.length; i++){ System.out.println(s[i]); }
求交集、并集等:
Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); Student s3 = new Student("zed3", 3); c1.add(s1); c1.add(s2); c1.add(s3); Student s4 = new Student("zed4", 4); Student s5 = new Student("zed5", 5); Student s6 = new Student("zed6", 6); c2.add(s4); c2.add(s5); c2.add(s6); //将一个集合添加到另一个集合中,添加成功返回true System.out.println("是否添加成功 " + c1.addAll(c2)); for(Student c : c1){ System.out.println(c); } //判断集合中是否包含另一集合所有元素 System.out.println("是否包含另一个集合所有元素 " + c1.containsAll(c2)); //仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作),求交集 //删除掉另一集合不包含的元素,如果删除成功返回true。 System.out.println("求交集 " + c1.retainAll(c2)); System.out.println("求交集删除成功,输出交集 " + c1); //删除c1集合和c2集合的交集 c1.removeAll(c2); System.out.println("删除交集元素之后输出 " + c1);
迭代器
迭代器是遍历集合的一种方式
迭代器是依赖于集合而存在的
迭代器为什么不定义成一个类,而是一个接口?
Java提供很多集合类,这些集合类的数据结构是不同的,存储方式和遍历的方式应该是不同,进而它们的遍历方式也应该不一样。
在真正的具体实现在子类的内部类中
迭代的三种方法:
迭代的时候要注意强制转换数据类型。
Collection<Student> c = new ArrayList<>(); Student s1 = new Student("zed1", 1); Student s2 = new Student("zed2", 2); Student s3 = new Student("zed3", 3); c.add(s1); c.add(s2); c.add(s3); //方法一 Iterator<Student> it = c.iterator(); while(it.hasNext()){ //强制数据类型转换 Student s = (Student)it.next(); System.out.println(s); } //方法二 //这种方法效率最高,for循环完迭代器就编程垃圾了 //for(初始化语句; 条件语句; 此处可以为空) for(Iterator<Student> it = c.iterator(); it.hasNext(); ){ System.out.println(it.next()); } //方法三 for(Object obj : c){ //for each两种方式都可以,如果是调用对象方法的话,要强制进行类型转换 //System.out.println(obj); System.out.println(((Student) obj).getName() + "----" + ((Student) obj).getAge()); }
迭代器中使用remove()方法,删除的是集合中的元素,而不只是迭代器中的。
Iterator<Student> it = c.iterator(); while(it.hasNext()){ System.out.println(it.next()); it.remove(); } System.out.println("迭代器使用remove方法之后,集合中元素的个数为: " +c.size());
上面程序如果先调用remove()方法,再调用next()方法,会抛出IllegalStateException
错误。
Iterator<Student> it = c.iterator(); while(it.hasNext()){ //下面是将it.next()强制转换成Student类型 System.out.println(((Student)it.next()).getName() + "------" + ((Student)it.next()).getAge()); //请注意,上面命令,((Student)it.next()).getName()和((Student)it.next()).getAge()得到的变量不属于同一个对象 //因为getAge()已经是第二次调用next()方法了 }
List
List接口概述
有序的Collection(也成为序列)。此接口用户可以对列表中的每个元素的插入位置进行精确控制。用户可以根据元素的整数索引访问元素,并搜索列表中的元素。
与set不同,列表通常允许重复的元素
List案例
存储字符串并遍历
存储自定义对象并遍历
List集合特点
有序(存储和取出的元素一致),可重复的。
List<String> l = new ArrayList<>(); //可重复,放入取出顺序一致 l.add("java"); l.add("jse"); l.add("jee"); l.add("jee"); Iterator it = l.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
List相比Collection增加的几种方法:
List<String> l = new ArrayList<>(); l.add("1---java"); l.add("2---jse"); l.add("3---jee"); l.add("3---jee"); //在指定位置添加元素 l.add(0, "hello"); Iterator it = l.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("------------------------"); //获取指定位置的元素 System.out.println("获取指定位置的元素 " + l.get(2)); //返回第一次出现位置的索引 System.out.println("第一次出现指定元素的索引 " + l.indexOf("3---jee")); //如果不包含该元素返回-1 System.out.println("第一次出现指定元素的索引,不包含jee,返回-1 : " + l.indexOf("jee")); //返回列表中最后出现指定元素的索引 System.out.println("最后一次出现指定元素的索引 " + l.lastIndexOf("3---jee")); //移除列表中指定位置的元素,并返回该元素 System.out.println("移除指定位置的元素并返回 " + l.remove(4)); System.out.println(l); //用指定元素替换列表中指定元素,并返回 System.out.println("替换元素" + l.set(3, "JavaEE")); System.out.println(l); //List<E> subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图 List l2 = l.subList(1, 3); System.out.println(l2);
List特有遍历功能:
/* List特有遍历功能: size()和get()方法结合 */ for(int i = 0; i < list.size(); i++){ String s = (String)list.get(i); System.out.println(s); }
ListIterator一般不使用
List<String> l = new ArrayList<>(); l.add("1---java"); l.add("2---jse"); l.add("3---jee"); //listIterator继承了Iterator,所以可以用hasNext()和Next() //这样没有任何意义,要实现逆向遍历必须先正向遍历,因为指针在正向开始处 ListIterator lit = l.listIterator(); while(lit.hasPrevious()){ String s = (String)lit.previous(); System.out.println(s); } }
迭代器是依赖于集合存在的,在判断成功后,集合中新添加了元素. 而迭代器却不知道,所以就报错了。这个错叫并发修改异常 其实这个问题描述的是迭代器遍历元素的时候,通过集合是不能修改元素的。 List<String> l = new ArrayList<>(); l.add("1---java"); l.add("2---jse"); l.add("3---jee"); Iterator it = l.iterator(); while(it.hasNext()){ String s = (String)it.next(); //此处会发生并发修改异常 if("world".equals(s)){ list.add("javaee"); } } 如何解决呢? A、迭代器遍历的时候,用迭代器修改元素; 元素是跟在刚才迭代元素的后面的 List<String> l = new ArrayList<>(); l.add("1---java"); l.add("2---jse"); l.add("3---jee"); ListIterator it = l.listLterator(); while(it.hasNext()){ String s = (String)it.next(); if("world".equals(s)){ it.add("javaee"); } } B、集合遍历元素,集合修改元素(普通for)
List:
ArrayList:底层是数组 增删慢 查询快 线程不安全 效率高
Vector:底层是数组 增删慢 查询快 线程安全 效率低
LinkedList:底层是链表 增删快 查询慢 线程不安全 效率高