假设在源码中有这样一行:
manager.setBonus(2300);
下面来看看javac编译器是如何处理的:
final关键字可以用于修饰类、成员方法和成员变量,其主要用途:
public final class CChild extends CBase {
//...
}
public class CBase {
public final void setID(int id) {
//...
}
}
在此例中,CBase的任何子类都不能对setID方法进行覆写了。如果某个类中有一个名为func1的final方法,我们来进行如下分析:
其父类中若有func1方法且没设置final属性,虽然其子类的func1()方法被设置了final属性,但为了实现多态效果,依然会使用invokevirtual(按虚函数调用)的方式进行调用。
其子类不可能覆写该方法,所以可以在编译器静态绑定。虽然理论上如此,但Java8 SE中依然使用的是invokevirtual(按虚函数调用)的方式进行调用。
public class CNo1 {
public final void func4() {
System.out.println("CNo1::func4");
}
}
public class CDemo1 {
public static void main(String[] args) {
CNo1 n = new CNo1();
n.func4();
}
}
//javap看到的结果
Code:
stack=2, locals=2, args_size=1
0: new #2 // class CNo1
3: dup
4: invokespecial #3 // Method CNo1."":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method CNo1.func4:()V
12: return
public class CTest {
private static final double PI = 3.141592653;
//...
}
final类中的所有方法将自动成为final方法,但其中的成员变量不会自动变成final类型变量。
在类型转换方面,Java抛弃了C++定义的那套复杂的语法,返璞归真的使用了C的类型转换形式:
类型1 名称 = (类型1) 其他类型的对象;
一般只有两类转换是正常的:
为了保证类型转换的安全,JVM也提供了类似C++的RTTI机制,判明转换是否能成功:
boolean bRet = 类对象 instanceof 类;
只有bRet返回true时,才能安全地进行转型。注意,如果类对象为null,则表达式返回false。
再强调一次,向下转型不是一个好的设计,应该避免使用!
Manager* boss = dynamic_cast(staff);
if (boss)
{
//转型成功,进行后续操作...
}
C++是将转型与判断过程都集中在dynamic_cast过程中了,如果不成功,返回的boss为NULL,否则为对象的指针。
if (staff instanceof Manager) {
Manager boss = (Manager) staff;
//执行后续操作
}
Java中转换是否能成功的判定由instanceof完成,而类型转换则会直接进行转换,如果转换失败,要么是编译时报错,要么运行时抛异常。所以在转换前,必须先用instanceof投石问路。
在C++里有纯虚函数的概念,而包含纯虚函数的类无法实例化。在Java中,也有类似的语法:用abstract关键字修饰成员方法,则该方法成为一个抽象方法,抽象方法无需有实现,只要有声明即可。注意:包含抽象方法的类必须也要加上abstract关键字成为抽象类。
以著名的Shape为例,世界上有圆形、矩形等等,他们都是图形,但谁也无法定义“图形”,因为这是一个抽象的概念,因此,Shape类无需实例化。但所有图形都有一个draw的行为,即在画布上画出自己,因此考虑将其作为Shape类的成员方法。但由于Shape类是个抽象类,因此也没必要实现draw的动作,故该方法在Shape类中被定义为了抽象方法。
public abstract class Shape {
public abstract boolean draw(Cloth cloth);
}
需要注意的是:
ArrayList shapelists = new ArrayList();
shapelists.add(new Circle(3, 2, 1));
shapelists.add(new Rectangle(6, 6, 4, 2));
//...
for (Shape currentShape : shapelists) {
currentShape.draw(cloth);
}
在C++中,访问标识要和继承类型结合起来,所以一共有9种情况。记得某一年期末考试题还考这玩意儿…
而到了Java中,由于继承类型全部是公有继承了,再配合三个关键字,一共实现了4种类型。三个关键字怎么实现了4种访问控制级别呢?当然是不加这三个关键字默认有一种喽。