一、final 关键字

1.1 概述

学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承 API 中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了 final 关键字, 用于修饰不可改变内容。

  • final: 不可改变。可以用于修饰类、方法和变量。
    • 类:被修饰的类,不能被继承。
    • 方法:被修饰的方法,不能被重写。
    • 变量:被修饰的变量,不能被重新赋值。

1.2 使用方式

1.2.1 修饰类

  • 格式

    public final class 类名称 {
         
        // ...
    }
    
  • 含义:当前这个类不能有任何的子类。(太监类)

注意:一个类如果是 final 的,那么其中所有的成员方法都无法进行覆盖重写(因为没儿子。)

1.2.2 修饰方法

  • 格式

    修饰符 final 返回值类型 方法名(参数列表){
          
        //方法体 
    }
    
  • 含义:当前这个方法不能被重写。

注意:重写被 final 修饰的方法,编译时就会报错

1.2.3 修饰变量

  1. 局部变量–基本类型

    基本类型的局部变量,被 final 修饰后,只能赋值一次,不能再更改。【即 一次赋值,终生不变】

    代码如下:

    public class FinalDemo1 {
          
        public static void main(String[] args) {
          
            // 声明变量,使用final修饰 
            final int a; 
            // 第一次赋值 
            a = 10; 
            // 第二次赋值 
            a = 20; // 报错,不可重新赋值 
            // 声明变量,直接赋值,使用final修饰 
            final int b = 10; 
            // 第二次赋值 
            b = 20; // 报错,不可重新赋值 
        } 
    }
    

    总结:对于 final 修饰的基本类型,只要保证有唯一 一次赋值即可。

    思考,如下两种写法,哪种可以通过编译?

    • 写法一:

      final int c = 0;
      for (int i = 0; i < 10; i++) {
             
          c = i; 
          System.out.println(c); 
      }
      
    • 写法二:

      for (int i = 0; i < 10; i++) {
              
          final int c = i; 
          System.out.println(c); 
      }
      

    根据 final 的定义,写法1报错!写法2,为什么通过编译呢?因为每次循环,都是一次新的变量c,故每次 变量c 都只赋值一次。这也是我们需要注意的地方。

  2. 局部变量–引用类型

    引用类型的局部变量,被 final 修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改。

    代码如下:

    public class FinalDemo2 {
          
        public static void main(String[] args) {
          
            // 创建 User 对象 
            final User u = new User(); 
            // 创建 另一个 User对象
            u = new User(); // 报错,指向了新的对象,地址值改变。 
            // 调用setName方法 
            u.setName("张三"); // 可以修改 
        } 
    }
    

总结:

  • 对于基本类型来说,不可变说的是变量当中的数据不可改变
  • 于引用类型来说,不可变说的是变量当中的地址值不可改变
  1. 成员变量

    对于成员变量来说,如果使用 final 关键字修饰,那么这个变量也照样是不可变。

    1. 由于成员变量具有默认值,所以用了 final 之后必须手动赋值,不会再给默认值了。

    2. 必须保证类当中所有重载的构造方法,都最终会对 final 的成员变量进行赋值。

    3. 对于 final 修饰的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。

      • 直接赋值

        public class User {
                  
            final String USERNAME = "张三"; 
            private int age; 
        }
        
      • 构造方法赋值

        public class User {
                  
            final String USERNAME ;
            private int age;
            public User(String username, int age) {
                  
                this.USERNAME = username; 
                this.age = age; 
            } 
        }
        

      final 修饰的常量名称,一般都有书写规范,即所有字母都大写

二、权限修饰符

2.1 概述

在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,

  • public:公共的。

  • protected:受保护的

  • default:默认的

  • private:私有的

2.2 不同权限的访问能力

public > protected > (default) > private

public protected (default ) private
同一类中
同一包中(子类与无关类)
不同包的子类
不同包中的无关类

注意:(default) 并不是关键字 default,而是根本不写。

可见,public 具有最大权限。private 则是最小权限。

编写代码时,如果没有特殊的考虑,建议这样使用权限:

  • 成员变量使用 private ,隐藏细节。

  • 构造方法使用 public ,方便创建对象。

  • 成员方法使用 public ,方便调用方法。

小贴士:不加权限修饰符,其访问能力与 default 修饰符相同