zoukankan      html  css  js  c++  java
  • 方法对象java final关键字的用法

    之前一直在查找方法对象之类的问题,今天正好有机会和大家讨论一下.

        1.用final关键字设置常数

        很多程序设计语言都有自己的方法告知编译器某个数据是“常数”。常数重要应用于下述两个方面:
    (1) 编译期常数,它永久不会转变
    (2) 在运行期初始化的一个值,我们不希望它发生变化
    对于编译期的常数,编译器(程序)可将常数值“封装”到须要的计算过程里。也就是说,计算可在编译期间提早执行,从而节省运行时的一些开销。在Java中,这些形式的常数必须属于基本数据类型(Primitives),而且要用final关键字进行抒发。在对这样的一个常数进行定义的时候,必须给出一个值。
    无论static还是final字段,都只能存储一个数据,而且不得转变。
    若随同对象句柄应用final,而不是基本数据类型,它的含意就稍微让人有点儿含糊了。对于基本数据类型,final会将值变成一个常数;但对于对象句柄,final会将句柄变成一个常数。进行声明时,必须将句柄初始化到一个详细的对象。而且永久不能将句柄变成指向另一个对象。然而,对象本身是可以修改的。Java对此未提供任何手腕,可将一个对象直接变成一个常数(但是,我们可自己编写一个类,使其中的对象拥有“常数”效果)。这一限制也适用于数组,它也属于对象。
    下面是演示final字段用法的一个例子:

        //: FinalData.java
    //The effect of final on fields

        class Value {
     int i = 1;
    }

        public class FinalData {
     // Can be compile-time constants
     final int i1 = 9;
     
     static final int I2 = 99;
     // Typical public constant:
     public static final int I3 = 39;
     // Cannot be compile-time constants:
     final int i4 = (int) (Math.random() * 20);
     static final int i5 = (int) (Math.random() * 20);
     
     static int i6 = 8;

     Value v1 = new Value();
     final Value v2 = new Value();
     static final Value v3 = new Value();
     // ! final Value v4; // Pre-Java 1.1 Error:
     // no initializer
     // Arrays:
     final int[] a = { 1, 2, 3, 4, 5, 6 };

     public void print(String id) {
      System.out.println(id + ": " + "i4 = " + i4 + ", i5 = " + i5);
     }

     public static void main(String[] args) {
      FinalData fd1 = new FinalData();
         //! fd1.i1++;// Error: can't change value
      fd1.v2.i++; // Object isn't constant!
      System.out.println(fd1.v2.i);
      fd1.v1 = new Value(); // OK -- not final
      for (int i = 0; i < fd1.a.length; i++)
       fd1.a[i]++; // Object isn't constant!
      //! fd1.v2 = new Value(); // Error: Can't
      //fd1.v3 = new Value(); // change handle
       //fd1.a = new int[3];

      fd1.print("fd1");
      System.out.println("Creating new FinalData");
      FinalData fd2 = new FinalData();
    //  fd1.print("fd1");
    //  fd2.print("fd2");
      
      fd2.i6++;
      System.out.println(fd2.i6);
     }
    } // /:~

        
    由于i1和I2都是拥有final属性的基本数据类型,并含有编译期的值,所以它们除了能作为编译期的常数应用外,在任何导入方式中也不会涌现任何不同。I3是我们体验此类常数定义时更典型的一种方式:public表现它们可在包外应用;Static强调它们只有一个;而final标明它是一个常数。注意对于含有牢固初始化值(即编译期常数)的fianl static基本数据类型,它们的名字根据规则要全体采用大写。也要注意i5在编译期间是未知的,所以它没有大写。
    不能由于某样东西的属性是final,就认定它的值能在编译时代知道。i4和i5向大家证明了这一点。它们在运行期间应用随机生成的数字。例子的这一部份也向大家揭露出将final值设为static和非static之间的差异。只有当值在运行期间初始化的前提下,这类差异才会揭露出来。因为编译期间的值被编译器认为是相同的。这类差异可从输出结果中看出:

        

        

    fd1: i4 = 15, i5 = 9
    Creating

        new

        FinalData fd1: i4 = 15, i5 = 9 fd2: i4 = 10, i5 = 9

        

        注意对于fd1和fd2来讲,i4的值是独一的,但i5的值不会由于创立了另一个FinalData对象而发生转变。那是因为它的属性是static,而且在载入时初始化,而非每创立一个对象时初始化。
    从v1到v4的变量向我们揭露出final句柄的含意。正如大家在main()中看到的那样,并不能认为由于v2属于final,所以就不能再转变它的值。然而,我们确切不能再将v2绑定到一个新对象,因为它的属性是final。这便是final对于一个句柄的确切含意。我们会发现一样的含意亦适用于数组,后者只不过是另一种类型的句柄而已。将句柄变成final看起来仿佛不如将基本数据类型变成final那么有效。

        每日一道理
    信念是巍巍大厦的栋梁,没有它,就只是一堆散乱的砖瓦;信念是滔滔大江的河床,没有它,就只有一片泛滥的波浪;信念是熊熊烈火的引星,没有它,就只有一把冰冷的柴把;信念是远洋巨轮的主机,没有它,就只剩下瘫痪的巨架。

        2.空白final
    Java 1.1答应我们创立“空白final”,它们属于一些特殊的字段。尽管被声明成final,但却未失掉一个初始值。无论在哪种情况下,空白final都必须在现实应用前失掉正确的初始化。而且编译器会自动保障这一划定得以贯彻。然而,对于final关键字的各种应用,空白final拥有最大的灵活性。举个例子来讲,位于类外部的一个final字段现在对每一个对象都可以有所不同,同时仍然坚持其“不变”的本质。下面列出一个例子:

           

        package com.finaltest;

        class Poppet{
     
    }

        public class BlankFinal {
       
     final int i = 0;
     final int j;
     final Poppet p;
     
     public BlankFinal() {
           j=1;
           p = new Poppet();
     }
     
     public BlankFinal(int x){
      j = x;
      p = new Poppet();
     }
     
     public static void main(String[] args) {

      BlankFinal bf = new BlankFinal();
     }

        }

        现在强行要求我们对final进行赋值处理——要么在定义字段时应用一个抒发 式,要么在每一个构建器中。这样就可以确保final字段在应用前取得正确的初始化。

        3. final自变量
    Java 1.1答应我们将自变量设成final属性,方法是在自变量列表中对它们进行恰当的声明。这意味着在一个方法的外部,我们不能转变自变量句柄指向的东西。如下所示:

        //Using "final" with method arguments

        
    class Gizmo{
     public void spin(){}
    }

        public class FinalArguments {

     void with(final Gizmo g){
      //! g = new Gizmo();//Illdgal -- g is final
      g.spin();
     }
     
     void without(Gizmo g){
      g = new Gizmo();
      g.spin();
     }
     
     void f(final int i){
      //i++;//i can't change
     }
     
     int g(final int i){
      return i+1;
     }
     
     public static void main(String[] args) {
      FinalArguments bf = new FinalArguments();
      bf.without(null);
      bf.with(null);
     }
    }

        注意此时仍然能为final自变量分配一个null(空)句柄,同时编译器不会捕获它。这与我们对非final自变量采取的操纵是一样的。
    方法f()和g()向我们展示出基本类型的自变量为final时会发生什么情况:我们只能读取自变量,不可转变它。

        4.final方法
    之所以要应用final方法,可能是出于对两方面来由的考虑。第一个是为方法“上锁”,防止任何继承类转变它的原来含意。设计程序时,若希望一个方法的行为在继承期间坚持不变,而且不可被覆盖或改写,就可以采取这类做法。
    采用final方法的第二个来由是程序执行的效率。将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个final方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。相反,它会用方法主体内现实代码的一个副原来替换方法调用。这样做可防止方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能受到到不到嵌入代码所带来的任何性能晋升。因为任何晋升都被花在方法外部的时间抵消了。Java编译器能自动侦测这些情况,并很是“理智”地决定是不是嵌入一个final方法。然而,最好还是不要完全相信编译器能正确地作出所有判断。通常,只有在方法的代码量非常少,或者想明白禁止方法被覆盖的时候,才应考虑将一个方法设为final。
    类内所有private方法都自动成为final。由于我们不能访问一个private方法,所以它绝对不会被其他方法覆盖(若强行这样做,编译器会给出错误提示)。可为一个private方法添加final指示符,但却不能为那个方法提供任何额外的含意。

        5.final类
    如果说整个类都是final(在它的定义前冠以final关键字),就标明自己不希望从这个类继承,或者不答应其他任何人采取这类操纵。换言之,出于这样或那样的原因,我们的类肯定不须要进行任何转变;或者出于安全方面的来由,我们不希望进行子类化(子类处理)。
    除此以外,我们或许还考虑到执行效率的问题,并想确保涉及这个类各对象的所有行动都要尽可能地有效。如下所示:

        //Making an entire class final

        class SmallBrain{
     
    }

        final class Dinosaur{
     int i=7;
     int j=1;
     SmallBrain x = new SmallBrain();
     
     void f(){}
    }

        public class Jurassic {
     
     public static void main(String[] args) {

      Dinosaur n = new Dinosaur();
      n.f();
      n.i=40;
      n.j++;
     }

        }

        注意数据成员既可以是final,也可以不是,取决于我们详细选择。应用于final的规则一样适用于数据成员,无论类是不是被定义成final。将类定义成final后,结果只是禁止进行继承——没有更多的限制。然而,由于它禁止了继承,所以一个final类中的所有方法都默认为final。因为此时再也无法覆盖它们。所以与我们将一个方法明白声明为final一样,编译器此时有相同的效率选择。
    可为final类内的一个方法添加final指示符,但这样做没有任何意义。

        

        

     

        

    文章结束给大家分享下程序员的一些笑话语录: 大家喝的是啤酒,这时你入座了。
    你给自己倒了杯可乐,这叫低配置。
    你给自已倒了杯啤酒,这叫标准配置。
    你给自己倒了杯茶水,这茶的颜色还跟啤酒一样,这叫木马。
    你给自己倒了杯可乐,还滴了几滴醋,不仅颜色跟啤酒一样,而且不冒热气还有泡泡,这叫超级木马。
    你的同事给你倒了杯白酒,这叫推荐配置。
    菜过三巡,你就不跟他们客气了。
    你向对面的人敬酒,这叫p2p。
    你向对面的人敬酒,他回敬你,你又再敬他……,这叫tcp。
    你向一桌人挨个敬酒,这叫令牌环。
    你说只要是兄弟就干了这杯,这叫广播。
    有一个人过来向这桌敬酒,你说不行你先过了我这关,这叫防火墙。
    你的小弟们过来敬你酒,这叫一对多。
    你是boss,所有人过来敬你酒,这叫服务器。
    酒是一样的,可是喝酒的人是不同的。
    你越喝脸越红,这叫频繁分配释放资源。
    你越喝脸越白,这叫资源不释放。
    你已经醉了,却说我还能喝,叫做资源额度不足。
    你明明能喝,却说我已经醉了,叫做资源保留。
    喝酒喝到最后的结果都一样
    你突然跑向厕所,这叫捕获异常。
    你在厕所吐了,反而觉得状态不错,这叫清空内存。
    你在台面上吐了,觉得很惭愧,这叫程序异常。
    你在boss面前吐了,觉得很害怕,这叫系统崩溃。
    你吐到了boss身上,只能索性晕倒了,这叫硬件休克。

  • 相关阅读:
    thinkphp5 数据库和模型
    DAO设计模式
    JSP内置对象
    JSP基础
    Head First Servlet and JSP
    Maven项目中,系统设置的CLASSPATH环境变量问题
    HTML简介
    (三)Maven使用入门之Hello World
    (一)JUnit简介
    (二)Web应用体系结构
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3087220.html
Copyright © 2011-2022 走看看