《java编程思想》java复习笔记
最近在看《java编程思想》,书挺厚的,但是里面确实有很多东西在学的时候没有注意,重新在读的过程中,找到很多之前没有注意到的东西,在此记录。
第四章、控制执行流程
java中能否使用goto语句?
goto在java中作为保留字,但是在语言中没有用它。但是java中也可以完成一些相应的操作。标签是后面跟有冒号的标识符,例如 ‘lable:’。标签可以和 break、continue两个关键词连用。若这两个关键词和标签连用,会中断循环,跳转到标签所在的语句。再完成相应的特性(break+标签会跳转到标签处,但不会重新进入循环,而continue会重新进入循环——如果可以的话)。通过这一特性可以一次跳出多重循环。在switch-case结构中,有这样的栗子
public class Test{
public static void main(String[] args){
int i = 3;
switch(i){
case 1:
System.out.println("1");
case 2:
System.out.println("2");
case 3:
System.out.println("3");
case 4:
System.out.println("4");
default:
System.out.println("default");
}
}
}
output:
3
4
default
之前一直认为,case会按照冒号前的数值进行匹配,只有匹配的才能执行相应的语句,但是结果却说明这句话只适用于第一个匹配的项,之后的项不会进行匹配,会依次执行case后的语句。另外需要记忆的是,switch的选择因子只能是int、char或者enum类型。
第五章、初始化与清理
- override 重写(覆写),对父类中的同名方法进行不同方式的实现,但是不允许修改该方法的的方法签名(方法的名称和其每一个形参的顺序、类型和种类)。但是overload 重载则是多个同名函数具有不同的方法签名,为什么返回值不可以作为判断重载的标志之一呢?
void fun(){...}
int fun(){...}
这样两个方法,在被这样调用的时候fun();
编译器就无法区别到底调用那个函数了。
5.5清理:终结处理和垃圾回收
java中有垃圾回收器负责回收无用对象占据的内存资源。但是也有特殊情况下的对象无法被回收(没有使用new获得内存空间),而垃圾回收器只能回收通过new分配的内存。
finalize()
方法:一旦垃圾回收器准备好释放对象占用的内存,将首先调用finalize()
方法,并且在下一次的垃圾回收动作发生时,才会真正回收对象占用的内存。然而java中的对象却并不一定总是被垃圾回收器所回收,即
- 对象可能不被垃圾回收
- 垃圾回收不等于“析构”
只要在程序没有濒临存储空间用光的那一刻,对象占用的空间就总也得不到释放,如果程序结束,并且垃圾回收器一直也没有释放你创建的任何对象的存储空间,随着程序的退出,那些资源也全部交还给系统。换句话说,java虚拟机没有面临内存耗尽的状况时,是不会浪费时间去执行垃圾回收以恢复内存的。
垃圾回收只与内存有关
那么
finalize()
方法到底是用于怎样的需求呢?即通过某种创建对象方式以外的方式为对象分配了内存。当使用了JNI(java native interface java本地接口),java代码和c/c++代码进行了相互调用,在c/c++中使用了malloc函数系列来分配内存空间,自然需要用free函数来释放内存,否则将会造成内存泄露。所以需要用finalize()方法来调用它。找到一篇关于垃圾回收机制的博客
今天就先写到这里。。。
2015年3月25日09:26:15
5.6初始化
声明局部变量时,如果没有顺带的初始化变量,会在编译阶段发生错误。
但是如果是类成员变量,每个基本类型的数据成员都会被保证有一个初始值(0,false,[],0.0),而引用变量的初始值为
null
,这个叫做自动初始化。需要注意的有一点,构造器可以进行类数据成员的初始化,但是无法阻止自动初始化的进行,因为自动初始化是在构造器被调用之前完成的。
在类的内部,变量定义的顺序决定了初始化的顺序,但是无论这些变量是否在方法之前还是之后被声明,仍旧会在任何方法(包括构造器)之前得到初始化。
- 如果父类的构造方法中有被子类重写的方法,执行
SuperClass super = new SubClass();
时,初始化时调用父类的构造函数,是执行父类的原方法,还是执行子类中被重写的方法呢?有例子:
class SuperClass...{
public SuperClass()...{
System.out.println("SuperClass of constructor");
m();
}
public void m()...{
System.out.println("SuperClass.m()");
}
}
public class SubClassTest extends SuperClass ...{
private int i = 10;
public SubClassTest()...{
System.out.println("SubClass of constructor");
super.m();
m();
}
public void m()...{
System.out.println("SubClass.m(): i = " + i);
}
public static void main(String[] args)...{
SuperClass t = new SubClassTest();
}
}
/*
可能很多人会认为输出为:
SuperClass of constructor
SubClass.m(): i = 10
SubClass of constructor
SuperClass.m()
SubClass.m(): i = 10
其实不然!
正确输出为:
SuperClass of constructor
SubClass.m(): i = 0
SubClass of constructor
SuperClass.m()
SubClass.m(): i = 10*/
这是什么原因呢?
在生成对象时,父类调用的M()方法,不是父类的 M()方法,而时子类中被重写了的M()方法!!并且还出现一个怪异的现象,子类的privte int i 也被父类访问到,这不是和我们说private的成员只能在本类使用的原则相违背了吗?其实我们说的这条原则是编译期间所遵守的,在JAVA程序的编译期间,它只检查语法的合法性,在JAVA的JVM中,即运行期间,不管你声明的什么,对于JVM来说都是透明的,而多态是在运行期间执行的,所以能拿到SubClass的private成员,一点都不奇怪,只是此时还没执行 i = 10,所以在父类的构造方法中调用m()时,系统只能将i赋予系统初值0。
静态数据的初始化
静态初始化只有在必要的时刻才会进行,只有在第一个类对象被创建或者第一次访问静态数据的时候,它们才会被初始化。
初始化的顺序是
静态对象->非静态对象
静态块(跟在
static
关键字后的代码块)与其他静态初始化动作一样,在非静态对象前被初始化。
非静态实例初始化
和静态块初始化类似,只不过在代码块(实例初始化子句)前没有static
关键字。例如
public class Dog{
private int age;
private int sex;
{
age = 1;
sex = 1;
}
public Dog(){}
public Dog(int age){ this.age = age;}
//...
}
实例初始化子句会在构造函数被调用前完成操作,保证了不论哪个构造器被调用,都能执行统一的操作。
2015年4月4日21:00:39
8多态
8.2.1方法调用的绑定
将方法调用和一个方法主体关联起来叫做绑定。
若在程序执行前进行绑定,叫做前期绑定,如果在运行时根据对象类型进行绑定,叫做后期绑定。
后期绑定也被称作动态绑定,保证了多态的实现。
8.3.3 构造器内部的多态方法的行为
参看5.6初始化 第五条的示例
用尽可能简单的方法使得对象进入正常状态,如果可以的话,不要调用其他方法(尤其是能被子类重写的方法)。在构造器中唯一能安全调用的是基类中的final
方法(也包括private
方法,它们自动属于final
方法)。这些方法不能被覆盖,因此也就不会出现上面的问题。
8.4协变返回类型
在子类中的被覆盖方法的返回值类型,可以是父类该方法返回值类型的子类。即
class Flower{
public Flower(){System.out.println("flower");}
}
class Rose extends Flower{
public Rose(){System.out.println("rose");}
}
class Factory{
public Factory(){}
public Flower getFlower(){return new Flower;}
}
class RoseFactory{
public RoseFactory(){}
public Rose getFlower(){return new Rose();}
public static void main(String[] args){
Factory f = new Factory();
RoseFactory rf = new RoseFactory();
f.getFlower();
rf.getFlower();
}
/*输出:
flower
rose
*/
}