一、实验目的:
(1)掌握List接口及其实现类的特点及相关方法的用法;
(2)掌握Set接口及其实现类的特点及相关方法的用法;
(3)掌握List和Set接口集合元素的遍历。
二、实验内容:
1、编程分别使用使用Iterator迭代器、增强for循环、JDK 8——forEach三种方式遍历输出集合元素。步骤如下:
(1)定义一个测试类ListDemo,在该类创建一个List集合对象list,list对象调用add方法向集合中一次添加3个字符串元素:“hello”、”world” 、”java”;
(2)使用Iterator迭代器遍历输出list集合元素;
(3)使用增强for循环遍历输出list集合元素;
(4)使用JDK 8——forEach遍历输出list集合元素。
2、编程使用List集合存储自定义对象并遍历输出。步骤如下:
(1)定义一个Student类,该类包括姓名和年龄两个成员变量,定义一个带有姓名和年龄两个参数的构造方法,重写Object类的toString()方法,其返回值为姓名及年龄字符串;
(2)定义一个测试类StudentDemo在该类中创建ArrayList集合对象,在集合对象中添加5个学生类Student的对象元素如下:
Student(“王伦”, 21);
Student(“王苑”, 18);
Student(“程宇”, 20);
Student(“毕胜”, 22);
Student(“张雪”, 19);
(3)将学生对象按元素添加到集合的的顺序遍历输出,要求使用泛型。
3、用List集合实现36选7摇号。步骤如下:
(1)创建产生随机数的对象
(2)创建一个存储随机数的List集合。
(3)定义一个统计变量。从0开始。
(4)判断统计遍历是否小于7
是:先产生一个随机数,判断该随机数在集合中是否存在。
如果不存在:就添加,统计变量++。
如果存在:就不搭理它。
否:循环结束
(5)遍历集合。
4、List集合的嵌套及遍历输出。步骤如下:
(1)定义一个Student类,该类包括姓名和年龄两个成员变量,定义一个带有姓名和年龄两个参数的构造方法,重写Object类的toString()方法,其返回值为姓名及年龄字符串;
(2)定义一个测试类ArrayListDemo,在该类中先创建ArrayList集合班级对象smallArray1,添加以下学生类Student的对象元素如下:
Student(“貂蝉”, 19);
Student(“大乔”, 23);
Student(“小乔”, 18);
Student(“孙尚香”, 26);
(3)创建ArrayList集合对象班级smallArray2,添加以下学生类Student的对象元素如下:
Student(“孙二娘”, 25);
Student(“扈三娘”, 27);
Student(“李师师”, 17);
Student(“阎婆惜”, 36);
(4)创建ArrayList集合对象班级smallArray3,添加以下学生类Student的对象元素如下:
Student(“林黛玉”, 19);
Student(“王熙凤”, 35);
Student(“薛宝钗”, 20);
Student(“袭人”, 21);
(5)创建ArrayList<ArrayList>集合对象年级bigArray,将班级对象smallArray1、smallArray2、smallArray3添加到年级集合bigArray
(6)分别使用增强for形式和JDK8的forEach方式嵌套遍历输出班级学生信息。
5、使用HashSet集合存储自定义对象,并保证元素的唯一性。步骤如下:
(1)定义一个Student类,该类包括姓名和年龄两个成员变量,定义一个带有姓名和年龄两个参数的构造方法,重写Object类的toString()方法,其返回值为姓名及年龄字符串;
(2)定义一个测试类HashSetDemo,在该类中创建HashSet集合对象students,再向students集合对象中添加学生类Student的对象元素如下:
Student(“林志玲”, 27);
Student(“王祖贤”, 21);
Student(“张曼玉”, 25);
Student(“关之琳”, 29);
Student(“林志玲”, 27);
Student(“林志玲”, 20);
(3)为保证加入集合中的元素的唯一性(若Student对象的成员变量都相同,则认为是同一对象),在Student类中重写hashCode()方法和equals()方法,并将集合中的学生对象遍历输出,要求使用泛型。
6、使用TreeSet集合存储自定义对象,并实现有序输出(使用自然排序)。步骤如下:
(1)定义一个Student类,该类包括姓名和年龄两个成员变量,定义一个带有姓名和年龄两个参数的构造方法,重写Object类的toString()方法,其返回值为姓名及年龄字符串;
(2)定义一个测试类TreeSetDemo,在该类中创建TreeSet集合对象students,在象students集合对象中添加学生类Student的对象元素如下:
Student (“linqingxia”, 27);
Student (“zhangguorong”, 29);
Student (“wanglihong”, 23);
Student (“linqingxia”, 27);
Student (“liushishi”, 22);
Student (“wuqilong”, 40);
Student (“gaoyuanyuan”, 22);
(3)为保证加入集合中的元素的有序性和唯一性(若Student对象的成员变量都相同,则认为是同一对象),Student类实现Comparable接口,重写compareTo(Student s)方法,并将集合中的学生对象有序(按年龄从低到高)遍历输出,要求使用泛型。
7、使用TreeSet集合存储自定义对象,并实现有序输出(使用比较器排序)。步骤如下:
(1)定义一个Student类,该类包括姓名和年龄两个成员变量,定义一个带有姓名和年龄两个参数的构造方法,重写Object类的toString()方法,其返回值为姓名及年龄字符串;
(2)定义一个测试类TreeSetDemo,为保证加入集合中的元素的有序性和唯一性(若Student对象的成员变量都相同,则认为是同一对象),在该类中调用TreeSet的带参构造方法创建TreeSet集合对象students,该参数为Comparator接口的匿名内部类,并在在象students集合对象中添加学生类Student的对象元素如下:
Student (“linqingxia”, 27);
Student (“zhangguorong”, 29);
Student (“wanglihong”, 23);
Student (“linqingxia”, 27);
Student (“liushishi”, 22);
Student (“wuqilong”, 40);
Student (“gaoyuanyuan”, 22);
Student(“linqingxia”, 29);
(3)在Comparator接口的匿名内部类中重写compare(Student o1, Student o2)方法,并将集合中的学生对象有序(按姓名长度从小到大)遍历输出,要求使用泛型。
8、用Set集合实现36选7摇号。步骤如下:
(1)创建随机数对象
(2)创建一个HashSet集合
(3)判断集合的长度是不是小于7
是:就创建一个随机数添加
否:不搭理它
(4)遍历HashSet集合
三、思考题
1、什么是集合,请列举集合中常用的类和接口?
2、请简述TreeSet集合保证唯一性的两种方式
3、Java语言中,List的实现类ArrayList、Vector、LinkedList特点是什么?
4、Java语言中,使用泛型有什么好处?
实验代码:
ArrayList集合的遍历方法见:ArrayList的遍历方法
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
public class ListDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
System.out.println("==================================Iterator迭代器遍历=============================");
//使用Iterator迭代器遍历输出list集合元素
for (Iterator it = list.iterator(); it.hasNext();) {
System.out.println(it.next());
}
System.out.println("====================================增强for循环遍历===========================");
//使用增强for循环遍历输出list集合元素
for (String it : list) {
System.out.println(it);
}
System.out.println("==============================forEach遍历=================================");
//使用JDK 8——forEach遍历输出list集合元素
list.forEach(System.out :: println);
}
}
ArrayList集合的遍历方法见:ArrayList的遍历方法
import java.util.ArrayList;
import java.util.Scanner;
public class StudentDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<Student> list = new ArrayList<Student>();
list.add(new Student("王伦", 21));
list.add(new Student("王苑", 18));
list.add(new Student("程宇", 20));
list.add(new Student("毕胜", 22));
list.add(new Student("张雪", 19));
//遍历
for (Student it : list) {
System.out.println(it);
}
}
}
import java.util.ArrayList;
import java.util.Scanner;
/*
* 学生类
* */
public class Student {
private String name;
private int age;
public Student (String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString () {
return name+age;
}
}
随机数函数Random: 产生一个指定区间的随机数
contains方法: list集合框架中的一种查找某个值是否存在的方法,底层实现是for循环。
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
public class StudentDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//创建产生随机数的对象
Random rand = new Random();
//创建一个存储随机数的List集合
ArrayList<Integer> list = new ArrayList<Integer>();
//定义一个统计变量从0开始
int cnt = 0;
while(cnt < 7) {
int x;
x = rand.nextInt(36);
//contains方法
boolean Exist = list.contains(x);
if(Exist)
continue;
else {
list.add(x);
cnt++;
}
}
System.out.println("36选7摇号如下:");
for (int it : list) {
System.out.print(it + " ");
}
System.out.println();
}
}
ArrayList集合的遍历方法见:ArrayList的遍历方法
import java.util.ArrayList;
import java.util.Scanner;
public class ArrayListDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//班级1 smallArray1
ArrayList<Student> smallArray1 = new ArrayList<Student>();
smallArray1.add(new Student("貂蝉", 19));
smallArray1.add(new Student("大乔", 23));
smallArray1.add(new Student("小乔", 18));
smallArray1.add(new Student("孙尚香", 26));
//班级2 smallArray2
ArrayList<Student> smallArray2 = new ArrayList<Student>();
smallArray2.add(new Student("孙二娘", 25));
smallArray2.add(new Student("扈三娘", 27));
smallArray2.add(new Student("李师师", 17));
smallArray2.add(new Student("阎婆惜", 36));
//班级3 smallArray3
ArrayList<Student> smallArray3 = new ArrayList<Student>();
smallArray3.add(new Student("林黛玉", 19));
smallArray3.add(new Student("王熙凤", 35));
smallArray3.add(new Student("薛宝钗", 20));
smallArray3.add(new Student("袭人", 21));
//年级 bigArray
ArrayList<ArrayList<Student>> bigArray = new ArrayList<ArrayList<Student>>();
bigArray.add(smallArray1);
bigArray.add(smallArray2);
bigArray.add(smallArray3);
//增强for循环遍历
for (ArrayList it : bigArray) {
System.out.println(it);
}
System.out.println("=======================================");
//forEach方式遍历
bigArray.forEach(System.out :: println);
}
}
import java.util.ArrayList;
import java.util.Scanner;
/*
* 学生类
* */
public class Student {
private String name;
private int age;
public Student (String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString () {
return name+age;
}
}
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
public class HashSetDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
HashSet<Student> students = new HashSet<Student>();
students.add(new Student("林志玲", 27));
students.add(new Student("王祖贤", 21));
students.add(new Student("张曼玉", 25));
students.add(new Student("关之琳", 29));
students.add(new Student("林志玲", 27));
students.add(new Student("林志玲", 20));
//增强for循环遍历
for (Student it : students) {
System.out.println(it);
}
}
}
在Student类中重写hashCode()方法和equals()方法
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
/*
* 学生类
* */
public class Student {
private String name;
private int age;
public Student (String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString () {
return name+age;
}
//重写hashCode()方法和equals()方法
@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);
}
}
TreeSet 排序
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
TreeSet<Student> students = new TreeSet<Student>();
students.add(new Student("linqingxia", 27));
students.add(new Student("zhangguorong", 29));
students.add(new Student("wanglihong", 23));
students.add(new Student("linqingxia", 27));
students.add(new Student("liushishi", 22));
students.add(new Student("wuqilong", 40));
students.add(new Student("gaoyuanyuan", 22));
//排序后的 TreeSet 输出
for (Student it : students) {
System.out.println(it);
}
}
}
通过重写 Comparable 接口中的 compareTo() 方法,强制排序,自定义排序规则:按年龄从低到高
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
/*
* 学生类
* */
public class Student implements Comparable<Student> {
private String name;
private int age;
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;
}
@Override
public String toString () {
return name+age;
}
//实现Comparable接口中的compareTo()方法
@Override
public int compareTo (Student age0) {
int age1 = this.getAge();
int age2 = age0.getAge();
int com = age1 - age2; //age升序排列
if(com > 0)
return 1;
else if (com == 0)
return 0;
else
return -1;
}
}
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
TreeSet<Student> students = new TreeSet<Student>();
students.add(new Student("linqingxia", 27));
students.add(new Student("zhangguorong", 29));
students.add(new Student("wanglihong", 23));
students.add(new Student("linqingxia", 27));
students.add(new Student("liushishi", 22));
students.add(new Student("wuqilong", 40));
students.add(new Student("gaoyuanyuan", 22));
students.add(new Student("linqingxia", 29));
//排序后的 TreeSet 输出
for (Student it : students) {
System.out.println(it);
}
}
}
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
/*
* 学生类
* */
public class Student implements Comparable<Student> {
private String name;
private int age;
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;
}
@Override
public String toString () {
return name+age;
}
//实现Comparable接口中的compareTo()方法
@Override
public int compareTo (Student name0) {
int name1 = this.getName().length();
int name2 = name0.getName().length();
int com = name1 - name2; //按姓名长度从小到大
if(com > 0)
return 1;
else if (com == 0)
return 0;
else
return -1;
}
}
HashSet自动去重,只需要检查set.size() 即可,不需要像list一样查询每次的随机数是否重复。
import java.util.*;
public class StudentDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//创建产生随机数的对象
Random rand = new Random();
//创建一个存储随机数的HashSet集合
HashSet<Integer> set = new HashSet<Integer>();
//判断集合的长度是不是小于7
// 是:就创建一个随机数添加
// 否:不搭理它
while(set.size() < 7) {
int x;
x = rand.nextInt(36);
set.add(x);
}
System.out.println("36选7摇号如下:");
for (int it : set) {
System.out.print(it + " ");
}
System.out.println();
}
}
思考题答案
1、什么是集合,请列举集合中常用的类和接口?
答:集合可以看作是一种容器,用来存储对象信息。所有集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。
Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了三个子接口:List、Set、Queue,因此Java集合大致也可分成List、Set、Queue、Map四种接口,常见的实现类分别是ArrayList、LinkedList、ArrayQueue、HashSet、TreeSet、HashMap、TreeMap等。
2、请简述TreeSet集合保证唯一性的两种方式
答:TreeSet 集合是基于红黑树实现的有序集合,它能够保证元素的唯一性。TreeSet 集合内部根据元素的比较结果进行插入和排序,并通过两种方式来保证元素的唯一性:
- 自然排序:TreeSet 要求集合中的元素实现
Comparable
接口,并重写compareTo
方法。通过该方法的比较结果,判断元素的大小和唯一性。如果两个元素的compareTo
方法返回值为 0,则视为相同元素,只保留一个。
例如,如果我们定义了一个存储整数的 TreeSet,集合中的元素会根据自然顺序进行排序,并且确保没有重复的元素。 - 定制排序:如果元素类没有实现
Comparable
接口,或者想要使用不同的比较规则来进行排序,可以通过传入一个Comparator
对象来实现定制排序。
Comparator
是一个比较器接口,可以根据自定义的比较规则对元素进行排序。在创建 TreeSet 时,可以传入Comparator
对象,对集合中的元素进行排序并保证唯一性。
例如,如果我们定义了一个存储字符串长度的 TreeSet,可以传入一个自定义的Comparator
对象来进行基于长度的排序。
通过这两种方式,TreeSet 确保了集合中不会存在相同的元素,同时以有序的方式存储元素。
3、Java语言中,List的实现类ArrayList、Vector、LinkedList特点是什么?
答:
ArrayList特点:底层数据结构是数组,查询快,增删慢。线程不安全,效率高。
Vector特点:底层数据结构是数组,查询快,增删慢。线程安全,效率低。
LinkedList特点:底层数据结构是链表,查询慢,增删快。线程不安全,效率高。
查询多用ArrayList,增删多用LinkedList,如果都多ArrayList。
4、Java语言中,使用泛型有什么好处?
答:1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。
2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。