博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
记一次被面试的final问题
阅读量:6895 次
发布时间:2019-06-27

本文共 3105 字,大约阅读时间需要 10 分钟。

---- 前言

   今天面试被问到了,我们都知道final修饰的东西是不可变的,那么是值不可变还是其地址不可变?一脸懵逼,回来查阅一番,总结一下

--- final与数据

   在日常行为下,一般数据指的都是基本数据变量或者常量。当final修饰的是一个基本的数据变量时,那么该变量的值就相当于一个常数不可变,当final修饰的是一个对象时,那么对于对象句柄,final会将句柄变成一个常数,就是此时不可变的对象的引用。

   然后,final修饰的对象是不可以重新指向新的一个对象的,但是自身对象的内容可以进行改变。

举个栗子

package com.xxg;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);      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!        fd1.v1.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");      }    }

结果:

fd1: i4 = 6, i5 = 11Creating new FinalDatafd1: i4 = 6, i5 = 11fd2: i4 = 11, i5 = 11

分析:

   i1和i2都是具备final属性的基本数据类型变量,并且在编译期都是具备有编译值的,而i3其实也差不多,只是多了public的访问修饰可以允许外边访问以及static强调只有一个

   i4和i5则证明了不是所有被final修饰的在编译期就能够确定值为多少,这两个都是在运行时调用随机函数生成数才能确认值。同时也看到了,由于i5是static修饰的,因为它的值并不会由于fd1和fd2对象的创建而发生改变。

 举个栗子

public static void main(String[] args){    final FinalString fs = new FinalString("1");    final FinalString fss = new FinalString("333");    fs = fss;}
public static void main(String[] args){    final String[] strs0 = {"123","234"};    final String[] strs1 = {"345","456"};    strs1 = strs0;    strs1[1] = "333";}

分析:

   这两个程序的运行会报错“The final local variable fs cannot be assigned”,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的,如果将第二程序的  strs1=str0 去掉,那么程序就可以正常运行

--- final与方法

  会使用final修饰方法,一方面的情况时为了确保该方法不会被修改或者由于继承类改变它的原本含义,另外一种情况时考虑到代码的运行效率问题,假如已经确定了某个方法是不会在变化了,那么可以通过final修饰,将其直接加载进入方法区,而可以忽略每次使用完方法和使用完后,堆内的压栈等一系列操作,可以减少系统的开销。

  类内所有private方法都自动成为final。由于我们不能访问一个private方法,所以它绝对不会被其他方法覆盖(若强行这样做,编译器会给出错误提示)。可为一个private方法添加final指示符,但却不能为那个方法提供任何额外的含义。

---fianl与类

  如果说整个类都是final(在它的定义前冠以final关键字),就表明自己不希望从这个类继承,或者不允许其他任何人采取这种操作。换言之,出于这样或那样的原因,我们的类肯定不需要进行任何改变;或者出于安全方面的理由,我们不希望进行子类化(子类处理)。

  将类定义成final后,结果只是禁止进行继承——没有更多的限制。然而,由于它禁止了继承,所以一个final类中的所有方法都默认为final。因为此时再也无法覆盖它们。所以与我们将一个方法明确声明为final一样,编译器此时有相同的效率

选择。可为final类内的一个方法添加final指示符,但这样做没有任何意义。

 

参考文献:《thinging in java》

转载于:https://www.cnblogs.com/liangyueyuan/p/9880532.html

你可能感兴趣的文章
配置管理小报100122:能者上、平者让、庸者下
查看>>
配置管理小报100204:产品路线图
查看>>
开发 Windows RT 桌面应用(来自 Surface RT)
查看>>
iOS 6版本与之前版本差异总结
查看>>
JNI编程(二) —— 让C++和Java相互调用(1)
查看>>
memcached简介
查看>>
Ubuntu 更改 Gun Make 版本
查看>>
Service学习笔记
查看>>
idea配置git、GitHub
查看>>
Cocopods安装和升级备忘录
查看>>
如何用Python写一个贪吃蛇AI
查看>>
nginx全局变量
查看>>
今日一练习
查看>>
Kylin 在 58 集团的实践和应用
查看>>
javascript性能优化
查看>>
41. First Missing Positive
查看>>
sql的行转列(PIVOT)与列转行(UNPIVOT)
查看>>
sbt配置——数据源问题解决
查看>>
框架模式与设计模式之区别
查看>>
AngularJS+Satellizer+Node.js+MongoDB->Instagram-13
查看>>