回到目录
内容总结
- 第一节课的Lab0实质上是关于git仓库的建立和教程,这个就不再赘述了。
- Lab1是致力于Java编程的。这个思路也很正常:要学会逆向别人的代码,那就需要读懂它们,要能够读懂它们最直接的方法就是我也能写出它们。Java Programming的这个实验是为了之后Android Programming打下基础。
- 因为大部分选上这门课的同学都有C++的基础,至少对面向对象的理念不会陌生。因此这里简单地概述一些有关于Java的语法特征。如果您想要系统地学习Java,可以在网上找到数不尽的资源,或者也可以和你旦教务处沟通一下,在上半学期开一门Java编程课程。
数据类型: Java的数据一共有两种类型,分别是原始类型(Primitive Type)以及引用类型(Reference Type)。原始类型包括:byte(1字节)、short(2字节)、int(4字节)、long(8字节)、float(4字节)、double(8字节)、char(2字节)、boolean。关于原始类型的参数传递是值传递。其中特别注意的是,char在Java中是2字节的,因为Java使用Unicode编码,这在之后的Native Code一块也会有所呼应。除了原始类型,都是引用类型,包括但不限于String、StringBuilder、Random。
类: 类(class)可以说是Java中几乎一切的基础。这一块和C++大抵一致,都有field(instance field和static field)和methods(instance methods和static methods)。instance field/methods和static field/methods的关键区别,在于是否依赖一个实例化的对象。构造函数(constructor)的概念,也基本和C++一致。
多态: 由于所有自己定义的类都属于引用类型,而Java也允许一般类之间的单继承,因此也会引入多态。与C++中显式地定义virtual不一样的是,Java的非private方法都是动态绑定(Dynamic Binding)实现的。
方法的重写和重载: 重写(Override)和重载(Overload),这个和C++中的概念一致,这里不多赘述。
内部类: 分为普通的内部类、静态的内部类以及匿名内部类。在之后的反编译得到的代码中,会大量见到内部类。
反射: 在获得目标类的字节码文件的情况下,知道一个类,可以知道它的所有字段和方法,并且获取和实现它。这个也是Java的一个强大的机制,在之后的Java-specific Obfuscation中会提到反射机制的使用。
JNI: 声明native,通过库文件的调用,可以调用如C等非Java语言的代码。这部分的知识在Native Code部分会提及。
垃圾回收: 垃圾回收(Garbage Collection),与C++中需要显式地销毁(堆上)对象不一样的是,Java采取垃圾回收机制。关于这部分机制的介绍,可以参见更多相关的教程。这一机制的存在,可以使我们在大部分时刻不太用关心空间的维护和释放。
Lab简介与参考
这个Lab一共分成5个Task:(Task0仅供热身)
- Task0: Hello World!
打印出Hello world即可,这应该是所有编程语言入门的第一步了。
//Task0.java
//TODO:Make this program output "Hello world!".
class Task0 {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
IDEA可以使用sout快捷键迅速地打出System.out.println();这句语句。如果开启了省电模式,将无法使用快捷键。类似地,主函数也可以使用psvm迅速打出。
- Task 1: Catch the exception
这个task的关键要点在于错误处理,难点在于如何优雅地打印出要求的格式。建议对这个task感到束手无策的同学仔细查看错误处理相关的API,所有答案也源自这里。
//Task1.java
public static void foo2(int value) throws NewException {
// TODO: How to handler exception to get target output?
try {
foo1(value);
} catch (NewException666 e) {
NewException newException = new NewException("You got a 666 Exception");
newException.initCause(e);
throw newException;
} catch (NewException999 e) {
NewException newException = new NewException("You got a 999 Exception");
newException.initCause(e);
throw newException;
} finally {
System.out.println("foo2 finished!");
}
}
关键在于这里的iniCause()函数的调用。
- Task 2: Thread Collaboration
这个task的问题是在于如何解决多线程中的并发读写引起的问题。关于这个解决方案,在另一门课程ICS(CS:APP)中会涉及,不过好像我们这一届是最后开设这门课程的了……
//Add.java
// TODO: How to make add stable?
public synchronized void add(int i){
sum+=i;
}
关键在于synchronized关键字。大家可以查阅相关的文档寻求进一步的帮助,这里就不多阐述其原理了。(加锁)
- Task 3: Callback Methods
关于回调函数,简单地来构造一个情境:A类的a()方法去调用B类的b()方法,b()方法在结束后再调用A类的callback()方法,这就是一次回调。特别地,这里是当callback()方法不是静态方法的一次特例。
//App.java
public class App implements CSCallBack {
// You need to modify this class.
// TODO: How to set callback?
private PhoneSystem system;
public App(PhoneSystem system) {
this.system = system;
}
public void click(){
System.out.println("Button clicked");
system.performOnClick(this);
}
@Override
public void OnClick() {
System.out.println("You click this button, so I will do ...");
}
}
//PhoneSystem.java
public class PhoneSystem {
// You need to modify this class.
// TODO: How to set callback?
public void performOnClick(App app) {
System.out.println("performOnClick clicked");
app.OnClick();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这里的回调机制,需要通过修改原先java文件中的两个关键函数的参数实现。如果不理解的话,可以试图模拟一下这个Task的操作的流程,应该就比较清楚回调的作用了。
- Task 4: Simple Java Program
这个Task的目标是实现一个栈(stack)。如果之前没有修过《数据结构》的同学,可以简单地将栈理解为一个先进后出的容器。我们需要实现一些栈的基本操作,并结合数据验证结果。
//Task4.java
import java.util.ArrayList;
public class MyStack<T> {
// TODO: Finish it!
private ArrayList<T> list = new ArrayList<T>();
public boolean isEmpty(){
return list.isEmpty();
}
public int getSize(){
return list.size();
}
public T peek(){
return list.get(list.size()-1);
}
public T pop(){
T temp=list.get(list.size()-1);
list.remove(list.size()-1);
return temp;
}
public void push(T o){
list.add(o);
}
@Override
public String toString() {
return "stack:"+list.toString();
}
}
这里的几个操作也和C++中实现栈的方法差不多。不一样的是,这里还简化了模型,只需要调用List相关的方法就可以管理数据的储存。(我也不记得最初始的代码里是否有ArrayList了)
写在最后
- 这个Lab的难度不大,但大家想要通过三节课就能学会一门编程语言,这不太现实。不过有C++基础的话,在了解相关机制时就很清楚了。这个Lab及Java编程的知识,对后面的一些Lab还是有作用的,尤其是Android Programming。