Stanford Compiler Week 9 Java
课程主页:
https://www.edx.org/course/compilers
课程视频:
https://www.bilibili.com/video/BV1NE411376V?p=20&t=6
备注:
图片均来自于课件。
这次回顾Java。
Java
- Java:COOL的升级版
- 同一时期出现
- 包含
- 数组
- 异常(Exceptions)
- 接口(Interfaces)
- 强制(Coercions)
- 线程
- 动态加载和初始化
- 总结
历史
- Java出现在SUN公司
- 最初针对机顶盒设备
- 最初的开发花费了数年(91-94)
- 后来重新定位为互联网语言(94-95)
- 每种新语言都需要一个“杀手级应用”
- 竞争对手是TCL,Python
一些语言比较
- Modula-3
- 类型
- Eiffel,ObjectiveC,C ++
- 面向对象,接口
- Lisp
- Java的动态风格(许多功能)
对比COOL
- 从我们的角度来看,Java是COOL的增强版,增加了如下特性
- 异常(Exceptions)
- 接口(Interfaces)
- 线程
- 动态加载
- 其他一些次要的特性
- Java是一种大语言
- 有很多功能
- 许多功能交互
Java数组
问题
B[] b = new B[10];
A[] a = b;
a[0] = new A();
b[0].aMethodNotDeclaredInA();
假设B < A,接下来会发生什么?
分析
在Java中,
- B < A,如果B从A继承
- 和Cool中一样
- C < A,如果C < B以及B < A
- 和Cool中一样
- B[] < A[],如果B < A
- 和Cool中不同
回顾之前的代码
B[] b = new B[10];
A[] a = b;
a[0] = new A();
b[0].aMethodNotDeclaredInA();
在可更新位置使用不同类型的多个别名是不合理的!
- 标准解决方法
- 禁止通过数组进行子类型化
- B < A,如果B从A继承
- C < A,如果C < B以及B < A
- B[] < A[],如果B = A
解决方法
- Java通过在运行时检查每个数组分配的类型正确性来解决此问题
- 分配的对象的类型与数组的类型兼容吗?
- 这增加了数组计算的开销
- 但请注意:基本类型的数组不受影响
- 基本类型不是类
Java异常 (Exceptions)
在一段代码的深处,您遇到意外错误,例如
- 内存不足
- 假设已排序的列表并没有排序
- 等等。
你应该做什么?
添加新的异常类型(类)
添加新形式
try { something } catch(x) { cleanup } throw exception
例子
class Foo {
public static void main(String[] args) {
try { X(); } catch (Exception e) {
System.out.println(“Error!”) }
}
public void X() throws MyException {
throw new MyException();
}
}
- $\mathrm{T(v)}=$ 抛出了值为$\mathrm v$的异常
- $\mathrm{v =\ }$普通值(一个对象)
实现
- 当我们遇到try
- 在堆栈中标记当前位置
- 当我们抛出exception
- 将堆栈展开到第一个try
- 执行相应的catch
- 更复杂的技术降低了try和throw的成本
在对象完成期间引发的未捕获异常会发生什么情况?
异常类型
方法必须声明它们可能引发的异常类型
public void X() throws MyException
- 在编译时检查
- 某些异常不必是方法签名的一部分
- 例如,取消引用null
其他普通类型规则
- throw必须应用于Exception类型的对象
Java接口(interface)
Interface指定类之间的关系而不继承。
interface PointInterface { void move(int dx, int dy); }
class Point implements PointInterface {
void move(int dx, int dy) { ... }
}
“Java程序可以使用接口,使相关类不必共享一个通用的抽象超类或向Object添加方法。”
换句话说,接口起到C++中多重继承的作用,因为类可以实现多个接口。
class X implements A, B, C { ... }
例子
研究生既可以是大学员工,也可以是学生
class GraduateStudent implements Employee, Student {... }
没有很好的方法使用单一继承将研究生和员工,学生结合起来。
具体实现
实现接口类中的方法不需要固定偏移量。
interface PointInterface { void move(int dx, int dy); }
class Point implements PointInterface {
void move(int dx, int dy) { ... }
}
class Point2 implements PointInterface {
void dummy() { ... }
void move(int dx, int dy) { ... }
}
- 分派$\mathrm{e.f(\ldots)}$,其中$\mathrm e$具有接口类型比通常更复杂,因为方法不以固定偏移量存在。
- 一种方法:
- 实现接口的每个类都有一个查找表方法名$\mathrm{method\ names\to methods}$
- 用于更快查找的哈希方法名称
- 编译时计算哈希
Java强制(Coercions)
- Java允许在某些情况下强制原始类型。
- 在1 + 2.0中,将int 1扩展为float 1.0
- 强制实际上只是编译器为您插入的原始函数
- 大多数语言在基本数值类型之间具有广泛的强制性
- Java区分两种强制 & 强制转换:
- 扩大总是成功的($\mathrm{int\to float}$)
- 缩小可能会失败,如果无法将数据转换为所需的类型($\mathrm{float\to int}$,向下转换)
- 缩小强制类型转换必须明确
- 拓展转换/强制转换可以是隐式的。
- Java中唯一没有定义强制/强制转换的类型是什么?
- Bool
例子
强制会导致令人惊讶的行为
考虑PL / I的一个例子
假设A,B,C为3个字符的字符串
A是什么
Java线程
Java具有通过线程实现的内置并发性
- 每个线程都有自己的程序计数器和堆栈
线程对象具有Thread类
- 启动和停止方法
同步在对象上获得锁:
synchronized (x) { e }
在同步方法中,this被锁定
例1
class Simple {
int a = 1, b = 2;
void to() { a = 3; b = 4; }
void fro() { println("a= " + a + ", b=" + b); }
}
有两个线程调用to()和fro(),打印的结果是什么?
- “a = 1 b = 2”
- “a = 3 b = 4”
- “a = 3 b = 2”
例2
class Simple {
int a = 1, b = 2;
void synchronized to() { a = 3; b = 4; }
void fro() { println("a= " + a + ", b=" + b); }
}
有两个线程调用to()和fro(),打印的结果是什么?
- “a = 3 b = 2”
- “a = 3 b = 4”
例3
class Simple {
int a = 1, b = 2;
void synchronized to() { a = 3; b = 4; }
void synchronized fro() { println("a= " + a + ", b=" + b); }
}
有两个线程调用to()和fro(),打印的结果是什么?
- “a = 3 b= 4”
小结
- 即使没有同步,变量也应只保存由某个线程写入的值
- 值的写入是原子的
- 违反了double
- Java并发语义很难详细理解,特别是在某些机器上如何实现它们方面
其他主题
类
- Java允许在运行时加载类
- 对源进行类型检查在编译时进行
- 字节码验证在运行时进行
- 由类加载器(ClassLoader)处理加载策略
- 类也可能被卸载
- 定义中未明确规定
初始化
- Java中的初始化很复杂
- 包括COOL中的所有内容以及更多内容
- 由于并发的原因导致非常复杂
- 首次使用类中的符号时,类会初始化
- 当类被加载时不会被初始化
- 将初始化错误延迟到可预测的点(当引用了类中的某些内容时)
完整流程
- 锁定类的类对象
- 如果另一个线程将其锁定,请等待该锁定
- 如果同一线程已经在初始化该类,则释放锁并返回
- 如果类已经初始化,则正常返回
- 否则,将此线程标记为正在进行初始化,并解锁类
- 初始化超类,字段(按文本顺序)
- 但首先初始化静态的最终字段
- 在初始化之前为每个字段提供默认值
- 任何错误都将导致错误地初始化类,将类标记为错误
- 如果没有错误,则锁定类,将标签类初始化,通知正在等待类对象的线程,解锁类
交互
- 在具有$\mathrm N$个特征的任何系统中,都可能存在$\mathrm N^2$个特征交互。
- 大型,功能强大的系统很难理解!
- 包括编程语言
小结
Java做得很好
- 按照生产级语言标准,做得很好
Java将许多重要思想带入了主流
- 强静态分型
- 垃圾回收
但是Java也
包括无法充分理解的功能
具有太多特征
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere