昨天写到11点半写完了lab1,今天来总结一下
感觉比ICS的lab体验好得多…🐶
先看一下每个Task考察的点:
Task0
第一关没什么问题,给了个C语言的hello,world
改成Java即可
public class Task0{
public static void main(String[]args){
System.out.println("Hello World");
}
}//第一行Class有点忘了,必须和文件名完全相同!
输出:
Task1
这关是捕获异常,第一反应就是try catch语句
当然还要打印异常信息和Caused by,参考了这篇博文:
https://www.jb51.net/article/81544.htm
public class Task1 {
public static void foo1(int a) throws NewException666,NewException777 {
// Do not change this method!
if(a == 6){
NewException666 newException666 = new NewException666("666 Exception");
throw newException666;
}else if(a == 7){
NewException777 newException777 = new NewException777("777 Exception");
throw newException777;
}else{
System.out.println("There is no exception");
}
}
public static void foo2(int a) throws NewException666, NewException777, NewException {
// TODO: How to handler exception to get target output?
try{
foo1(a);
}
catch(NewException777 newException777){
NewException newException = new NewException("Yes I got 777 Exception");
System.out.println("foo2 finished");
newException.initCause(newException777);
newException.printStackTrace(); }
catch(NewException666 newException666){
NewException newException = new NewException("Yes I got 666 Exception");
System.out.println("foo2 finished");
newException.initCause(newException666);
newException.printStackTrace(); }
//打印错误信息:printStackTrace()
//同时打印Caused by:initCause(exception)
}
public static void main(String[] args) {
// Do not change this method!
try{
int luckynumber=new Random().nextInt(2)+6;
System.out.println("You lucky number is: "+luckynumber);
foo2(luckynumber);
}catch (Exception e){
e.printStackTrace();
}
}
}
输出:
Task2
这关是多线程引起的错误,助教写好了runnable接口
但是多线程修改同一个值会有一个问题:
修改的过程是:将值从内存取出->修改->再存入内存
所以线程有交叉时,由于流水线操作的问题,会出现错误
比起ICS要自己上锁,Java有很简单的操作方法
用synchronized实现同步化即可,在多个线程执行这个方法时,每一个线程获得执行该方法的执行权就会把这个方法上锁结束后开锁,只有等到这个方法没有被上锁时才可以被其他线程运行
参考了下面的博文:
https://www.cnblogs.com/SAM-CJM/p/9782062.html
public class GPA {
public double myGPA=0;
// TODO: How to make my gpa stable?
synchronized public void add(double i){
myGPA+=i;
}
}
输出:
Task3
这就是一个编程题了…
数据结构里的循环队列出列问题
public class Task3 {
public static void main(String[] args) {
// Do not change this method!
int[] student={9, 13, 3, 4, 20, 6, 11, 1, 12, 10, 2, 8, 19, 14, 15, 18, 7, 16, 17, 5};
int[] result=new Party().outputrank(student,5);
System.out.println("Party start!");
for (int aResult : result) {
System.out.println("Next one is: " + aResult);
}
}
}
public class Party {
// TODO: How to calculate the sequence of students?
//实现循环出列
public int[] outputrank(int[] originalrank, int interval) {
int[] result = new int[originalrank.length];
for (int i = 0, sign = 0; i < originalrank.length; i++) {
int count = 0;
while (count < interval-1) {
sign = (sign + 1) % originalrank.length;
if (originalrank[sign] != 0)
count++;
}
result[i] = originalrank[sign];
originalrank[sign] = 0;
sign = (sign + 1) % originalrank.length;
while (i<originalrank.length-1&&originalrank[sign] == 0) {
sign = (sign + 1) % originalrank.length;
}
}
return result;
}
}
输出:
Task4
这个是有点难的一个了
是之前没有接触过的回调方法
回调机制:
调用者A需要被调用者B的结果时,就需要B执行完后主动调用A的callback方法进行反馈
通常的回调方式:
1.class A实现接口CallBack callback——背景1
2.class A中包含一个class B的引用b ——背景2
3.class B有一个参数为callback的方法f(CallBack callback) ——背景3
4.A的对象a调用B的方法 f(CallBack callback) ——A类调用B类的某个方法 C
5.然后b就可以在f(CallBack callback)方法中调用A的方法 ——B类调用A类的某个方法D
//主程序
public class Task4 {
public static void main(String[] args) {
// Do not change this method!
PhoneSystem ps = new PhoneSystem();
App app = new App(ps);
//调用class A的方法
app.click();
}
}
//接口
public interface CSCallBack {
// Do not change this method!
public void OnClick();
}
//实现接口的class A
public class App implements CSCallBack {
// You need to modify this class.
// TODO: How to set callback?
//包含了class B 的引用
private PhoneSystem system;
public App(PhoneSystem system) {
this.system = system;
}
//主程序调用了这个方法click()
public void click(){
System.out.println("Button clicked");
//调用class B的方法
system.performOnClick(this);
}
//覆盖重写了接口中的方法
@Override
public void OnClick() {
System.out.println("You click this button, so I will do ...");
}
}
//class B
public class PhoneSystem {
// You need to modify this class.
// TODO: How to set callback?
//传入的参数是实现了接口的类class A
public void performOnClick(App a) {
System.out.println("performOnClick clicked");
//回调A中覆盖重写的函数,实现特殊化的反馈
a.OnClick();
try {
Thread.sleep( 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
使用回调的好处:
解耦:应使多个程序之间的耦合度尽量低,以便复用
回调还可以实现不同的反馈:用不同的类去implement接口即可,然后覆盖重写各自不同的接口内方法,最后只要传入的参数不同,得到的反馈就不同