一、理解final

望文生义,final意为“最终的,最后的”,我理解为“不能被改变的”,它可以修饰类、变量和方法。

所以我是否可以理解为被它所修饰的类、变量和方法都不能被改变呢?答案是”是“,因为有以下约束条件的存在:

1、final修饰类

被final修饰的类不能被继承,即它不能拥有自己的子类,否在会在编译期间报错。且看下面的例子:

第一步:创建一个用final修饰的父类Father

第二步:创建一个子类Son继承Father

如图所示,我们看到了报警信息,点进去一看,如下图所示:

意思就是类Son不能继承被final修饰的类Father,上面的结论得以印证。

2、final修饰方法

被final修饰的方法不能被重写,但是:

重写的前提是子类可以从父类中继承此方法,所以当父类中被final修饰的方法的访问权限为private时,子类中就可以重写该方法了。

详情且看下面的实例:

(一)父类中的方法控制权限为public

第一步:在Father类中创建一个方法,并用final修饰

第二步:用类Son继承类Father并重写work方法

可以看到当子类重写父类中用final修饰的方法时,报错了,报错信息如下:

即子类不能重写父类中被final修饰的方法

下面看另一种情况

(二)父类中的方法控制权限为private

第一步:在Father类中创建一个方法,并用final修饰

第二步:用类Son继承类Father并重写work方法

可以看到程序没有报错,黄色下划线的warning如下所示:

意为该方法没有被使用,而当我把方法的控制权限改为public并且不用final修饰时,一切继承和重写都是正常的,如下图所示:

由此,第二条结论也得以印证。

3、final修饰变量

final修饰的变量,无论是类属性、对象属性、形参还是局部变量,都需要进行初始化操作。

(1)修饰变量

可以看到被final修饰的变量报错了,报错信息如下:

意为被final修饰的字段language没有被初始化,所以当变量被final修饰时要赋值初始化,如下:

(2)修饰类属性

类属性可以理解为一个将一个类作为另一个类的属性

第一步:先创建一个特征类

第二步:将特征类Feature设置为Son类的属性,并用final修饰

同样当类属性用final修饰时报错了,报错信息如下:

同样,报错信息为没有进行对final修饰的类进行初始化,下面看一下不用final修饰时是否报错:

很明显,答案是没有,那再来看一下当初始化Feature类后又会是怎样的?

可以看到,初始化用fina修饰的属性类后并没有报错,上面的结论也得以印证了!

二、解答问题

结合以上基础知识,我们来分析一下为什么String类是final的?

首先来看一个例子:

上面这个例子,是让一个普通类继承String类,结果发现报错了,错误信息如下:

即类String1不能是final类String的子类,这里已经很明显地看出String类是final的,但是到底是为了什么呢?先给出答案吧:

主要是为了”安全性“和”效率“的缘故,因为:

1、由于String类不能被继承,所以就不会没修改,这就避免了因为继承引起的安全隐患;

2、String类在程序中出现的频率比较高,如果为了避免安全隐患,在它每次出现时都用final来修饰,这无疑会降低程序的执行效率,所以干脆直接将其设为final一提高效率;

下面是我在其他人的博客中发现的一个很有趣也很有价值的答案,截图拿来参考一下这位高人的解释:

以上就是我通过调研对本次问题的理解,如有不足或错误之处,望看到这篇文章的你能给予指点和批评,未完待续......

最美好的时光里,不要一直是一个lowser!

最佳答案:

主要是为了“效率” 和 “安全性” 的缘故。若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所以String被定义成final。

其它答案一:

String和其他基本类型不同,他是个对象类型.既然是对象类型,如果是在静态方法下是必须调用静态方法或值的,如果是非静态的方法,就必须要实例化. 
main函数是个static的.所以String要能像其他的基本类型一样直接被调用.这也是为什么在main函数下使用String类型不会报告错误的原因.. 
一下就解释了两个心里的疑问.. 
以前一直觉得奇怪,为什么String是对象类型在main函数下却是不需要实例化的.再次佩服java设计人员想得真周到.

其它答案二:

当定义String类型的静态字段(也成类字段),可以用静态变量(非final)代替常量(final)加快程序速度。反之,对于原始数据类型,例如int,也成立。

例如,你可能创建一个如下的String对象:

private static final String x = "example";

对于这个静态常量(由final关键字标识),你使用常量的每个时候都会创建一个临时的String对象。在字节代码中,编译器去掉”x”,代替它的是字符串“example”,以致每次引用”x”时VM都会进行一次哈希表查询。

相比之下,度于静态变量(非final关键字),字符串只创建一次。仅当初始化“x”时,VM才进行哈希表查询。

还有另一个解释: 
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了人们覆盖length()方法。

  另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。

示例:

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

}

如果String 不是final 那么就可以继承 
public class String2 extends String{ 
   // .. 
   // ... 
}

那我们的 main也就可以写成 
public class Test { 
public static void main(String2[] args)  { // 注意此处 
//  

}

英文参考:http://forums.sun.com/thread.jspa?threadID=636414

=============================================================

另外补充一点:

引用:http://zhidao.baidu.com/question/94324055.html
作用就是 final的类不能被继承,不能让别人继承有什么好处? 
意义就在于,安全性,如此这般: 
Java自出生那天起就是“为人民服务”,这也就是为什么Java做不了病毒,也不一定非得是病毒,反正总之就是为了安全,人家Java的开发者目的就是不想让Java干这类危险的事儿,Java并不是操作系统本地语言,换句话说Java必须借助操作系统本身的力量才能做事,JDK中提供的好多核心类比如String,这类的类的内部好多方法的实现都不是Java编程语言本身编写的,好多方法都是调用的操作系统本地的API,这就是著名的“本地方法调用”,也只有这样才能做事,这种类是非常底层的,和操作系统交流频繁的,那么如果这种类可以被继承的话,如果我们再把它的方法重写了,往操作系统内部写入一段具有恶意攻击性质的代码什么的,这不就成了核心病毒了么? 
--- 
上面所述是最重要的,另外一个方面,上面2位老兄说的也都很对,就是不希望别人改,这个类就像一个工具一样,类的提供者给我们提供了,就希望我们直接用就完了,不想让我们随便能改,其实说白了还是安全性,如果随便能改了,那么Java编写的程序肯定就很不稳定,你可以保证自己不乱改,但是将来一个项目好多人来做,管不了别人,再说有时候万一疏忽了呢?他也不是估计的,所以这个安全性是很重要的,Java和C++相比,优点之一就包括这一点;
---
原因绝对不只有这么多,因为如果这些个核心的类都能被随便操作的话,那是很恐怖的,会出现好多好多未知的错误,莫名其妙的错误....

【转载】http://blog.csdn.net/fenglibing/article/details/5486449

【转载】http://www.cnblogs.com/ikuman/p/3284410.html

========================================================== 做事要认真=========================================================
自己的理解:
  final这个关键字,本意:不可更改、改变。   原因:安全和效率。
    final修饰的类是不能被继承的,所以final修饰的类是不能被篡改的。
 
  安全体现在哪?
  1)、确保它们不会在子类中改变语义。String类是final类,这意味着不允许任何人定义String的子类。
换言之,如果有一个String的引用,它引用的一定是一个String对象,而不可能是其他类的对象。 
  2)、String 一旦被创建是不能被修改的,
    String类用final定义,表示这个类不可被修改。当我们用String定义一个“aaa”时,在再定义一个“aaabbb”时,不是在原来的内存地址中修改”aaa为“aaabbb“的,是在另外的地址上存入“aaabbb”的。个人认为,将String类定义为final,最主要的原因是保证安全。
例如:
 
  public class Test1 {  
    public static void main(String[] args) {

      String s = "hello";

      String s1 = s + "world";

      System.out.println(s);

      System.out.println(s1);

      StringBuffer ss = new  StringBuffer("h");

      StringBuffer ss1 = ss.append("w");

      System.out.println(ss);

      System.out.println(ss1);

    }

  }

  运行结果:

  hello

  helloworld

  hw

  hw

因为String类不可变,因此在s被赋值为hello时,再赋值world时,被存储在另外的内存地址上,所以s的值依然为hello。但是StringBuffer没有这样不可变的保护,所以会在原来的数据上进行修改,将ss的值改为hw。

  

Java 设计者将 String 为可以共享的,下面这段是源码中的注释:

   

/**
* The {@code String} class represents character strings. All
* string literals in Java programs, such as {@code "abc"}, are
* implemented as instances of this class.
* <p>
* Strings are constant; their values cannot be changed after they
* are created. String buffers support mutable strings.
* Because String objects are immutable they can be shared. For example:
* String str = "abc";
* is equivalent to:
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
*/
对应翻译:
/**
*字符串类表示字符串。所有
*在java程序中的字符串,如“ABC”,是
*实现为这个类的实例。
*
*字符串是常量,它们的值在它们之后不能更改
*创建。支持可变字符串字符串缓冲区。
*因为字符串对象是不可改变的,它们可以共享。

  

java问题解读,String类为什么是final的的更多相关文章

  1. Java里的String类为什么是final的

    今天在看<图解设计模式>,里面出了一个问题“String类用final修饰,导致它无法被继承(扩展),这样做违反了开闭原则,这么做有什么正当理由?” 答案是效率和安全性  首先是效率,由于 ...

  2. Java问题解读系列之String相关---String类为什么是final的?

    今天看到一篇名为<Java开发岗位面试题归类汇总>的博客,戳进去看了一下题目,觉得有必要夯实一下基本功了,所以打算边学边以博客的形式归纳总结,每天一道题, 并将该计划称为java问题解读系 ...

  3. Java 基础之 String 类

    String String 被声明为 final,因此不能被继承.(Integer 等包装类也不能被继承) 在 java8 中,String 内部使用 char 数组 来存储数据 public fin ...

  4. 关于Java中的String类知识点小总结

    Java中的String类知识点 前言 在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串. 如何创建字符串 最简单的方式 String str = "he ...

  5. String类为什么是final的

    首先我们使用new创建一个String对象的时候比如: String str=new String("123"); 这句话里面创建了两个对象,第一个在系统中创建了一个"a ...

  6. Java常用API(String类)

    Java常用API(String类) 概述: java.lang.String 类代表字符串.Java程序中所有的字符串文字(例如 "abc" )都可以被看作是实现此类的实例 1. ...

  7. Java基础笔记-String类

    String 类(被final修饰) 字符串是一种特殊的对象,一旦字符串被初始化就不可以被改变了.(内容不变) 例如: String  s = “abc”; String  s1 = new Stri ...

  8. java中的String类常量池详解

    test1: package StringTest; public class test1 { /** * @param args */ public static void main(String[ ...

  9. 为什么Java中的String类是不可变的?

    String类是Java中的一个不可变类(immutable class). 简单来说,不可变类就是实例在被创建之后不可修改. 在<Effective Java> Item 15 中提到了 ...

随机推荐

  1. python利用requests统计1个接口的响应时间

    参照 https://www.cnblogs.com/yoyoketang/p/8035428.html requests统计接口的响应时间有2种方式 r.elapsed.total_seconds( ...

  2. PHP爬数据 QueryList

    QueryList官方文档:https://www.querylist.cc/docs/guide/v3 因为php版本使用5.6,所以使用QueryList v3版本,php7可以使用 v4版本 v ...

  3. 用meta name="renderer" content="webkit|ie-comp|ie-stand"来切换360双核安全浏览器的极速模式和兼容模式

    以下信息摘自360官方网站: 浏览模式:极速模式.兼容模式及IE9高速模式是360浏览器显示网页时使用的三种模式:极速模式表示极速模式兼容模式表示兼容模式IE9IE10模式表示IE9/IE10模式(仅 ...

  4. Apache添加到windows服务和移除Apache的windows服务

    Apache添加到windows服务和移除Apache的windows服务 Apache免安装版将其添加到Windows服务中: 打开cmd控制台,在上面输入"你的Apache安装目录\bi ...

  5. Linux安装redis并且连接内网的redis

    1.安装redis步骤 1.首先准备工作  [root@10-100-14-130 ~]# yum install gcc-c++   yum install wget 2.推荐进入到linux路径/ ...

  6. 19异常和file部分笔记

    19异常和file部分笔记-2018/09/041.异常  1.1 throwable()几个常见方法 * getMessage()获取异常信息,返回字符串 * toString()获取异常类名和异常 ...

  7. 洛谷——P1379 八数码难题

    P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...

  8. <MyBatis>入门四 传入的参数处理

    1.单个参数 传入单个参数时,mapper文件中 #{}里可以写任意值 /** * 传入单个参数 */ Employee getEmpById(Integer id); <!--单个参数 #{} ...

  9. Linux学习笔记(五) 账号管理

    1.用户与组账号 用户账号:包括实际人员和逻辑性对象(例如应用程序执行特定工作的账号) 每一个用户账号包含一个唯一的用户 ID 和组 ID 标准用户是系统安装过程中自动创建的用户账号,其中除 root ...

  10. Django-REST_Framework 第三方登录

    DRF第三方登录,我们将使用第三方包实现!!! 1.首先安装 pip install social-auth-app-django 文档请看 https://python-social-auth.re ...