代码改变世界

Java基础知识的十个盲点

2004-12-25 11:57  FantasySoft  阅读(2212)  评论(1编辑  收藏  举报

        连续三天的Java Language Fundamental Knowledge培训,整体是会让那些有经验的Java程序员哈欠连天的。原本也想坐到Training Room的后排敷衍了事,不过想想自己的基础,最后还是选择了坐到第一排。
        三天的课程平淡无奇,讲的无非是任何一本Java语言速成类的书籍都会讲到的内容。不过,当面对着
这么多纷繁复杂的基础知识时候,我还是发现不少的盲点,或许有些错误的认识还很低级的呢,大家见笑了。
        1、数字类型的后缀(如double类型使用d,long类型使用l等)的作用;关于这一点,我们先来看一个变量的定义:int i = 2200000000;这个当然不会编译通过,因为这个数字已经超过了int类型的范围,很自然的,我将int改成了long。大家觉得修改过后是不是可以编译通过了呢?实际上仍然是不行的,不仅不能给int类型的i赋上一个超过int范围的数字,而且2200000000也不能这样孤零零的存在,因为它要告诉编译器:我是一个long类型的数。只有在2200000000后面加上l之后,才是一个真正合法的变量定义
        2、class的modifier到底可以用哪几个,分别具有怎样的作用;这一点是比较简单,但是问一下,
private可以用作class的modifier呢?你是否会犹豫呢?能够用作class的modifier只有几个:final,abstract,public和default modifier;
        3、method和field的accessible modifier中默认modifier(即是没有使用public、protected或者
private)的受限制程度是比protected高,还是低呢?对于这个问题,我一直都不是很清晰。正确的答案是高的。默认的accessible modifier使得method和field具有package级别的可访问性,package以外的class是不可以访问这些method和field的,而protected则不然,在package以外,如果是该class的子类则可以访问到protected修饰的method和field,却访问不到默认modifier修饰的method和field;
        4、构造函数是否可以使用final或者abstract的修饰符呢?答案是不行的。构造函数只能使用
accessible modifier;
        5、构造函数是不能有返回值的,也就是不能在其函数名前加上返回值的修饰符。那么如果定义了一
个与类同名的具有返回值的函数会不会产生编译错误呢?这个问题请看下面的代码:     

class Test {
    
public void Test() 
{
    }

}

        很明显,我不会这样写,但是这段代码会产生编译错误吗?结果是不会的。因为这只是类Test中的一个返回值为void的方法。使用javac编译是不会有任何提示的。但是,使用jikes则会给出一个warning以告诉programmer:类Test中包含了一个跟构造函数同名的函数。从这里也可以看出jikes作为Java编译器具有比javac更加专业的一面;
        6、synchronized这个关键字,可以用在class的field前面吗?答案是不行的。synchronized只能用在
方法上,以及定义同步的block;
        7、当一个父类显式定义了一个非默认的构造函数(也就是带参数的构造函数)的时候,子类是否一定需
要自己定义构造函数呢?答案是一定要的。大家先看以下代码:     

Class SuperClass {
    SuperClass(
int i) {}

}

Class SubClass extends SuperClass 
{
}

       在SubClass中,我们是一定要显式定义一个构造函数,然后在构造函数中调用父类的构造函数的,否则就无法编译通过,编译的错误是父类没有定义默认的构造函数。从编译错误的提示中,我们可以找到另外的解决方法,就是在SuperClass当中再定义一个默认的构造函数即可,子类就不用煞有介事的自己去定义一个构造函数去调用父类的构造函数,然后啥也不做了。因此,我觉得应该养成一种习惯,就是需要定义非默认的构造函数的时候,别忘了将默认的构造函数也定义一遍,这样就可以给扩展的子类提供方便了;
        8、在interface中定义的field是static的吗?是final的吗?答案是interface中的field是static和final 的。在interface定义的field
是必须初始化的,同时也是可以通过intefaceName.fieldName的方式去访问的;
        9、这个问题是关于abstract的,大家先看以下代码:

abstract class Foo {
    
void
 test();
}

        这样写有问题吗?我开始是觉得没有问题的,但是实际上这样是会有编译错误的。原因很简单,因为test方法并不是abstract的,需要加上方法体的标志——{};或者说如果一个方法没有方法体,那么必须声明其是abstract的。
        10、最后一个问题是关于instanceof的,大家也先看看以下代码:

class A {}
class B extends A {}
class C extends B {}
class Test {
    
public static void main(String[] args) 
{
        C c 
= new
 C();
        System.
out
.println(c instanceof A);
    }

}

        print出来的会是true还是false呢? 答案很简单,是true。不过,我一直都以为是false,因为c只是类C的实例,但是我忘了一点,每当使用new关键字去创建一个实例的时候,都会逐个 层次地调用其父类的构造函数,那么这里instanceof返回确实应该是true了。