一、final修饰符概述

1. final可以修饰类、变量和方法

2. final修饰的类、变量和方法不可改变

3. 不允许为final变量重新赋值,子类不允许覆盖父类的final方法,final类不能派生子类

4. 通过使用final关键字,允许Java实现不可变类,不可变类会让系统更加安全

二、final成员变量

1. 对于final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值

2. 由于成员变量不一定需要显式初始化,故那些既没有在定义时指定初始值,也没有在初始化块、构造器中指定初始值的final成员变量的值将一直是系统默认分配的0、'\u0000'、false或null,这些final成员变量也就完全失去了存在的意义,因此Java规定:final修饰的成员变量必须由程序员显式地指定初始值

  • final类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地方的其中之一指定
  • final实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定
	// 定义final成员变量时指定默认值
final int a = 6; // 下面final成员变量将在构造器或初始化块中分配初始值
final String str;
final int c;
final static double d; // 下面定义的ch实例变量是不合法的,因为没有显式指定初始值
// final char ch; // 初始化块,可对没有指定默认值的实例变量指定初始值
{
str = "Hello";
} // 静态初始化块,可对没有指定默认值的类变量指定初始值
static
{
d = 3.14;
} // 构造器,可对既没有指定默认值,又没有在初始化块中指定初始值的实例变量指定初始值
public FinalVariableTest()
{
c = 5;
}

三、final局部变量

1. 相比于成员变量,系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化,因此使用final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值

  • 如果在定义时指定了默认值,则后面代码中不能再对该变量赋值
  • 如果在定义时未指定默认值,则可以在后面代码中对该final变量赋初始值,但只能一次,不能重复赋值

四、final变量→宏变量

1. 当某个final变量满足以下两个条件时,它就不再是一个变量,而是相当于一个直接量(即宏变量)

  • 在该final变量定义时指定了初始值
  • 该初始值可以在编译时就被确定下来

2. 除了为final变量赋值时赋直接量的情况外,如果被赋的表达式只是基本的算术表达式或字符串连接运算,没有访问普通变量,也没有调用方法,Java编译器同样会将这种final变量当成“宏变量”处理

		// ex:下面定义了4个final“宏变量”
final int a = 5;
final int b = 3 + 2;
final double d = 1.2 / 3;
final String str = "我爱" + "China"; // 下面的ss变量的值因为调用了方法,所以无法在编译时被确定下来,ss也就不会被当成“宏变量”处理
final String ss = "我爱China" + String.valueOf(1314);

  

五、final方法

1. final修饰的方法不可被重写,但完全可以被重载

2. 由于子类无法重写父类的private方法(如果子类中定义一个与父类private方法有相同方法名、相同形参列表、相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法),因此即使使用final修饰一个private方法,依然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值类型的方法

public class PrivateFinalMethodTest
{
private final void test() {}
} class sub extends PrivateFinalMethodTest
{
// 下面的方法定义不会出现问题
public void test() {}
}

注:虽然子类和父类都包含了同名的void test()方法,但子类并不是重写父类的方法,因此即使父类的void test()方法使用了final修饰,子类中依然可以定义void test()方法。

六、final类

1. final修饰的类不可以有子类,所以若某个类不想被继承,则可以使用final修饰该类

public final class FinalClass
{
} // 下面的类定义将出现编译错误
class Sub extends FinalClass
{
}

七、不可变类

1. 不可变类是指创建该类的实例后,该实例的实例变量是不可改变的

2. Java提供的8个包装类和java.lang.String类都是不可变类

3. 如果要创建自定义的不可变类,可遵守如下规则:

  • 使用private和final修饰符来修饰该类的成员变量
  • 提供带参数构造器,用于根据传入参数来初始化类里的成员变量
  • 仅为该类的成员变量提供getter方法,不要为该类的成员变量提供setter方法
  • 如果有必要,重写Object类的hashCode()和equals()方法
/*
* 定义一个不可变类Address
*/
public class Address
{
// 不可变类的实例的实例变量不可改变
private final String detail;
private final String postCode; public Address()
{
detail = "";
postCode = "";
} public Address(String detail, String postCode)
{
this.detail = detail;
this.postCode = postCode;
} public String getDetail()
{
return this.detail;
}
public String getPostCode()
{
return this.postCode;
} // 重写equals()方法,判断两个对象是否相等
public boolean equals(Object obj)
{
// ...
}
public int hashCode()
{
return detail.hashCode() + postCode.hashCode() * 31;
}
}

补:对于上面的Address类,当程序创建了Address实例后,将无法修改该Address实例的detail和postCode实例变量。

4. 不可变类的实例在整个生命周期中永远处于初始化状态,它的实例变量不可改变,因此对不可变类的实例的控制将更加简单

  • 不可变类的实例状态不可改变,可以很方便地被多个对象所共享

12. final修饰符的更多相关文章

  1. 类成员(static)和final修饰符

    在Java类里只能包含成员变量.方法.构造器.初始化块.内部类(包括接口.枚举)5种成员,类成员是用static来修饰的,其属于整个类. 当使用实例来访问类成员时,实际上依然是委托给该类来访问类成员, ...

  2. Java final 修饰符知识点总结

    final从字面上理解含义为“最后的,最终的”.在Java中也同样表示出此种含义. final可以用来修饰变量(包括类属性.对象属性.局部变量和形参).方法(包括类方法和对象方法)和类. 1. fin ...

  3. Java中的final修饰符

    1.什么时候可以选择final修饰符 如果想让一个类不被其他类继承,不允许在有子类,这时候就要考虑用到final来修饰. 2.用final修饰的类 首先大家要明白,用final修饰的类是不能被继承的, ...

  4. 对于形式参数只能用final修饰符,其它任何修饰符都会引起编译器错误

    在Java中修饰符总共有一下几种: 1.访问控制修饰符    分别有:public private protected,缺省 2.其它修饰符      分别有:abstract,final,stati ...

  5. private static final 修饰符

    java修饰符分类修饰符字段修饰符方法修饰符根据功能同主要分下几种 1.权限访问修饰符 public,protected,default,private,四种级别修饰符都用来修饰类.方法和字段 包外 ...

  6. JAVA基础-栈与堆,static、final修饰符、内部类和Java内存分配

    Java栈与堆 堆:顺序随意 栈:后进先出(Last-in/First-Out). Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和mu ...

  7. as3 中 final 修饰符

    现在,在ActionScript 3.0的修饰符中,只有final修饰符没有介绍.之所有放在这里介绍,是因为final修饰符只与继承有关,指定一个方法不能被重写或一个类不能被继承. 一般来说,当用fi ...

  8. final修饰符:

    知识点: 1.final关键字用于修饰类.变量和方法 2.有点类似C#里的 sealed 关键字,用于表示它修饰的方法.变量和类不可以再被改变 3.final修饰变量时,表示该变量一旦获取了初始值,就 ...

  9. Java中final修饰符深入研究

    一.开篇 本博客来自:http://www.cnblogs.com/yuananyun/ final修饰符是Java中比较简单常用的修饰符,同时也是一个被"误解"较多的修饰符.对很 ...

随机推荐

  1. Docker 运行一个Web应用

    使用 docker 构建一个 web 应用程序. 我们将在docker容器中运行一个 Python Flask 应用来运行一个web应用 参数说明: -d:让容器在后台运行. -P:将容器内部使用的网 ...

  2. Java学习笔记(8)---Scanner类,浅谈继承

    1.Scanner类: a.定义: java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入. Scanner s = new Scanner(S ...

  3. WPF 动态生成对象属性 (dynamic)

    原文:WPF 动态生成对象属性 (dynamic) 项目中列行的数据 都需要动态生成 所以考虑到对象绑定  可需要一个动态生成属性的意思 缺点 加载速度会慢 很明显的慢 解决办法 尽量减轻动态属性的量 ...

  4. Java内存中的常量池

    1,java内存模型简介 <深入理解java虚拟机>里将java内存分为如下五个模块: 堆-堆是所有线程共享的,主要用来存储对象. 其中,堆可分为:新生代和老年代两块区域.使用NewRat ...

  5. Go语言系列教程

    一 Go介绍与开发环境搭建 01-Go语言简介 02-开发环境搭建 03-Go语言集成开发环境之GoLand安装使用 04-Go语言集成开发环境之VS Code安装使用 05-Go包管理详解 二 Go ...

  6. Sharding-JDBC:垂直拆分怎么做?

    经过读写分离的优化后,小王可算是轻松了一段时间,读写分离具体的方案请查看这篇文章: Sharding-JDBC:查询量大如何优化? 可是好景不长,业务发展是在太快了.数据库中的数据量猛增,由于所有表都 ...

  7. Win32 程序开发入门:一个最简单的Win32程序

    一.什么是 Win32 Win32 是指 Microsoft Windows 操作系统的 32 位环境,与 Win64 都为 Windows 常见环境. 这里再介绍下 Win32 Applicatio ...

  8. 6 种微服务 RPC 框架,你知道几个?

    开源 RPC 框架有哪些呢? 一类是跟某种特定语言平台绑定的,另一类是与语言无关即跨语言平台的. 跟语言平台绑定的开源 RPC 框架主要有下面几种. Dubbo:国内最早开源的 RPC 框架,由阿里巴 ...

  9. 一些常见的http状态码

    HTTP状态码是服务器和客户端之间交流信息的语言,下面列出一些常见的HTTP状态码. 1XX系列 指定客户端应相应的某些动作,代表请求已被接受,需要继续处理.由于在HTTP/1.0协议中没有定义任何1 ...

  10. PAT 1002 A+B for Polynomials(map模拟)

    This time, you are supposed to find A+B where A and B are two polynomials(多项式). Input Each input fil ...