继承篇
新建对象时,引用必须比new对象的等级高
- 新建对象时,包含两部分,一部分是new出来的对象,一部分是创建的新引用。引用的类型可以是接口、抽象类、普通类,而new对象的类型必须是实现类,这个实现类常见的有三种表现形式,一种是普通的类,另外是抽象类或接口,但是必须实现所有还没有实现的方法。引用的类型可以使用new出来对象的父类,但是不能使用其子类。可以这样理解:引用的作用是调用方法,子类往往拥有比父类更多的方法(通过继承多个接口等),因此只能用方法更少的父类指向方法更多的子类,以防我们引用了某个方法,但是在new出来的对象中并不存在,造成错误。
cast对象时,需要从子类cast为父类 需要从内存中实际对象的类别转化为其父类或本身
- 和上面的一条有异曲同工之妙,在类型强转之后,我们需要调用对象中的方法,强转的过程想必也不会添加新的方法吧。所以强转是不是可以看作是单纯地去掉一些方法呢,其实不是的。强转的最大作用其实是让我们用不同的引用类型去访问同一个对象,而堆中的对象本身并没有改变。
- 但是,在安卓开发中经常会用到 (Button) findViewById(R.id.activity_button) 这样的操作,而Button明明是子类啊,为什么可以强转呢?区别在于引用指向的对象在内存中究竟是什么。如果其在内存中是以Button存在的,那么即使返回类型是以View引用的,也可以强转回Button。
子类override父类的方法时,可以改变方法的返回值,但是返回值必须是父类返回值的子类
- 还是和引用与实现对象的类型有关。在调用方法时,利用的是引用的类型,即父类。如果引用类型中没有某个方法,就无法调用,即使实现对象中有此方法。所以父类方法的返回类型就是我们调用方法时期望得到的类型。我们可能会利用一个返回值引用去指向得到的返回值。所以由“新建对象时,引用必须比new对象的等级高”可知,返回值引用的类型要比返回对象的等级高,如果子类实现返回一个等级更高的对象,就可能违背这个原则。
方法中实际返回的类型要比声明的类型等级低
- 由原则1,2易得
运行篇
守护线程和用户线程
在java程序开始执行之后,会产生多个线程。主要分为用户线程和守护线程。用户线程包括我们平时使用的main函数创建的主线程,这个线程主要完成一些复杂的工作,而守护线程则是为了程序正常运行提供服务的线程。他们主要有以下区别:
jvm只等待用户线程结束才结束
用户线程优先级比守护线程高
这保证了cpu会优先满足用户进程的执行
由谁创建:用户线程通常由用户创建,而守护线程往往由操作系统创建
用户线程是jvm运行的前提,当只有守护线程时,jvm无法继续运行
栈帧的组成
Each frame contains:
Local variable array 本地变量数组
- boolean
- byte
- char
- long
- short
- int
- float
- double
- reference
- returnAddress
除了double和float之外,都占用8个字节/32bit
Return value 返回值
Operand stack 操作数栈
Reference to runtime constant pool for class of the current method 运行时常量池的引用
运行时常量池的作用
在c(++)语言中,代码通常被编译为一个个对象,然后通过连接他们来产生可运行文件或者dll。在连接阶段,符号引用被实际的内存地址代替。而在java中这个过程是在运行时动态实现的。
当java class被加载到jvm中之后,所有的引用和变量都会被存储在类的常量池中,这里的存储使用的是符号引用,而不是对应于实际的地址引用。jvm的具体实现可以选择何时解析符号引用,分为两种,饥饿模式和懒汉模式。饥饿模式的解析发生在字节码验证之后,懒汉模式则发生在引用和变量第一次被使用时。Binding是变量、方法的符号引用被直接引用取代的过程,这个过程只发生一次。