笔记索引
每个类都可以创建main函数
说明
在Java中,可以为每一个类创建一个main()方法,这使得测试每个类变得简单易行,而且在测试过后也无需删除main(),可以留待下次测试。即使一个程序中包含多个类,也只有命令行所调用的那个类的main()方法会被调用;即使这个类只有包访问权限,这个类的main()方法也可以被调用。
示例
以两个不同包的编译单元为例:
package com.phycanva.demonstrate;
public class Multimain {
public static void main(String[] args) {
System.out.println("public类主函数");
}
}
class Multimain_package{
public static void main(String[] args) {
Multimain.main(args);
System.out.println("包访问权限类主函数");
}
}
package com.phycanva.demonstrate.assist;
import com.phycanva.demonstrate.*;
public class Multimain_out {
public static void main(String[] args) {
Multimain.main(args);
//!Multimain_package.main(args); //错误:不在同一个包内,不可见
}
}
我所使用的IDE是Eclipse。
在运行时如果一个编译单元中有多个类,可以选择其中的一个类进行运行,如下图:
在访问权限范围内,类可以调用其他类的main()函数。
我们不妨把“类”当成运行的目标,而把“main()”当成一个特殊的方法:它既有作为一般public static方法的特性,也是运行类的入口。
代理
说明
Java没有对代理的直接支持,但可以进行手动实现。代理是继承和组合的中庸之道:我们像组合一样把一个成员对象置于所要构造的类中;与此同时我们像继承一样,在新类中暴露了该成员对象的所有方法。
示例
package com.phycanva.demonstrate;
public class ControlCenter {
void command1() {
System.out.println("指令1");
}
void command2() {
System.out.println("指令2");
}
}
class Machine{
ControlCenter cc = new ControlCenter();
void command1() {
cc.command1();
}
void command2() {
cc.command2();
}
public static void main(String[] args) {
Machine m = new Machine();
m.command1();
m.command2();
}
}
通过手动构造两个方法来达到暴露接口的目的。
final关键字
final关键字的含义通常为“无法改变的”,使用final通常出于两种不同的考虑:设计和效率。
final数据
我们使用final来向编译器告知一块数据是恒定不变的
- 一个永不改变的编译时常量
- 一个在运行时被初始化、且恒定的值
当final修饰的常量为编译期常量的情况,编译器可以将该常量值代入所有用到它的地方(类似于C语言的宏)来进行优化;这类常量必须是基本数据类型,并且在定义时就要为其赋值。
当final运用于对象引用的时候,只能使引用的指向不变,而不能使引用指向的对象保持不变。
static final
当final和static连用时,数据会兼备static和final关键词所赋予的特性:
- 定义static:强调数据只有一份;
- 定义为final:强调数据是一个常量。
根据惯例,既是static、又是final的域(即编译期常量)应用大写表示,使用下划线分隔单词(这点和C中的常量相似)。
误区警示
注意:我们不能因为数据是final的,就认为可以在编译期间知道它的值
例如:
private static final int RAD = rand.nextInt(20);
显然只有在运行时,才可以确定RAD的确定值。
空白final
所谓“空白final”是指被声明为final却没有赋予初值的域,所以看上去好像没有被初始化一样。但是无论什么情况,编译器都能确保空白final在使用之前必须初始化
编译器确保final必须在两个地方进行初始化
- 在域的定义处(非空白final)
- 在每个构造器中(空白final)
final参数
说明这个参数是不能更改,即在这个方法中赋予参数只读的特性(这与C、C++中形参加const类似)
这一特性只要用于向匿名内部类传递数据
final方法
使用final的方法的原因有二:
- 设计方面:把方法锁定,防止任何继承类修改它的含义
- 效率方面:提高效率
private方法与final方法
对于方法而言,final和private有神似之处:final不允许继承类修改它的含义;private不允许被继承。因为不能被继承,所以不存在含义被修改的情况,即:所有的private方法都隐性地被指定为是final的。
误区警示
当我们试图通过继承来覆盖一个private方法的时候,似乎没什么毛病(编译器也不会报错),但是我们并没有真正覆盖成功。
package com.phycanva.demonstrate;
public class Father_fakeInherit {
protected void f1() {System.out.println("父类 f1");}
}
class Son_fakeInherit extends Father_fakeInherit {
public void f1() {System.out.println("子类 f1");}
public static void main(String[] arg ) {
Son_fakeInherit s = new Son_fakeInherit();
s.f1();
Father_fakeInherit f = s;
f.f1();
}
}
当被继承方法为protected时,父类中定义的方法被覆盖,输出:
子类 f1
子类 f1
package com.phycanva.demonstrate;
public class Father_fakeInherit {
private void f1() {System.out.println("父类 f1");}
}
class Son_fakeInherit extends Father_fakeInherit {
public void f1() {System.out.println("子类 f1");}
public static void main(String[] arg ) {
Son_fakeInherit s = new Son_fakeInherit();
s.f1();
Father_fakeInherit f = s;
f.f1();
}
}
将protected更改为private时,在调用时出现错误:
The method f1() from the type Father_fakeInherit is not visible
表示父类实例无法从外部调用f1()方法,这就说明了父类的f1()没有被覆盖(如果被覆盖了,应该成功调用子类public的f1()方法)
“覆盖”仅在某方法是父类的接口的一部分时才会出现。即:必须能将一个对象向上转型为它的基本类型,并调用相同的方法。如果某方法是private,它就不是父类接口的一部分,即private方法无法被继承,它仅是所在类内部的一部分。
final类
当一个类被整体定义为final的时候,表明这个类无法被继承,所以类中所有的方法都被隐式地指定为final,在final类中给方法加final修饰,要么是为了提高可读性,要么纯属闲得蛋疼。
后记
由于仍处于学习阶段,文章中的内容很可能不够准确也不够全面。文中若有错误出现,敬请指出,一定虚心改正;有需要补充修改的地方,也请各位不吝赐教,十分乐意与大家交流学习。