精华内容
下载资源
问答
  • 1.当final修饰一个类的时候,那么该类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。 比如在java.lang包里面不能被继承的类 public final class Byte public final class Character public ...


    首先,final的用法:在什么时候需要使用final?

    1.当final修饰一个类的时候,那么该类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。

    比如在java.lang包里面不能被继承的类


    public final class Byte
    public final class Character
    public static final class Character.UnicodeBlock
    public final class Class<T>
    public final class Compile
    public final class Double
    public final class Float
    public final class Integer
    public final class Long
    public final class Math
    public final class ProcessBuilder
    public final class RuntimePermission
    public final class Short
    public final class StackTraceElement
    public final class StrictMath
    public final class String
    public final class StringBuffer
    public final class StringBuilder
    public final class System
    public final class Void 

    另外一种阻止类的继承的方法是显示的将构造函数置为private,这样的话子类将调用不了超类的方法,也就达到了不能被继承类的作用。

    那么为什么不让继承这个类呢(他怎么这么自私不让被继承2333)?

    答:final,防止任何继承类改变它本来的含义(也可以说是上锁吧)当你将final用于类身上时,一个final类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要
    进行修改或扩展。对于final类中的成员,你可以定义其为final,也可以不是final。而对于方法,由于所属类为final的关系,自然也就成了final型的。当然也可能会有安全方面的因素,使用final不进行子类化。

    final对于方法中为什么要用到?

    答:目的其实是给方法进行上锁,一个方法在继承期间保持不变,不能被覆盖或者改写,就可以采用这个做法。

     

    采用final方法对于程序执行效率上面有什么优势?

    答:编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个final方法调用,
    就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。
    相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销
    Java编译器能自动侦测这些情况,并颇为“明智”地决定是否嵌入一个final方法。然而,最好还是不要
    完全相信编译器能正确地作出所有判断。通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。类内所有private方法都自动成为final。由于我们不能访问一个private方法,所以它绝对不会被其他方法覆盖(若强行这样做,编译器会给出错误提示)。
    可为一个private方法添加final指示符,但却不能为那个方法提供任何额外的含义。

     

    被final修饰的变量的特点?

    答:被final修饰的变量其实就相当于定义了一个常量,无法被修改的变量,如果final修饰的是一个基本数据类型的变量,那么这个变量的值就定了,不能变了,而如果修饰的是一个引用变量,那么该变量存的是一个内存地址,该地址就不能变了但是该内存地址所指向的那个对象还是可以变的
    (final修饰的变量地址不能变,但是地址所指向的对象可以变)(家被固定了,但是住着谁无所谓)

     

    给方法定义的参数是 final类型的是不想别人在方法内部修改参数的值如果final修饰的是一个基本类型,那么是可以的,如果修饰的是引用类型,那么便不行了,因为就如上文那个str.append 对象的内容是可以变化的!(所以方法的入参是引用类型的变量其实并不能防止别人更改ta的内容)

     

     

    附:java基本的数据类型(java分为基本的数据类型和引用类型)

    byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0

    short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0

    int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0

    long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L

    float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0

    double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0

    char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空 (char的话两个字节!!1 byte = 8 bit ;char 在java中是2个字节。java采用unicode,2个字节(16位)来表示一个字符!!

    boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false

     

    展开全文
  • 前言 我们在了解final关键字...final关键字修饰变量、方法和类,不管修饰什么,其本意都是指“它是无法更改的”。本文将介绍final关键字: final关键字修饰变量 final关键字修饰方法参数 final关键字修饰方法 final...

    前言

    我们在了解final关键字之前,可以先从它的字面意思去理解,有道翻译查询如下:
    在这里插入图片描述
    也就是说,final的中文意思就是最终的、不可改变的。在Java中,final关键字表达的也是这样的意思。final关键字修饰变量、方法和类,不管修饰什么,其本意都是指“它是无法更改的”。本文将介绍final关键字:

    • final关键字修饰变量
    • final关键字修饰方法参数
    • final关键字修饰方法
    • final关键字修饰类

    (若文章有不正之处,或难以理解的地方,请多多谅解,欢迎指正)

    final关键字修饰变量

    只要是被final修饰的成员变量或本地变量(在方法中或在代码块中的变量称为本地变量)都称为final变量,final变量经常和static关键字一起使用,作为常量。用final关键字修饰的变量,只能进行一次赋值操作,并且生存期间不可以改变其值。

    不过final关键字在基本数据类型和引用类型产生的效果还是有点区别。举个栗子:

    public class Cats {
        public static void main(String[] args){
            final int catNum = 6;
            final Cat c = new Cat("black");
            catNum = 5;  //Cannot assign a value to final variable 'catNum'
            c.color = "white";  //正常执行
            c = new Cat("brown");  //Cannot assign a value to final variable 'c'
        }
    }
    class Cat{
        String color;
        public Cat(String color){
            this.color = color;
        }
    }
    

    从上述代码可以看出,final关键字对于基本数据类型和引用类型的效果是一样的:只能进行一次赋值操作,并且生存期间不可以改变其值。而且,虽然final关键字限制引用类型的引用地址,但并不会对引用类型的内部属性进行限制,所以c.color = "brown"是可以正常执行的。

    final关键字修饰方法参数

    上文提到,final关键字修饰变量时,该变量只能进行一次赋值操作,且不能改变其值。如果变量是作为参数传入的,那么我们怎么保证它的值不会改变呢?这就用到了final的第二个用法。

    public static void print(final int i, final Date date){
            i = 1;  //Cannot assign a value to final variable 'i'
            date = new Date();  //Cannot assign a value to final variable 'date'
            System.out.println(i);
        }
    

    可以看到,如果我们不希望传入的参数在方法中被改变,可以在方法签名中声明该参数被final关键字修饰

    final关键字修饰方法

    如果你认为一个方法的功能已经足够完整了,在方法前面声明final,代表这个方法不可以被子类的方法重写。因为final方法在编译的时候就已经静态绑定了,不需要运行时再动态绑定,所以final方法比非final方法要快一点

    class BlackCat extends Cat{
        public String getColor(){
            //'getColor()' cannot override 'getColor()' in 'Cat'; overridden method is final
        }
    }
    class Cat{
        private String color = "white";
        final public String getColor(){
            return color;
        }
    }
    

    那么“在开发过程中,private修饰方法隐式等同于使用final修饰“,这是真的吗?举个栗子:

    在使用final修饰方法时,子类方法是不能复写父类中用final修饰的方法:

    public class Cat{
        final void meow(){}
    }
    class BlackCat extends Cat{
        void meow(){}  //'meow()' cannot override 'meow()' in 'Cat'; overridden method is final
    }
    

    而使用private修饰方法时,虽然子类中可以存在于父类同名的private方法,但这个方法却不是从父类那里继承过来的了:

    public class Cat{
        private void meow(){}
    }
    class BlackCat extends Cat{
        @Override //Method does not override method from its superclass
        private void meow(){}
    }
    

    但是如果直接说,“private修饰方法等同于使用final修饰“,笔者不太认同,举个栗子:

    public class Cat{
        private void getColor(){}
        private final void getFood(){}
        final void getOwner(){}
    }
    

    我们进行编译之后,使用idea的插件jclasslib Bytecode Viewer查看Cat类的字节码,我们可以通过class文件中,专门描述方法的方法表的访问标志access_flags来判断:

    首先是private void getColor()方法:
    在这里插入图片描述
    此次是private final void getFood()方法:
    在这里插入图片描述
    最后是final void getOwner()方法:
    在这里插入图片描述
    总结一下,所有final关键字只有明确禁止重写方法的时候,才使用其修饰方法

    final关键字修饰类

    final关键字修饰类,表示这个类不可以被继承。所以如果不希望某个类有子类,就可以用final关键字来修饰。并且由于是用final关键字修饰的类,其类中的方法也会被隐式只为final方法

    在JDK中有很多类是final关键字修饰的,如String、Integer等。

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    

    结语

    本文主要对final关键字进行介绍,如果本文对你有帮助,请给一个赞吧,这会是我最大的动力~

    参考资料:

    Java关键字(四)——final

    Java中final关键字详解

    展开全文
  • final 关键字

    2015-02-09 23:49:03
     在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下final关键字的基本用法。  1.修饰类  当用final修饰一个类时,表明这个类不能被继承。也就是说,...

    一.final关键字的基本用法

      在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下final关键字的基本用法。

      1.修饰类

      当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

      在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。

      2.修饰方法

      下面这段话摘自《Java编程思想》第四版第143页:

      “使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“

      因此,如果只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final的。

      注:类的private方法会隐式地被指定为final方法。

      3.修饰变量

      修饰变量是final用得最多的地方,也是本文接下来要重点阐述的内容。首先了解一下final变量的基本语法:

      对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

      举个例子:

      

      上面的一段代码中,对变量i和obj的重新赋值都报错了。

    二.深入理解final关键字

      在了解了final关键字的基本用法之后,这一节我们来看一下final关键字容易混淆的地方。

    1.类的final变量和普通变量有什么区别?

      当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。

      那么final变量和普通变量到底有何区别呢?下面请看一个例子:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    public class Test {

        public static void main(String[] args)  {

            String a = "hello2"; 

            final String b = "hello";

            String d = "hello";

            String c = b + 2; 

            String e = d + 2;

            System.out.println((a == c));

            System.out.println((a == e));

        }

    }

      

    true

    false

      大家可以先想一下这道题的输出结果。为什么第一个比较结果为true,而第二个比较结果为fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。这种和C语言中的宏替换有点像。因此在上面的一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的  值。而对于变量d的访问却需要在运行时通过链接来进行。想必其中的区别大家应该明白了,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,比如下面的这段代码就不会进行优化:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    public class Test {

        public static void main(String[] args)  {

            String a = "hello2"; 

            final String b = getHello();

            String c = b + 2; 

            System.out.println((a == c));

     

        }

         

        public static String getHello() {

            return "hello";

        }

    }

      这段代码的输出结果为false。

    2.被final修饰的引用变量指向的对象内容可变吗?

      在上面提到被final修饰的引用变量一旦初始化赋值之后就不能再指向其他的对象,那么该引用变量指向的对象的内容可变吗?看下面这个例子:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    public class Test {

        public static void main(String[] args)  {

            final MyClass myClass = new MyClass();

            System.out.println(++myClass.i);

     

        }

    }

     

    class MyClass {

        public int i = 0;

    }

      这段代码可以顺利编译通过并且有输出结果,输出结果为1。这说明引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的。

    3.final和static

      很多时候会容易把static和final关键字混淆,static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变。看下面这个例子:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    public class Test {

        public static void main(String[] args)  {

            MyClass myClass1 = new MyClass();

            MyClass myClass2 = new MyClass();

            System.out.println(myClass1.i);

            System.out.println(myClass1.j);

            System.out.println(myClass2.i);

            System.out.println(myClass2.j);

     

        }

    }

     

    class MyClass {

        public final double i = Math.random();

        public static double j = Math.random();

    }

    运行这段代码就会发现,每次打印的两个j值都是一样的,而i的值却是不同的。从这里就可以知道final和static变量的区别了。

    5.关于final参数的问题

      关于网上流传的”当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法外的变量“这句话,我个人理解这样说是不恰当的。

      因为无论参数是基本数据类型的变量还是引用类型的变量,使用final声明都不会达到上面所说的效果。

      看这个例子就清楚了:

      上面这段代码好像让人觉得用final修饰之后,就不能在方法中更改变量i的值了。殊不知,方法changeValue和main方法中的变量i根本就不是一个变量,因为java参数传递采用的是值传递,对于基本类型的变量,相当于直接将变量进行了拷贝。所以即使没有final修饰的情况下,在方法内部改变了变量i的值也不会影响方法外的i。

      再看下面这段代码:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    public class Test {

        public static void main(String[] args)  {

            MyClass myClass = new MyClass();

            StringBuffer buffer = new StringBuffer("hello");

            myClass.changeValue(buffer);

            System.out.println(buffer.toString());

        }

    }

     

    class MyClass {

         

        void changeValue(final StringBuffer buffer) {

            buffer.append("world");

        }

    }

      运行这段代码就会发现输出结果为helloworld。很显然,用final进行修饰并没有阻止在changeValue中改变buffer指向的对象的内容。有人说假如把final去掉了,万一在changeValue中让buffer指向了其他对象怎么办。有这种想法的朋友可以自己动手写代码试一下这样的结果是什么,如果把final去掉了,然后在changeValue中让buffer指向了其他对象,也不会影响到main方法中的buffer,原因在于java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。

      所以关于网上流传的final参数的说法,我个人不是很赞同。

     

     

     

     

     

     

     

     

     

      Java和AS3.0关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。

      可以修饰的对象: final 类 final方法 final变量 

    1、final类

      final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会再被扩展,那么就设计为final类。

    2、final方法

      如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。

        final不能用于修饰构造方法。 

      使用final方法的原因有二:  第一、把方法锁定,防止任何继承类修改它的意义和实现。

      第二、高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。

    3、final变量(常量)

      用final修饰的成员变量表示常量,值一旦给定就无法改变!能被赋值一次,赋值后值不再改变。  final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。  从下面的例子中可以看出,一旦给final变量初值后,值就不能再改变了。

      另外,final变量定义的时候,可以先声明,而不给初值,这种变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是,final空白在final关键字的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。

    4、final参数

      当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。  示例:   public voidf1(f

    inal int i){ } //i是final类型的,值不允许改变的

     

     

     

     

     

     

     

     

    介绍一下使用到fianl的三中情况:数据,方法,类。

      

       final数据

       许多编程语言都有某种方法,来向编译器告知一块数据是恒定不变的。有时数据的恒定不变是很有用的,例如:

    1,一个编译时恒定不变的常量

    2,一个在运行时初始化,而你不希望它被改变。

       对于编译期常量的这种情况,编译器可以将该常量值代入任何可能用到它的计算式中,也就是说,可以在编译期就执行计算式,这减轻了一些运行时的负担。在java中,这类常量必须是基本类型,并且以final表示。在对这个常量定义时,必须进行赋值。

       一个即是static又是fianl的域只占一段不能改变的存储空间。

       当final应用于对象引用时,而不是基本类型时,其含义有些让人疑惑。对基本类型使用fianl不能改变的是他的数值。而对于对象引用,不能改变的是他的引用,而对象本身是可以修改的。一旦一个final引用被初始化指向一个对象,这个引用将不能在指向其他对象。java并未提供对任何对象恒定不变的支持。这一限制也通用适用于数组,它也是对象。

       下面的事例示范fianl域的情况。注意,根据惯例,即是static又是fianl的域(即编译器常量)将用大写表示,并用下划分割个单词:

    [java] viewplaincopy

    1.  package reusing;  
    2.   
    3. //: reusing/FinalData.java  
    4. // The effect of final on fields.  
    5. import java.util.*;  
    6. import static net.mindview.util.Print.*;  
    7.   
    8. class Value {  
    9.   int i; // Package access  
    10.   public Value(int i) { this.i = i; }  
    11. }  
    12.   
    13.   
    14.   
    15. public class FinalData {  
    16.   private static Random rand = new Random(47);  
    17.   private String id;  
    18.   public FinalData(String id) { this.id = id; }  
    19.   // Can be compile-time constants:  
    20.   private final int valueOne = 9;  
    21.   private static final int VALUE_TWO = 99;  
    22.   // Typical public constant:  
    23.   public static final int VALUE_THREE = 39;  
    24.   // Cannot be compile-time constants:  
    25.   private final int i4 = rand.nextInt(20);  
    26.   static final int INT_5 = rand.nextInt(20);  
    27.   private Value v1 = new Value(11);  
    28.   private final Value v2 = new Value(22);  
    29.   private static final Value VAL_3 = new Value(33);  
    30.   // Arrays:  
    31.   private final int[] a = { 1, 2, 3, 4, 5, 6 };  
    32.   public String toString() {  
    33.     return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;  
    34.   }  
    35.   
    36.   
    37.   public static void main(String[] args) {  
    38.     FinalData fd1 = new FinalData("fd1");  
    39.     //! fd1.valueOne++; // Error: can't change value  
    40.     fd1.v2.i++; // Object isn't constant!  
    41.     fd1.v1 = new Value(9); // OK -- not final  
    42.     for(int i = 0; i < fd1.a.length; i++)  
    43.       fd1.a[i]++; // Object isn't constant!  
    44.     //! fd1.v2 = new Value(0); // Error: Can't  
    45.     //! fd1.VAL_3 = new Value(1); // change reference  
    46.     //! fd1.a = new int[3];  
    47.     print(fd1);  
    48.     print("Creating new FinalData");  
    49.     FinalData fd2 = new FinalData("fd2");  
    50.     print(fd1);  
    51.     print(fd2);  
    52.   }  
    53. }   
    54.   
    55. /* Output: 
    56. fd1: i4 = 15, INT_5 = 18 
    57. Creating new FinalData 
    58. fd1: i4 = 15, INT_5 = 18 
    59. fd2: i4 = 13, INT_5 = 18 
    60. */  

         由于valueOne和VALUE_TWO都是带有编译时数值的fianl基本类型,所以它们二者均可以用作编译期常量,并且没有重大区别。VALUE_THREE是一种更加典型的对常量进行定义的方式:定义为public,可以被任何人访问;定义为static,则强调只有一份;定义为fianl,这说明它是个常量。请注意带有恒定初始值(即,编译期常量)的final static基本类型全用大写字母命名,并且字母与字母之间用下划线隔开。

       我们不能因为某些数据是fianl的就认为在编译时可以知道它的值。在运行时使用随机数来初始化i4和INT_5的值叫说明了这一点。事例部分也展示了将fianl数据定义为static和非static的区别。此区别只有当数值在运行时内被初始化时才会显现,这是因为在编译器对编译时的数值一视同仁(并且他们可能因为优化而消失)。当运行时会看见这个区别。请注意,在此fd1和fd2中i4的值是唯一的,每次都会被初始化为15,13。INT_5的值是不可以通过创建第二个FinalData对象加以改变的。这是因为他是static的,在装载类时(也就是第一次创建这个类对象时)已经被初始化,而不是每次创建都初始化。

       


    如果看上面的事例来理解我标记颜色的的部分有点困难的话,请看下面的事例:

       

     

    [java] viewplaincopy

    1. public class B3 {  
    2.     static Random r =new Random(12);  
    3.     final int int1= r.nextInt(100);//产生0-99的随机数  
    4.     static final int INT_2= r.nextInt(100);  
    5.       
    6.   
    7.     public static void main(String[] args) {  
    8.         B3 b1=new B3();  
    9.         System.out.println("int1:"+b1.int1+"    INT_2:"+b1.INT_2);  
    10.         B3 b2=new B3();  
    11.         //b2.INT_2=100;//错误的赋值  
    12.         System.out.println("int1:"+b2.int1+"    INT_2:"+b2.INT_2);  
    13.   
    14.     }  
    15.   
    16. }  

    启动main()先执行的是B3 b1=new B3();,创建B3的第一个对象,这将会先初始化static final int INT_2= r.nextInt(100);,然后是初始化finalint int1= r.nextInt(100);,所以第一条输出语句的结果是int1:12    INT_2:66。接下来创建B3的第二个对象,这也会导致B3类中成员的初始化,但staticfinal int INT_2= r.nextInt(100);不会在被初始化,为什么前面已经提过。输出的结果是int1:56    INT_2:66。两次的输出INT_2的值都是一样的。

       在说回我们的第一个事例,V1到VAL_3说明final引用的意义。正如在main()方法中看见的,可以改变对象数组a的值,但不能将a的引用指向另一个对象。看起来使基本类型成为fianl比引用类型成为final的用处大。

        java也许生成"空白final",所谓空白final是指被声明为final但又未给初值的域。无论什么情况下编译器都会保证final域在使用前初始化。但空白final在fianl的使用上提供了很大的灵活性,为此,一个fianl域可以根据某些对象有所不同,却又保持恒定不变的特性。下面的事例说明了一点。

     

    [java] viewplaincopy

    1. class Poppet {  
    2.   private int i;  
    3.   Poppet(int ii) { i = ii; }  
    4. }  
    5.   
    6. public class BlankFinal {  
    7.   private final int i = 0; // Initialized final  
    8.   private final int j; // Blank final  
    9.   private final Poppet p; // Blank final reference  
    10.   // Blank finals MUST be initialized in the constructor:  
    11.   public BlankFinal() {  
    12.     j = 1; // Initialize blank final  
    13.     p = new Poppet(1); // Initialize blank final reference  
    14.   }  
    15.   public BlankFinal(int x) {  
    16.     j = x; // Initialize blank final  
    17.     p = new Poppet(x); // Initialize blank final reference  
    18.   }  
    19.   public static void main(String[] args) {  
    20.     new BlankFinal();  
    21.     new BlankFinal(47);  
    22.   }  
    23. } //  

     

    final 参数

          java中也许将参数列表中的参数以声明的方式声指明为final。这意味着你无发改变参数所指向的对象。

    [java] viewplaincopy

    1. class Gizmo {  
    2.   public void spin() {}  
    3. }  
    4.   
    5. public class FinalArguments {  
    6.   void with(final Gizmo g) {  
    7.     //! g = new Gizmo(); // Illegal -- g is final  
    8.   }  
    9.   void without(Gizmo g) {  
    10.     g = new Gizmo(); // OK -- g not final  
    11.     g.spin();  
    12.   }  
    13.   // void f(final int i) { i++; } // Can't change  
    14.   // You can only read from a final primitive:  
    15.   int g(final int i) { return i + 1; }  
    16.   public static void main(String[] args) {  
    17.     FinalArguments bf = new FinalArguments();  
    18.     bf.without(null);  
    19.     bf.with(null);  
    20.   }  
    21. } //  

    方法f()g()展示了基本类型的参数被指定为final是所出现的结果:你可以读参数,但不能修改参数。这一特性只要用来向匿名内部类传递数据。

    final 方法

       使用final方法有两个原因。第一个原因是把方法锁定,以防止任何继承它的类修改它的含义。这是出于设计的考虑:想要确保在继承中使用的方法保持不变,并且不会被覆盖。

       过去建议使用final方法的第二个原因是效率。在java的早期实现中,如果将一个方法指明为fianl,就是同意编译器将针对该方法的所有调用都转为内嵌调用。当编译器发现一个final方法调用命令时,它会根据自己的谨慎判断,跳过插入程序代码这种正常的调用方式而执行方法调用机制(将参数压入栈,跳至方法代码处执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来代替方法调用。这将消除方法调用的开销。当然,如果一个方法很大,你的程序代码会膨胀,因而可能看不到内嵌所带来的性能上的提高,因为所带来的性能会花费于方法内的时间量而被缩减。

        上面标颜色的地方不太懂。不知道那位看过Java编程思想和知道的高人给解释解释。

        在最进的java版本中,虚拟机(特别是hotspot技术)可以探测到这些情况,并优化去掉这些效率反而降低的额外的内嵌调用,因此不再需要使用final方法来进行优化了。事实上,这种做法正逐渐受到劝阻。在使用java se5/6时,应该让编译器和JVM去处理效率问题,只有在想明确禁止覆盖式,才将方法设置为fianl的。

        final和private关键字

       类中的所有private方法都是隐式的制定为final的。由于你无法访问private方法你也就无法覆盖它。可以对private方法添加final修饰词,但这毫无意义。

    [java] viewplaincopy

    1. class WithFinals {  
    2.   // Identical to "private" alone:  
    3.   private final void f() { print("WithFinals.f()"); }  
    4.   // Also automatically "final":  
    5.   private void g() { print("WithFinals.g()"); }  
    6. }  
    7.   
    8. class OverridingPrivate extends WithFinals {  
    9.   private final void f() {  
    10.     print("OverridingPrivate.f()");  
    11.   }  
    12.   private void g() {  
    13.     print("OverridingPrivate.g()");  
    14.   }  
    15. }  
    16.   
    17. class OverridingPrivate2 extends OverridingPrivate {  
    18.   public final void f() {  
    19.     print("OverridingPrivate2.f()");  
    20.   }  
    21.   public void g() {  
    22.     print("OverridingPrivate2.g()");  
    23.   }  
    24. }  

         "覆盖"只有在某方法是基类接口的一部分时才会发生。即,必须将一个对象向上转型为它的基类并条用相同的方法。如果某方法是private的,它就不是基类接口的一部分。它仅是一些隐藏于类中的程序代码,如果一个基类中存在某个private方法,在派生类中以相同的名称创建一个public,protected或包访问权限方法的话,该方法只不过是与基类中的方法有相同的名称而已,并没有覆盖基类方法。由于private方法无法触及且有很好的隐藏性,所以把它看成是因为他所属类的组织结的原因而存在外,其他任何事物都不用考虑。

        final 类

        当将类定义为final时,就表明了你不打算继承该类,而且也不也许别人这样做。换句话说,出于某种考虑,你对该类的设计永不需要做任何变动,或者出于安全的考虑,你不希望他有子类。

    [java] viewplaincopy

    1. class SmallBrain {}  
    2.   
    3. final class Dinosaur {  
    4.   int i = 7;  
    5.   int j = 1;  
    6.   SmallBrain x = new SmallBrain();  
    7.   void f() {}  
    8. }  
    9.   
    10. //! class Further extends Dinosaur {}  
    11. // error: Cannot extend final class 'Dinosaur'  
    12.   
    13. public class Jurassic {  
    14.   public static void main(String[] args) {  
    15.     Dinosaur n = new Dinosaur();  
    16.     n.f();  
    17.     n.i = 40;  
    18.     n.j++;  
    19.   }  
    20. }   

        请注意,final类的域可以根据个人的意愿选择是或不是final。不论类是否被定义为final,相同的规则同样适用于定义为final的域。然而,由于final是无法继承的,所以被final修饰的类中的方法都隐式的制定为fianl,因为你无法覆盖他们。在fianl类中可以给方法添加final,但这不会产生任何意义。

     

     

     

     

     

     

     

     

     

    展开全文
  • 谈一下final关键字

    2019-05-19 22:24:13
    最近校招,发现都喜欢问...我们常见的String类和基本数据类型都是由final关键字修饰的类,final修饰类则类不能被继承。 2.final关键字修饰方法: final关键字修饰方法,则方法不能被重写 final关键字修饰方法,在...

    最近校招,发现都喜欢问final关键字,今天就总结一下final关键字
    final关键字可以修饰类,方法和变量

    1.final关键字修饰类:
        我们常见的String类和基本数据类型都是由final关键字修饰的类,final修饰类则类不能被继承。
    2.final关键字修饰方法:

    1. final关键字修饰方法,则方法不能被重写
    2. final关键字修饰方法,在老版本的java,final修饰的方法意味着同意编译器将此方法转为内联方法,以提高效率。但是在现在的jvm能够根据选择自动的判断是否转为内联方法,与final关键字无关了.
    3. private修饰的方法被隐式的转为final所以也不能被继承

    3.final关键字修饰变量:

    1. final关键字修饰基本数据类型,这时候基本数据类型就相当于常量,其值不能被修改。如果修改了在编译时就会报错
      可以看到
      2.final关键字修饰引用类型,这个引用就不能指向其他的对象,但是可以修改其值
      在这里插入图片描述
      3.final关键字修饰的变量是否能被修改?
      在这里插入图片描述
      可以看到一个被final关键字修饰且赋值了的基本数据类型是不能被修改的,因为jvm会把它当做常量处理(如果去掉了final,只是private的话可以被修改为2)
    展开全文
  • 文章目录final关键字基本用法修饰类修饰方法修饰变量final变量 与 普通变量 区别final 与 static 区别final关键字作用final修饰变量能够提供性能final修饰的变量是线程安全的(没有共享就没有伤害) final关键字基本...
  • final修饰变量:表明该变量是一个常量,不能再次赋值 2.1 final修饰局部变量 fianl修饰基本数据类型变量:final 修饰指的是基本类型的数据值不能发生改变 final修饰引用数据类型变量:final 修饰指的是引用类型的...
  • final关键字

    2020-03-07 11:43:32
    最近校招,发现都喜欢问final关键字,今天就总结...
  • instanceof 关键字 instanceof关键字判断一个对象是否属于指定的类型。 使用前提:判断的对象与指定类型必须存在继承关系或实现关系。 使用格式:对象 instanceof ... final修饰 基本类型变量 变量不能重新赋值...
  • Java之final关键字

    2020-03-27 15:20:12
    修饰类当用final修饰一个类的时候,表示这个类不能被继承。 注意: a. 被final修饰的类,final类中的成员变量可以根据自己的实际需要设计为fianl。 b. final类中的成员方法都会被隐式的指定为final方法。 说明...
  • java final关键字详解

    千次阅读 2018-08-10 20:07:08
    但它最一般的意思就是声明“这个东西不能改变”。之所以要禁止改变,可能是考虑到两方面的因素:设计或效率。由于这两个原因颇有些区别,所以也许会造成final 关键字的误用。我们将讨论final 关键字的三种应用场合:...
  • java-final关键字

    2018-06-19 13:35:50
    在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)  final会告诉编译器,这个数据是不会修改的,那么编译器就可能会在编译时期就对该数据进行替换甚至执行计算,这样可以对我们的程序起...
  • (1)final关键字修饰一个基本类型的变量时(成员变量和局部变量),这个变量不能再次更改,就相当于一个常量了。 (2)final关键字修饰一个引用类型的变量,该变量不能重新指向新的对象。 (3)final关键字修饰一个...
  • final关键字的字面意思是最终的, 可修改的. 这似乎是一个看见名字就大概知道怎么用的语法, 但你是否有深究过final在各个场景中的具体使用方法, 注意事项, 以及背后涉及的Java设计思想呢? 目录 一. final修饰...
  • 1. final关键字修饰一个基本类型的变量时,该变量不能重新赋值,第一次的值为最终的 2. final关键字修饰一个引用类型变量时,该变量不能重新指向新的对象 3. final关键字修饰一个函数的时候,该函数不能被重写 4. ...
  • Java中final关键字分析

    2019-10-14 10:56:52
    Final关键字 最近研究了下final这个关键字,网上的总结也很多,自己看了许多的帖子和书稍微总结一下以供大家一起学习~ 修饰变量 final对变量的修饰分为基本类型和引用类型,对基本类型的修饰表现为变量的可修改,...
  • 在java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。 修饰类 当用final修饰一个类时,表明这个类不能被继承。 final类的所有成员方法都会被隐式地指定为final方法 修饰方法 把方法...
  • final关键字(重点) final本意为"最终的",无法更改的。可以修饰类、成员方法以及成员变量 final修饰类 最终类 表示该类不能被...final关键字修饰类表示该类不能被继承,比如说:java.lang.System/String类等; ...
  • final修饰的实例变量,必须手动赋值,不能采用系统默认值 final修饰的引用一旦指向某个对象之后,不能让它去指向其他对象,那么被指向的对象永远不能被垃圾回收器回收 final修饰的引用虽然指向某个对象后不能指向...
  • 原文:Java中final关键字的深入探究 final 关键字的字面意思是最终的,可修改的。这似乎是一个看见名字就大概知道怎么用的语法,但你是否有深究过final在各个场景中的具体用法,注意事项,以及背后涉及的Java...
  • 我们有时会发现jdk的源码中经常出现final这个关键字,那么它到底有什么作用呢?只是一种规范?还是说在某种场景下有性能上的优化?...一、修饰类(非抽象类)若final关键字修饰类,则表示该类不能...
  • 之前一直对final这个关键的功能,很模糊。在编程中很多次都是使用eclispe自动在变量前加的final关键字,一直对这个好奇,... 严格地说final修饰变量不可被改变,一旦获得了初始值,该final变量的值就不能被重新赋值
  • 2.final修饰变量(成员变量或局部变量),则成为常量,只能赋值一次。 3.修饰成员变量时,定义时同时给出初始值,而修饰局部变量时可以暂时赋初始值,但是只能够赋值一次。 常量 字面值常量 10...
  • final修饰的是基本数据类型的时候,就是最终值不能发生改变(final修饰的数据可以先声明,再去赋值,只能赋值一次) 如果成员变量final修饰且没有给值,那么要保证在创建变量之前赋值 (构造方法或者构造代码块 ,多...
  • JavaSe·面向对象篇(九) final关键字 1. 概述 学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承API中提供的类,改写其内容呢?显然这是不合适的。为了避免...
  • final 关键字final 1.修饰方法 作用 被修饰的方法 不能被重写 2.修饰变量 作用 被final修饰的对象... 修饰的基本数据类型的变量不能被重新赋值 3.修饰类 作用 被修饰的类不能被继承示例代码: public class Demo01 {
  • 格式:对象 instanceof 类型 这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例 final关键字的概念与四种用法 意为最终的,不可改变的 可以用来修饰类,方法,局部变量,成员变量 对于类...
  • final 用来修饰变量 只能被赋值一次,在运行时赋值,所谓运行时 就是当程序执行到这块代码时才会对final 修饰的变量进行赋值。 应用场景一如下图所示,当 final 使用在类中时,在声明变量时,你必须对其初始化赋值 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,346
精华内容 20,938
关键字:

判断final关键字不能修饰变量