作业09-集合与泛型
1.本周学习总结
1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容。
- 一、泛型的基本概念
泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
- 二、关于向上转型和向下转型
为什么会提到这个呢,主要是因为在没有出现泛型之前,程序员是对Object引用进行“向下转型”和“向上转型”操作来实现某些类型的转换。“向上转型”是安全的,但是在“向下转型中”若是用错了类型就会出现异常。如:
package other;
public class Test {
private Object a; // 定义Object类型成员变量
public Object getA() { // 设置get方法
return a;
}
public void setA(Object a) { // 设置set方法
this.a = a;
}
public static void main(String[] args) {
Test t = new Test();
t.setA(new Float(12.3));
Integer f = (Integer)(t.getA());
System.out.println(f);
}
}
因为不存在语法错误,所以编译器不会报错,但是在运行的时候会出现ClassCastException的异常。由此看来,“向下转型”操作通常会出现问题,而泛型机制可以很好的解决这个问题。
- 三、泛型的常规用法
1.泛型类的定义
泛型类是具有一个或多个类型变量的类,语法如下:
MutiOverClass<T1,T2> //MutiOverClass为泛型类名称
2.泛型接口的定义
泛型接口和泛型类的定义方法类似,语法如下:
interface MutiOverInte<T1,T2>
3.泛型方法的定义
泛型方法的定义就比较复杂,其语法如下:
图片引用自这
- 四、类型通配符
在泛型机制中,提供了类型通配符,其主要作用是在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类。要声明这样一个对象可以使用“?”通配符来表示,同时使用extends关键字来对泛型加以限制。
其语法如下:
泛型类名称<? extends List> a = null
//<? extends List>表示类型未知,当需要使用该泛型对象时,可以单独实例化
另外,泛型类不止可以向下限制,还可以进行向上限制,这就要用到super
关键字即可,如泛型类名称<? super List> a = null
1.2 选做:收集你认为有用的代码片段
//菱形语法
List<String> strList = new ArrayList<String>(); //java7以前
List<String> strList = new ArrayList<>(); //java7时
//java的foreach语句
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
numbers.stream().filter(i -> i % 2 == 0)..forEach(System.out::println);
//使用Map.Entry对元素进行遍历,并使用匿名内部类实现对map中元素的排序
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (o1.getValue() == o2.getValue()) {
return o1.getKey().compareTo(o2.getKey());
}
return o2.getValue() - o1.getValue();
}
});
- 书面作业
本次作业题集集合
1. List中指定元素的删除(题集题目)
1.1 实验总结。并回答:列举至少2种在List中删除元素的方法。
答:这题比较容易,就是一开始遍历List的时候,没有考虑到从0开始遍历删除元素时后面元素下标的变化,导致有些本该删除的元素没有被删除。
在List中删除元素的方法:
//删除list中的偶数元素
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<10;i++){ //往list中添加元素
list.add(i);
}
//方法一:从前往后遍历删除元素
for(int i=0;i<list.size();i++){
if(list.get(i)%2==0){
list.remove(i);
i--;
}
}
//方法二:反向遍历删除元素
for(int i=list.size()-1;i>=0;i--){
if(list.get(i)%2==0)
list.remove(i);
}
//方法三:利用Iterator删除元素
for(Iterator<Integer> iterator = list.iterator();iterator.hasNext(); ){
int e = iterator.next();
if(e%2==0)
iterator.remove();
}
//方法四:新建一个新集合来删除元素
List<Integer> newList = new ArrayList<Integer>();
for(Integer e:list){
if(e%2==0)
newList.add(e);
}
list.removeAll(newList);
//方法五:利用removeIf删除某一个元素
list.removeIf(e -> e%2==0);
//输出删除完成后列表(以上五个运行结果都一样,就贴一张图了)
System.out.println(list);
运行结果:
//方法六:利用forEach()过滤元素
list.stream().filter(e ->e%2==1).forEach(System.out::println);
运行结果:
2. 统计文字中的单词数量并按出现次数排序(题集题目)
诶,上次的作业中似乎写过了,那就照搬过来吧
2.1 伪代码(不得复制代码,否则扣分)
创建HashMap对象map
循环读入文章中的单词
IF 读入单词为”!!!!!”
退出循环
ELSE
IF map中没有相应的key
添加单词到map中并设置value为1
ELSE
将key对应的value值加1
创建ArrayList对象list
实现Collections接口对map对象进行排序
输出map的长度
输出排序后list中前十个数据
2.2 实验总结
答:这题中用到了HashMap,key值为单词,value值为单词出现的次数,这题比较复杂的地方就是要使用一个能够存放Map数据ArrayList来实现Collections接口来实现相应的排序。
关键代码如下:
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (o1.getValue() == o2.getValue()) {
return o1.getKey().compareTo(o2.getKey());
}
return o2.getValue() - o1.getValue();
}
});
其中Map.Entry为Map的一个内部接口,它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。使用它可以更方便我们去访问Map中的元素。
3. 倒排索引(题集题目)
本题较难,做不出来不要紧。但一定要有自己的思考过程,要有提交结果。
3.1 截图你的代码运行结果
3.2 伪代码(不得复制代码,否则扣分)
创建Map对象map,其中key类型为String,value类型为ArrayList
创建ArrayList对象line
循环读入文章中的单词
IF 读入单词为"!!!!!"
退出循环
ELSE
IF map中没有相应的key
添加单词到map中并将当前行数的值添加到value中
ELSE
判断当前行数是否已经存在于value中,若没有,则添加当前行数到value中
创建迭代器Iterator
遍历输出map中的内容
输入一行字符串以空格分开
IF map中不同时存在指定单词
输出found 0 results
ELSE
求指定单词的value值的交集
IF 交集为0
输出found 0 results
ELSE
输出交集以及交集中数字对应的行数
3.3 实验总结
答:这题比较好玩的地方就是要在要将Map的value的类型设置为ArrayList的,以方便存储单词出现行数,然后要注意的点就是将某一单词的当前行数加入ArrayList中时要判断列表中是否已经存在该行的行数,即这个单词是否在这行中出现多次,之前一直错误就是因为没有考虑到一行可以存放多个相同单词,然后使用Iterator迭代器进行Map的输出。最后求单词出现函数的实质其实就是求指定单词的出现行数的交集,可以用retainAll方法来求。
4.Stream与Lambda
编写一个Student类,属性为:
private Long id;
private String name;
private int age;
private Gender gender;//枚举类型
private boolean joinsACM; //是否参加过ACM比赛
创建一集合对象,如List
4.1 使用传统方法编写一个搜索方法List<Student> search(Long id, String name, int age, Gender gender, boolean joinsACM)
,然后调用该方法将id>某个值,name为某个值, age>某个值, gender为某个值,参加过ACM比赛的学生筛选出来,放入新的集合。在main中调用,然后输出结果。(截图:出现学号、姓名)
测试数据:
List<Student1> student = new ArrayList<Student1>();
student.add(new Student1(1L,"wang",15,Gender.man,false));
student.add( new Student1(8L,"zhao",16,Gender.woman,true));
student.add( new Student1(87L,"chen",17,Gender.man,false));
student.add ( new Student1(100L,"xu",18,Gender.woman,false));
student.add( new Student1(67L,"chen",19,Gender.man,true));
student.add( new Student1(90L,"chen",20,Gender.man,true));
student.add( new Student1(177L,"chen",21,Gender.man,true));
//搜索方法
static List<Student1> search(Long id, String name, int age, Gender gender, boolean joinsACM,List<Student1> list){
List<Student1> student = new ArrayList<Student1>();
for(Student1 e:list){
if(e.getId()>id&&e.getName().equals(name)&&e.getGender()==gender&&e.isJoinsACM()==joinsACM){
student.add(e);
}
}
return student;
}
//main函数
List<Student1> newStudent = search(50L, "chen",18,Gender.man, true,student);
for(Student1 e:newStudent){
System.out.println(e.toString());
}
}
运行截图:
4.2 使用java8中的stream(), filter(), collect()编写功能同4.1的代码,并测试(要出现测试数据)。构建测试集合的时候,除了正常的Student对象,再往集合中添加一些null,你编写的方法应该能处理这些null而不是抛出异常。(截图:出现学号)
List<Student1> newStudent = student.stream().filter(e -> e!=null&&e.getId()>50&&e.getName().equals("chen")&&e.getAge()>18&&e.getGender()==Gender.man&&e.isJoinsACM()==true).collect(Collectors.toList());
测试数据(只是添加了两个null进去):
student.add(new Student1(1L,"wang",15,Gender.man,false));
student.add( new Student1(8L,"zhao",16,Gender.woman,true));
student.add(null);
student.add( new Student1(87L,"chen",17,Gender.man,false));
student.add(null);
student.add ( new Student1(100L,"xu",18,Gender.woman,false));
student.add( new Student1(67L,"chen",19,Gender.man,true));
student.add( new Student1(90L,"chen",20,Gender.man,true));
student.add( new Student1(177L,"chen",21,Gender.man,true));
运行结果:
其实和上面的结果是一样的……
5. 泛型类:GeneralStack
题集jmu-Java-05-集合
之GeneralStack
5.1 GeneralStack接口的代码
interface GeneralStack<T>{
T push(T item);
T pop();
T peek();
public boolean empty();
public int size();
}
5.2 结合本题与以前作业中的ArrayListIntegerStack
相比,说明泛型有什么好处
答:在ArrayListIntegerStack中
,栈中的元素只能是Integer类型的,内容比较有局限性,而使用了泛型,则可以根据自己的要求来规定入栈元素的类型,就像这题中,我们只要定义一个接口就可以实现对Integer
、Double
和Car
类型的栈操作,减少了代码的冗余,使用起来也很灵活。
6. 选做:泛型方法
基础参考文件GenericMain,在此文件上进行修改。
6.1 编写方法max,该方法可以返回List中所有元素的最大值。List中的元素必须实现Comparable接口。编写的max方法需使得String max = max(strList)
可以运行成功,其中strList为List<String>
类型。也能使得Integer maxInt = max(intList);
运行成功,其中intList为List<Integer>
类型。注意:不得直接调用Collections.max函数。
//max方法
public static <T extends Comparable<T>> T max(List<T> list){
Collections.sort(list);
return list.get(list.size()-1);
}
测试数据:
List<String> listA = new ArrayList<String>();
listA.add("aaaaa");
listA.add("bbbbb");
listA.add("ddddd");
listA.add("ccccc");
System.out.println(max(listA));
运行结果:
测试数据:
List<Integer> listB = new ArrayList<Integer>();
listB.add(11111);
listB.add(22222);
listB.add(44444);
listB.add(33333);
System.out.println(max(listB));
运行结果:
6.2 选做:现有User类,其子类为StuUser,且均实现了Comparable接口。编写方法max1,基本功能同6.1,使得User user = max1(stuList);可以运行成功,其中stuList为List类型。也可使得Object user = max(stuList)运行成功。
//max1方法
public static <T extends Comparable< ? super T>> T max1(List<T> list,Comparator< ? super T> comp) {
Collections.sort(list,comp);
return list.get(list.size()-1);
}
测试数据:
List<StuUser> listC = new ArrayList<StuUser>();
listC.add(new StuUser(11, "aaa"));
listC.add(new StuUser(22, "bbb"));
listC.add(new StuUser(44, "ccc"));
listC.add(new StuUser(33, "eee"));
listC.add(new StuUser(33, "ddd"));
User user1 = max1(listC,new StuUserComparator());
Object user2 = max1(listC,new StuUserComparator());
System.out.println(user1);
System.out.println(user2);
运行结果:
6.3 选做:编写int myCompare(T o1, T o2, Comparator c)
方法,该方法可以比较两个User对象,也可以比较两个StuUser对象,传入的比较器c
既可以是Comparator<User>
,也可以是Comparator<StuUser>
。注意:该方法声明未写全,请自行补全。
//myCompare方法
public static <T> int myCompare(T o1,T o2, Comparator<? super T> c){
return c.compare(o1, o2);
}
测试数据:
User user1 = new User(123);
User user2 = new User(321);
int a = myCompare(user1,user2,new UserReverseComparator());
if(a<0)
System.out.println(user1+" > "+user2);
else if(a==0)
System.out.println(user1+" = "+user2);
else
System.out.println(user1+" < "+user2);
StuUser stu1 = new StuUser(44, "ccc");
StuUser stu2 = new StuUser(55, "ddd");
int b = myCompare(stu1,stu2,new StuUserComparator());
if(a<0)
System.out.println(stu1+" > "+stu2);
else if(a==0)
System.out.println(stu1+" = "+stu2);
else
System.out.println(stu1+" < "+stu2);
运行结果:
7. 选做:逆向最大匹配分词算法
集合实验文件中的第07次实验(集合).doc文件,里面的题目6.
7.1 写出伪代码(不得直接复制代码)
创建HashSet对象dic
Add word to dic
设置最大截取长度maxLength
While has nextLine{
Creat list
While line 的长度不为0{
从后往前以最大截取长度截取句子e
If dic.continue(e){
Add e to list
line = 截取字符串(0,line.size-e.size)
从后往前以最大截取长度截取句子e
}
Else
去掉e的第一个字符继续操作
}
倒序输出list中的元素
}
7.2 截图你的代码运行结果。
3.码云及PTA
题目集:jmu-Java-05-集合
3.1. 码云代码提交记录
- 在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
3.2 截图PTA题集完成情况图
需要有两张图(1. 排名图。2.PTA提交列表图)
3.3 统计本周完成的代码量
需要将每周的代码统计情况融合到一张表中。
自己的目标能实现吗?
恩第一周定的目标是到期末能够写7000+行的代码,看样子应该可以完成??
周次 | 总代码量 | 新增代码量 | 总文件数 | 新增文件数 |
---|---|---|---|---|
2 | 607 | 607 | 15 | 15 |
3 | 1642 | 1035 | 33 | 18 |
5 | 2044 | 402 | 42 | 9 |
6 | 2874 | 830 | 57 | 15 |
7 | 3161 | 287 | 63 | 6 |
8 | 4299 | 1138 | 72 | 9 |
9 | 4831 | 532 | 81 | 9 |
10 | 5475 | 644 | 93 | 12 |
- 评估自己对Java的理解程度
尝试从以下几个维度评估自己对Java的理解程度
维度 | 程度 |
---|---|
语法 | pta的题目基本上没问题吧,一些比较偏的语法也可以通过百度解决 |
面向对象设计能力 | 这方面的能力还比较弱,在设计购物车系统的时候充分暴露了出来,正在努力改善中 |
应用能力 | 也许借助一些资料可以完成一些简单的工具? |
至今为止代码行数 | 5475 |