gdufo

 

final 于 abstract 的问题

第一题:
   class Something{
        final int f;
      public void doSomething(){
            System.out.println("f="+f)
        }
    }
第二题:
    abstract class Something{
        private abstract void doSomething();
    }

出错在哪里?

1)Something类在实例化的时候,会对成员变量进行初始化,f会被赋值于0,按照语法结果就是f=0,可是实际上不是。Java编译器为了减少人犯低级错误,对final修饰的变量不会再进行默认初始化,而是强制要求你显示的赋一个值。Java编译器考虑的可真周到啊,把它自己的语法都给推翻了。这么低级的程序我是写不出来,所以我答错了。
2)这一题按照语法也没错了,可是为什么会被编译不过去呢,说白了原因也就是Java编译器为我们考虑太周到了,我们为什么要在抽象类中定义一个抽象方法,我们大家都知道抽象类是不能实例化,定义抽象方法就是为了定义一个子类来继承该抽象类并实现它的抽象方法,但是题目中给定的抽象方法是private修饰的,也就是说它是不能被继承的,也就是说我们根本不肯能写出来一个能实现该抽象方法的类,说的更具体一点也就是这个抽象类被定义的毫无意义。Java编译器真是太强了,连这个也被考虑到了,反正我是从来没写过这么低级的程序,更不会去写出来一个毫无意义的抽象类。
一句话,这两道题考得不是final和abstract的语法,因为完全合法,而是语义,也就是Java编程规范。
 PS:关于为什么final修饰的成员变量不能被默认初始化的问题,我想了很久,终于想明白了。我们大家都知道对象初始化分为三步:
1)默认初始化
2)赋值初始化
3)构造方法初始化
如果你在类中定义的是一个普通的成员变量非final成员变量,对该类的对象初始化时,该成员变量会严格按照以上三步进行初始化。如果是该类的成员变量是用final修饰的,该类对象初始化时,对该成员变量的初始化按照常规也应该由这三步组成,但是由于final修饰的变量是常量,不能进行二次赋值,所以对该类型的变量初始化只能由其中一步来完成,不能出现交叉,否则会有编译错误。下面是两个可以正常编译、运行的写法:
/**
 * 
 * 
@author <a href="mailto:flustar2008@163.com">flustar</a>
 * 
@version 1.0 Creation date: Mar 22, 2008 7:18:18 PM
 
*/

public class TestFinal {
    
final int f=1;
    
public void doSomething() {
        System.out.println(
"f=" + f);
    }

    
public static void main(String args[]) {
        TestFinal test 
= new TestFinal();
        test.doSomething();
    }

}

/**
 * 
 * 
@author <a href="mailto:flustar2008@163.com">flustar</a>
 * 
@version 1.0 Creation date: Mar 22, 2008 7:18:18 PM
 
*/

public class TestFinal {
    
final int f;
    
public TestFinal(){
        f
=1;
    }

    
public void doSomething() {
        System.out.println(
"f=" + f);
    }

    
public static void main(String args[]) {
        TestFinal test 
= new TestFinal();
        test.doSomething();
    }

}
下面再让我们回过头来看看下面这个程序它完全符合Java的语法:
class Something{
        
final int f;
      
public void doSomething(){
            System.out.println(
"f="+f)
        }

    }

为什么说它完全符合语法:
1)按照常理会对f默认初始化为0;
2)程序中并没有出现交叉,也就是说并没有进行二次赋值的可能。
但是编译器为什么不放过它呢?
现在让我们来假设一下如果不给f变量不显示的赋一个值,它一定会被初始化为0,按照final的定义一旦被初始化一个值后就不能修改了,也就是说f的值只能是0了。再想想当初我们为什么要定义一个final修饰的常量,难道仅仅就是为了得到一个默认的不能修改的初始值吗,这恐怕有违我们当初定义final变量的真正意愿,那么我定义这个final变量又有何意义呢。所以在对对象进行初始化时,发现对象的成员是用final修饰的就会查看它是否被显示的赋了值,如果没有就会不能正常编译。这也是Java编程规范中为什么要强制对final变量进行显示赋值的真正原因。同样的道理在abstract类里面定义private abstract方法,这个又有何意义呢?Java中把那些符合语法但不符合常规的用法定义成了规范,我想这也是Java为什么会有编程规范的原因吧,呵呵,扯远了。。。

posted on 2008-08-14 21:39 gdufo 阅读(550) 评论(0)  编辑  收藏 所属分类: JAVA 基础


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

常用链接

留言簿(6)

随笔分类

随笔档案

文章分类

文章档案

收藏夹

Hibernate

友情链接

搜索

最新评论

阅读排行榜

评论排行榜