Java 第八周总结
第八周的作业。
目录
1.本章学习总结
2.Java Q&A
3.码云上代码提交记录及PTA实验总结
1.本章学习总结
1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容。
上次我讲了容器,这次就讲泛型。
容器类,可以持有大量对象。如果我们要存储不同类型的对象,则可以让容器去持有Object类型的对象,即全部向上转型至根类。但是我们通常只会使用容器来存储一种类型的对象,这时就需要我们指定容器来持有什么类型的对象,然后在编译阶段的时候就能保证不会持有除指定类型外的其他类型的对象。
Java SE5引入泛型,泛型实现了参数化类型,允许我们用一对尖括号将类型参数括住,然后放在类名后面。然后可以再用实际的类型去替换此类型参数。
这边要注意的还有,就是容器里面可以存放该类型,或者是该类型的子类,所以多态和泛型并不起冲突。我可以向持有父类的容器发送消息,然后运行阶段根据具体类型作出不同的回应。
这就是Java泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理一切细节。
泛型不仅可以应用于类上,还可以用于方法。而且拥有泛型方法跟所在的类是否是泛型类没有关系。
Java编程思想上还提到了一个基本的指导原则:
无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更清楚明白。另外,对于一个 static的方法而言,无法访问泛型类的类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。
定义泛型方法,就是将泛型的参数列表放在返回值之前即可。
关于类型擦除,就是 ArrayList<Integer>
和ArrayList<String>
在运行的时候其实是一种类型。即任何具体的类型信息都被擦除,这两种形式都被擦除为最原生态的方式就是ArrayList。
extends和super关键字的使用:首先要注意的是即使Apple是Fruit,Apple的List也不是Fruit的List,Apple的List只能持有Apple及其子类,而Fruit可以持有所有水果。如果我们想建立两种带参容器的向上转型关系,就使用extends,例如List<? extends Fruit> fruits = new ArrayList<Apple>();
但是我不能往里面添加任何Apple、Fruit甚至是Object类对象,按照编程思想说的,add()的参数此时变成了"? extends Fruit",编译器不能了解需要Fruit的具体子类型,所以只会接受null。不过能确保的是这个列表中的对象至少都是Fruit类型的。至于super(超类型通配符),我们可以使参数类型为<? super T>的容器持有T或者是T的子类。
?是*通配符,当我们不知道具体实际类型的时候,就很好用。
最后要注意的是任何基本类型都不能作为类型参数。解决的办法就是使用自动包装机制。
总之,泛型是使用起来简单、方便的语法,但是自己编写泛型代码确是一件非常累的事情。编程思想洋洋洒洒花了将近100页来写泛型就可见一斑。
2.Java Q&A
1.List中指定元素的删除
1.1 实验总结
针对样例中出现的数量不等的空格,使用正则表达式的贪婪原则将它们分开来String[] strings = line.split(" +");
java中split任意数量的空白字符
还有就是在remove的过程当中,删除当前下标为i的元素后,该元素后的所有元素将往前移一格,所以i这时候需要自减一次。这样可以确保所有元素都可以不被遗漏地检测。
另一种安全删除的方法就是使用迭代器进行遍历,然后调用迭代器的remove()方法来移除当前对象。如何正确删除List中的元素
Iterator的remove()方法移除迭代器最后返回的一个元素,在调用remove()方法前必须调用next()方法。而且注释中还指出remove()只是一个可选方法,当某个迭代器不支持remove()方法,但是还是调用了remove()方法,就会抛出UnsupportedOperationException的异常。
1.2 截图你的提交结果(出现学号)
2.统计文字中的单词数量并按出现次数排序
2.1 伪代码(简单写出大体步骤)
for each word in text
put it in the map and the count increments
make a list to record the pair of the key and the corresponding value
according to the value and the key sort the list
n = min(the size of list, 10)
for i = 0 to n - 1
print the ith pair
2.2 实验总结
首先这边用HashMap即可,虽然按照题目的要求需要进行排序,但是我们可以放到列表当中来完成操作。
这边来讲一下Map的一些操作。
比如get()方法。当键不在容器中时,get()方法将返回null,在本例中,就表明单词第一次在文章当中出现,否则就会返回对应的值。
put()方法是用来往Map容器里面添加键值对的,如果出现有键相同的情况,则会用新值去取代旧值。Java的Map统计次数似乎比C++麻烦一些,或许是我不清楚,假如用C++的Map来统计次数的话,只要根据键像数组下标那样访问对应的值,并自增即可,而Java需要重新put进去。
Map可以用keySet()方法返回键的Set,values()方法来返回值的Collection,或者用entrySet()方法来返回键值对的Set,这边用到的就是这第三种方法。
2.3 截图你的提交结果(出现学号)
3.倒排索引
3.1 伪代码(简单写出大体步骤)
create a map from word to a sorted set
for line in the paragraph
for word in line
add the number of line in the set of the word
for each search
compute the intersection of the sets of the words
if the intersection is empty
print found 0 results
else
print the elements of the set
3.2 实验总结
要注意单词找不到的情况,只要有一个单词找不到,返回空集即可。还有就是和前面一样输入输出的问题,在统计的时候可以使用next()方法来逐个吃单词,在查询的时候则要先读取一行,再对单词进行分割。
3.3 截图你的提交结果(出现学号)
4.Stream与Lambda
编写一个Student类,属性为:
private Long id;
private String name;
private int age;
private Gender gender;//枚举类型
private boolean joinsACM; //是否参加过ACM比赛
创建一集合对象,如List,内有若干Student对象用于后面的测试。
4.1 使用传统方法编写一个方法,将id>10,name为zhang, age>20, gender为女,参加过ACM比赛的学生筛选出来,放入新的集合。在main中调用,然后输出结果。
public static ArrayList<Student> choose(ArrayList<Student> arrayList) {
ArrayList<Student> arrayList2 = new ArrayList<Student>();
for (Student student : arrayList) {
if (student.getId() > 10L && student.getName().equals("zhang")
&& student.getAge() > 20 &&
student.getGender().equals(Gender.女)
&& student.isJoinsACM()) {
arrayList2.add(student);
}
}
return arrayList2;
}
4.2 使用java8中的stream(), filter(), collect()编写功能同4.1的函数,并测试。
ArrayList<Student> arrayList2 = (ArrayList<Student>) arrayList.parallelStream()
.filter(student -> (student.getId() > 10L && student.getName().equals("zhang")
&& student.getAge() > 20 &&
student.getGender().equals(Gender.女)
&& student.isJoinsACM()))
.collect(Collectors.toList());
测试结果同4.1图
4.3 构建测试集合的时候,除了正常的Student对象,再往集合中添加一些null,然后重新改写4.2,使其不出现异常。
ArrayList<Student> arrayList2 = (ArrayList<Student>) arrayList.parallelStream()
.filter(student -> student != null && (student.getId() > 10L && student.getName().equals("zhang")
&& student.getAge() > 20 &&
student.getGender().equals(Gender.女)
&& student.isJoinsACM()))
.collect(Collectors.toList());
那就只要再加上student != null
这句话就好了,就是上来就判断非空。
5.泛型类:GeneralStack
5.1 GeneralStack接口的代码
interface GeneralStack<E> {
E push(E e);
E pop();
E peek();
boolean empty();
int size();
}
5.2 结合本题,说明泛型有什么好处
一般的类或者是方法,都只能使用具体的类型,要么是具体类型,要么是自定义的类,这样如果要编写应用于多种类型的代码,就要针对每一个类写对应的代码,非常僵硬。
泛型可以使我们的代码应用于多种类型。
使用泛型类型机制的最吸引人的地方,就是在使用容器类的地方。
在泛型出现之前,将一个对象放在一个容器中,这个对象会被向上转型为Object,当然这样就会丢失类型信息。然后要把这个对象从容器中取回的时候,就得向下转型成一个正确的类型。就像书上说的,把一个Dog放在一个Cat的List中,是没有任何问题的。但是我要把它转型为Cat的时候就会抛出异常,但是我们只有在运行的时候才能发现。这是泛型在带来更加通用代码的一个副作用,即创建类型安全的容器。
5.3 截图你的提交结果(出现学号)
6.泛型方法
6.1 编写方法max,该方法可以求出List中所有元素的最大值,并返回。List中的元素必须实现Comparable接口。编写的max方法使得String max = max(strList)可以运行成功,其中strList为List类型。
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
return Collections.max(coll);
}
//test
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("abc");
arrayList.add("cccc");
arrayList.add("bbb");
System.out.println(max(arrayList));
6.2 编写方法max1,基本功能同6.1,但让其所返回的值可以赋予其父类型变量。如有User类,其子类为StuUser,且均实现了Comparable接口。编写max1使得User user = max1(stuList);可以运行成功,其中stuList为List<StuUser>
类型。也可使得Object user = max(stuList)运行成功。
public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
return Collections.max(coll, comp);
}
public static void main(String[] args) {
ArrayList<StuUser> arrayList = new ArrayList<StuUser>();
arrayList.add(new StuUser(10, "1"));
arrayList.add(new StuUser(20, "4"));
arrayList.add(new StuUser(15, "6"));
User user = max(arrayList, new StuUserComparator());
System.out.println(user);
Object user1 = max(arrayList, new UserReverseComparator());
System.out.println(user1);
}
返回的StuUser类型向上转型应该是没有什么问题的吧
6.3 选做:编写int myCompare(T o1, T o2, Comparator c)方法,该方法可以比较User对象及其子对象,传入的比较器c既可以是Comparator<User>
,也可以是Comparator<StuUser>
。注意:该方法声明未写全,请自行补全。
public static<T> int myCompare(T o1, T o2, Comparator<T> c) {
return c.compare(o1, o2);
}
public static void main(String[] args) {
StuUser stuUser = new StuUser(10, "1");
StuUser stuUser2 = new StuUser(20, "4");
User user = new User(15);
System.out.println(stuUser);
System.out.println(stuUser2);
System.out.println(user);
System.out.println(myCompare(stuUser, stuUser2, new StuUserComparator()));
System.out.println(myCompare(stuUser, user, new UserReverseComparator()));
}
7.选做:逆向最大匹配分词算法
7.1 写出伪代码即可
for word in dict
add in the set
new a list
while input a sentence
clear the list
for i in range the length of sentence to 0
for j in range 0 to i - 1
string <- the substring from j to i
if the set contains the string
add in the list
break
if j equals to i - 1
add the substring from j to i in the list
i <- j
reverse the list
output the list
因为分词的要求是逆向匹配最大,所以这边每次查询的时候都应该从字符串的最左边开始,然后因为外循环是从后面加到前面,所以最后如果是按照词语在句子当中的次序输出的话,就要逆置列表。
7.2 截图你的代码运行结果。
8.JavaFX入门
完成其中的作业1、作业2。内有代码,可在其上进行适当的改造。建议按照里面的教程,从头到尾自己搭建。
进去的界面
显示Muster的详细信息
添加新的Person
修改Anna的信息
把Werner删了
3.码云上代码提交记录及PTA实验总结
3.1 码云代码提交记录
- 在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
看的不过瘾的请点下面
回到顶部