Collection单列集合复习
集合
(Map中还有LinkedHashMap和TreeMap(二叉树存储))
Collection集合的遍历
1.集合转换成数组,然后再对数组进行遍历
Object[] |
toArray() 返回一个包含此集合中所有元素的数组。 |
Object[] toArray();
2.获取迭代器、当于一个爪子
iterator() 返回此集合中的元素的迭代器。 |
|||
boolean |
hasNext() 如果迭代具有更多元素,则返回 true 。 |
||
next() 返回迭代中的下一个元素。 |
hesNext:判断是否有下一个元素
next:获取下一个元素,还会移动迭代器的位置
3.高级for循环(底层实现就是迭代器)
Collection集合三种通用遍历方式实例:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test02 {
public static void main(String[] args) {
Collection<Student> coll = new ArrayList<Student>();
//Collection是接口,不能创建对象,所以只能创建子类对象(多态)
Student s1 = new Student("熊落落",21);
Student s2 = new Student("杨梦梦",22);
Student s3 = new Student("李鹏鹏",25);
Student s4 = new Student("崔美娟",23);
Student s5 = new Student("孙二娜",22);
Student s6 = new Student("红果果",21);
coll.add(s1);coll.add(s2);
coll.add(s3);coll.add(s4);
coll.add(s5);coll.add(s6);
System.out.println("******第一种遍历方式******");
//单列集合通用的第一种遍历方式(调用toArray()方法,转为数组,然后遍历)
Object[] objs = coll.toArray();//注意单列集合的这个toArray()方法返回值是一个Object类型的数组
for(Object obj : objs) {
/*String string = obj.toString();
System.out.println(string);
多态(父类的引用指向子类的对象)中的成员方法的访问特点
1.编译看左边,运行看右边
2.编译的时候,要看父类中是否存在该方法,如果存在,编译通过,否则编译报错。
3.运行的时候,要运行子类的重写的方法,如果没有重写的方法,执行父类的方法。*/
Student stu = (Student)obj;
/*不强转为子类对象的引用stu时,obj只能调用两者共有的方法中的子类对象的方法而不能调用Student类中特有的方法.
这其实是多态的访问特点,好好学习吧!学完就忘,像个憨憨,丢人不*/
System.out.println(stu);
}
System.out.println("******第一种遍历方式******");
System.out.println();
System.out.println("******第二种遍历方式******");
//单列集合通用的第二种遍历方式(采用Iterator迭代器进行遍历)
Iterator<Student> it = coll.iterator();//使用泛型,声明迭代器类型
//Iterator迭代器是个接口,不能直接创建对象,但可以通过集合调用iterator()方法创建对象
while(it.hasNext()) {//如果集合中还有元素
System.out.println(it.next());//获取集合中下一个元素
}
System.out.println("******第二种遍历方式******");
System.out.println();
System.out.println("******第三种遍历方式******");
//单列集合通过的第三种遍历方式(采用高级for循环进行遍历)
for(Student stu : coll) {//由于前面声明了泛型,这里遍历就省去了很多麻烦
System.out.println(stu);
}
System.out.println("******第三种遍历方式******");
}
}
class Student{
private String name;
private int age;
public Student() {}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public String toString() {//由于在打印对象名的时候,虚拟机会自动调用toString方法,打印对象地址
//所以可以重写toString()方法,打印出我们希望看到的结果!注意:这个方法的返回类型是String类型!
//调用是虚拟机自动完成的!
return "name = " + name + ",age = " + age;
}
}
List集合中特有的遍历方式实例:
(使用size(),get()等方法进行遍历
import java.util.ArrayList;
import java.util.List;
//List集合中特有的遍历(使用size(),get()等方法进行遍历)
public class Test03 {
public static void main(String[] args) {
/*List list = new ArrayList();
list.add(0, 3);
list.add(0, 4);
System.out.println(list);
list.remove(0);
System.out.println(list);
list.set(0, 6);
System.out.println(list);
System.out.println(list.get(0));*/
List list = new ArrayList();
list.add("我和我的祖国");
list.add("一刻也不能分割");
list.add("只愿天长地久");
list.add("与我意中人儿紧相随");
list.add(123);
list.add(456);
for(int n = 0;n < list.size();n++) {
System.out.println(list.get(n));
}
}
}
并发修改异常
java.util.ConcurrentModificationException
原因:在使用迭代器操作集合时,集合本身也在操作集合,所以出现并发修改的异常。
解决方式:要么集合本身在操作集合,要么迭代器在操作集合。
Vector:
public class Test04 {
public static void main(String[] args) {
Vector vector = new Vector();
vector.addElement("abc");
vector.addElement("bbb");
vector.addElement("ccc");
vector.addElement("ddd");
System.out.println(vector);
System.out.println(vector.removeElement("abc"));
System.out.println(vector);
//遍历 枚举器
Enumeration elements = vector.elements();
while(elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
}
}
枚举器中的两个方法
boolean |
测试此枚举是否包含更多元素。 |
如果此枚举对象至少有一个要提供的元素,则返回此枚举的下一个元素。 |
LinkedList练习一:
import java.util.LinkedList;
public class LinkedList01 {
public static void main(String[] args) {
LinkedList ll = new LinkedList();
ll.addFirst("abc");
ll.addFirst("aaa");
ll.addLast("ccc");
System.out.println(ll);
//[aaa, abc, ccc]
Object obj = ll.removeLast();
System.out.println(obj);
//ccc
System.out.println(ll);
//[aaa, abc]
System.out.println(ll.getFirst());
//aaa
}
}
LinkedList练习二:
模拟栈和队列的操作
import java.util.LinkedList;
/*4.模拟栈和队列的操作(LinkedList)
栈:先进后出 自定义异常抛出
队列:先进先出*/
public class Test02LinkedList {
public static void main(String[] args) throws Exception {
MyStack<String> ms = new MyStack<String>();
ms.push("123");
ms.push("我爱你,祖国!");
ms.push("wakaka");
System.out.println(ms);
System.out.println(ms.pop());
System.out.println(ms.pop());
System.out.println(ms.pop());
System.out.println(ms.pop());
}
}
class MyStack<E>{//栈本身就是一种操作受限的链表
LinkedList<E> linkedList = new LinkedList<E>();
public MyStack() {}
public void push(E e) {
linkedList.addLast(e);//进栈,加元素
}
public E pop() throws Exception {
if(isEmpty()) {
throw new MyStackEmptyException("感觉身体被掏空!");
}
return linkedList.removeLast();//这里出栈应该用移除来代替
}
public boolean isEmpty() {
return linkedList.isEmpty();
}
}
class MyStackEmptyException extends Exception{
public MyStackEmptyException(String str) {
super(str);
}
}
Set:元素无序,不重复
练习一:
随机生成10个20-40之间的(不重复的)随机数,存储在合适的集合中,并且进行遍历
/*6.练习
随机生成10个20-40之间的(不重复的)随机数,存储在合适的集合中,并且进行遍历*/
public class Test01Set {
public static void main(String[] args) {
Random r = new Random();
Set<Integer> set = new HashSet<Integer>();
while(set.size()<10) {
int num = r.nextInt(21)+20;
set.add(num);
}
for(Integer n : set) {
System.out.println(n);
}
}
}
练习二:
键盘录入一个字符串,输出其中的字符,相同的字符只输出一次。
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
/*2.键盘录入一个字符串,输出其中的字符,相同的字符只输出一次。*/
public class Test02Set {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个字符串:");
String line = sc.nextLine();
char[] chs = line.toCharArray();
Set<Character> set = new HashSet<Character>();
for(int n = 0;n < chs.length;n++) {
char c = chs[n];
set.add(c);
}
for(Character c : set) {
System.out.println(c);
}
}
}
HashSet
哈希表,HashSet保证了元素的唯一性,值相同的元素都去掉。
HashSet存储自定义类型的元素
如何保证元素唯一呢?
hashCode()
|--哈希值相同:再进去比较equals()
|--equals值返回为true:认为是重复元素,不进行存储
|--equals值返回为false:认为不是重复元素,进行存储
|--哈希值不相同:直接进行存储
HashSet保证自定元素唯一性的实例:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
//测试HashSet如何保证自定义元素唯一
public class Test01HashSet {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Student("熊落落",21));
hs.add(new Student("杨梦梦",22));
hs.add(new Student("李鹏鹏",25));
hs.add(new Student("孙二娜",24));
hs.add(new Student("熊落落",23));
hs.add(new Student("熊落落",21));
Iterator it = hs.iterator();
while(it.hasNext()) {
Student stu = (Student)it.next();
System.out.println(stu);
}
/*输出结果:
29015722
26296872
26711470
23119401
29015722
29015722
name = 熊落落,age = 21
name = 熊落落,age = 23
name = 杨梦梦,age = 22
name = 李鹏鹏,age = 25
name = 孙二娜,age = 24
根据定义的规则,线比较对象name的哈希码值,如果不一致,直接存储,
如果一致,再去比较姓名和年龄的值是否一样,不一致,存储.一致,不存储.
*/
}
}
class Student{
private String name;
private int age;
public Student() {}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public String toString() {//由于在打印对象名的时候,虚拟机会自动调用toString方法,打印对象地址
//所以可以重写toString()方法,打印出我们希望看到的结果!注意:这个方法的返回类型是String类型!
//调用是虚拟机自动完成的!
return "name = " + name + ",age = " + age;
}
public int hashCode() {
/*Objects.hash()与Objects.hashCode()
* static int hash(Object... values)
为(多个)输入值序列生成哈希码,最好不要输入单个(返回的可能不是哈希码值);
static int hashCode(Object o)
返回单个输入值的哈希码值 */
/*System.out.println(Objects.hashCode(age));
return Objects.hashCode(age);*///如果年龄的哈希值一样(int类型的哈希码值就是它本身,没什么意义
System.out.println(Objects.hashCode(name));
return name.hashCode();//字符串是引用数据类型,可直接调用hashCode()方法
}
public boolean equals(Object obj) {//注意,它的返回值是boolean类型
Student stu = (Student)obj;
return name.equals(stu.name)&&age==stu.age;//认真,别写错了
//比较姓名和年龄是否一样
}
}
TreeSet:
也是一个Set子类,也可以保证元素的唯一,底层结构是二叉树。
既可以保证元素唯一,也可能进行自动排序
TreeSet可以保证元素唯一,也可以自动排序。
|--使元素本身具有比较性,自定义类实现Comparable接口,重写comparTo()方法
|--使集合本身具有比较性,自定义比较器实现Comparator接口,重写compare()方法
如果两者同时存在呢???
使用集合本身的比较性,元素本身的比较效失效!!
TreeSet集合保证自定义元素唯一的两种方式
TreeSet集合保证自定义对象唯一的实例一():
自定义类实现一个Comparable接口,重写compareTo()
返回值:正整数、零、负整数
题目:如果本书的书名和价格一致认为同一本书,不进行存储
按照书名进行升序排序,如果书名相同,按照价格降序排序(用TreeSet存储)
import java.util.Iterator;
import java.util.TreeSet;
/*题目:如果本书的书名和价格一致认为同一本书,不进行存储
按照书名进行升序排序,如果书名相同,按照价格降序排序(用TreeSet存储)*/
public class Test01TreeSet {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
Book b1 = new Book("活着",25);
Book b2 = new Book("果宝",21);
Book b3 = new Book("王者",22);
Book b4 = new Book("活着",23);
Book b5 = new Book("活着",25);
ts.add(b1);ts.add(b2);
ts.add(b3);ts.add(b4);
ts.add(b5);
Iterator it = ts.iterator();
while(it.hasNext()) {
Book b = (Book)it.next();
System.out.println(b);
}
}
}
class Book implements Comparable{
String bookName;
double bookPrice;
public Book() {
super();
// TODO Auto-generated constructor stub
}
public Book(String bookName, double bookPrice) {
super();
this.bookName = bookName;
this.bookPrice = bookPrice;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public double getBookPrice() {
return bookPrice;
}
public void setBookPrice(double bookPrice) {
this.bookPrice = bookPrice;
}
@Override
public String toString() {
return "Book [bookName=" + bookName + ", bookPrice=" + bookPrice + "]";
}
/*题目:如果本书的书名和价格一致认为同一本书,不进行存储
按照书名进行升序排序,如果书名相同,按照价格降序排序(用TreeSet存储)*/
public int compareTo(Object obj) {
Book b = (Book)obj;
int result = bookName.compareTo(b.getBookName());
if(result==0) {//如果书名一致,判断价格
return -(new Double(bookPrice).compareTo(new Double(b.getBookPrice())));
//降序 Double也继承了Compareble类,重写了compareTo方法,所以可以这么写
}else if(result > 0) {
return 1;//名字升序
}
return -1;
}
}
运行结果:
Book [bookName=果宝, bookPrice=21.0]
Book [bookName=活着, bookPrice=25.0]
Book [bookName=活着, bookPrice=23.0]
Book [bookName=王者, bookPrice=22.0]
TreeSet集合保证自定义对象唯一的实例二():
TreeSet集合本身具有比较性,在创建集合对象时添加一个比较器,自定义比较器实现Comparator,重写compare方法,使添加的元素按照集合本身的比较规则去进行添加
题目:如果本书的书名和价格一致认为同一本书,不进行存储
按照书名进行降序排序,如果书名相同,按照价格升序排序(用TreeSet存储)
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*题目:如果本书的书名和价格一致认为同一本书,不进行存储
按照书名进行降序排序,如果书名相同,按照价格升排序(用TreeSet存储)*/
public class Test02TreeSet {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new Comparator() {
public int compare(Object o1,Object o2) {
Book b1 = (Book)o1;
Book b2 = (Book)o2;
int result = b1.getBookName().compareTo(b2.getBookName());
if(result==0) {
return new Double(b1.getBookPrice()).compareTo(new Double(b2.getBookPrice()));
}else if(result > 0) {
return -1;
}
return 1;
}
});
Book b1 = new Book("活着",25);
Book b2 = new Book("果宝",21);
Book b3 = new Book("王者",22);
Book b4 = new Book("活着",23);
Book b5 = new Book("活着",25);
ts.add(b1);ts.add(b2);
ts.add(b3);ts.add(b4);
ts.add(b5);
Iterator it = ts.iterator();
while(it.hasNext()) {
Book b = (Book)it.next();
System.out.println(b);
}
}
}
class Book implements Comparable{
String bookName;
double bookPrice;
public Book() {
super();
// TODO Auto-generated constructor stub
}
public Book(String bookName, double bookPrice) {
super();
this.bookName = bookName;
this.bookPrice = bookPrice;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public double getBookPrice() {
return bookPrice;
}
public void setBookPrice(double bookPrice) {
this.bookPrice = bookPrice;
}
@Override
public String toString() {
return "Book [bookName=" + bookName + ", bookPrice=" + bookPrice + "]";
}
/*题目:如果本书的书名和价格一致认为同一本书,不进行存储
按照书名进行升序排序,如果书名相同,按照价格降序排序(用TreeSet存储)*/
public int compareTo(Object obj) {
Book b = (Book)obj;
int result = bookName.compareTo(b.getBookName());
if(result==0) {//如果书名一致,判断价格
return -(new Double(bookPrice).compareTo(new Double(b.getBookPrice())));
//降序 Double也继承了Compareble类,重写了compareTo方法,所以可以这么写
}else if(result > 0) {
return 1;//名字升序
}
return -1;
}
}
运行结果:
Book [bookName=王者, bookPrice=22.0]
Book [bookName=活着, bookPrice=23.0]
Book [bookName=活着, bookPrice=25.0]
Book [bookName=果宝, bookPrice=21.0]
可见,当两者同时存在时,TreeSet会按照Comparator定义的规则去存储,排序