美文网首页Java工程师知识树
Java基础-面向对象-final关键字

Java基础-面向对象-final关键字

作者: HughJin | 来源:发表于2021-03-01 08:13 被阅读0次

Java工程师知识树 / Java基础


1、final关键字作用

final可以修饰类、方法、变量。那么分别是什么作用呢?

(1)修饰类:表示类不可被继承

(2)修饰方法:表示方法不可被覆盖

(3)修饰变量:表示变量一旦被赋值就不可以更改它的值。java中规定final修饰成员变量必须显示指定变量的值。

2、final关键字修饰类

final关键字修饰类表示这个类是不可被继承的.

3、final关键字修饰方法

final修饰的方法不能被重写,但是可以重载。

下面给出了一个代码例子。

主要注意的是:父类中private的方法,在子类中不能访问该方法,但是子类与父类private方法相同的方法名、形参列表和返回值的方法,不属于方法重写,只是定义了一个新的方法。

class ClassFinal3{
    private void testClassFinalMethod(){};
}
// 实现final修饰的接口
class InnerClass4 extends ClassFinal3 {
    void testClassFinalMethod(){};
}

使用final方法的原因有两个:

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

类中所有的private方法都隐式地指定为final。

4、final关键字修饰变量

(1)修饰成员变量

  • 如果final修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量时指定初始值。
  • 如果final修饰的是成员变量,可以在非静态初始化块、声明该变量或者构造器中执行初始值。

(2)修饰局部变量

系统不会为局部变量进行初始化,局部变量必须显示初始化。因此使用final修饰局部变量时,即可以在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋初值(仅一次)

实例:

package com.jvm.study;

public class FinalVar {
    final static int a = 0;//再声明的时候就需要赋值
    public static void main(String[] args) {
        final int localA;   //局部变量只声明没有初始化,不会报错,与final无关。
        localA = 0;//在使用之前一定要赋值
        localA = 1; // 但是不允许第二次赋值 Variable 'localA' might already have been assigned to
        a = 1;// Cannot assign a value to final variable 'a'
    }
}

(3)修饰基本类型数据和引用类型数据

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

使用示例

package com.jvm.study;

public class FinalReferenceTest {
    public static void main() {
        final int[] iArr = {1, 2, 3, 4};
        iArr[2] = -3;//合法 
        iArr = null;//非法,对iArr不能重新赋值 Cannot assign a value to final variable 'iArr'

        final Person p = new Person(25);
        p.setAge(24);//合法
        p.setAge(12);//合法
        p = null;//非法  Cannot assign a value to final variable 'p'
    }

    static class Person {
        private int Age;
        Person(int Age) {
            this.Age = Age;
        }
        public int getAge() {
            return Age;
        }
        public void setAge(int age) {
            Age = age;
        }
    }

}

5、与Static关键字

static简介

static是静态修饰符,一般修饰成员。

被static修饰的成员属于类,不属于单个这个类的某个对象。static修饰的成员被多个对象共享。static修饰的成员属于类,但是会影响每一个对象。被static修饰的成员又叫类成员,不叫对象的成员。

注意:static不能修饰类 构造方法 局部变量。

成员变量使用

使用不同类中的成员变量有以下几种方式:

  • (1) 创建该类对象,使用对象调用
  • (2) 继承,使用super调用
  • (3) 使用类名直接调用,调用格式:类名.静态成员变量名

stati修饰成员变量的注意事项

  • (1)静态方法可以直接访问类变量和静态方法。
  • (2) 静态方法不能直接访问非静态成员变量或成员方法。非静态成员方法可以直接访问类变量或静态方法。
  • (3) 静态方法中,不能使用this关键字。

static和final联合使用

  • static和final可以修饰成员变量和成员方法,对于变量,可理解为“全局变量”,一旦赋值,不能被修改,可通过类名访问;对于方法,不能被子类覆盖,可通过类名访问。
  • private 方法默认均为 final 方法.
  • final 常常和 static, public 配合来修饰一个实例变量,表示为一个全类公有的公开静态常量。

6、不变模式

关于 final 的设计模式: 不变模式

  • 1、不变模式: 一个对象一旦产生就不可能再修改(String 就是典型的不变模式);通过不变模式可以做到对象共享;

  • 2、池化思想: 用一个存储区域来存放一些公用资源以减少存储空间的开销。

    有池的类型:boolean,byte,int,short,long,char,(池范围在-127~128之间)(float,double 等小数没有池)
    例: 在String类中有个串池(在代码区)。
    池: 堆里的一片独立空间。目的是拿空间换时间,让运算效率更高。

    • 如果用Stirng str = "abc" 来创建一个对象时,则系统会先在“串池”中寻找有没有“abc”这个字符串;

      如果有则直接将对象指向串池中对应的地址,如果没有则在串池中创建一个“abc”字符串。所以:

      String str1 = "abc";
      String str2 = "abc";
      Str1 == str2 //返回值是ture;他们的地址是一样的。
          //也就是说str1和str2都指向了代码空间中相同的一个地址,而这个地址空间保存就是是字符串"abc"
          //字符串是不可改变的类型,所以可以共享。所以串池里不会有相同的两个字符串。
      
    • 如果用 String str = new String("abc") 则直接开辟一块内存放"abc"这个字符串。所以上面这语句,创建两个"abc",一个在池,一个是对象

      String str = new String("abc")
      String str2 = new String("abc");
      Str == str2 //返回值是false;他们的地址是不一样的。
      

//即是说str和str2分别指向了堆空间中不同的两个地址,而这两个地址空间保存的都是字符串"abc"
```

7、final变量在内部类中使用

package com.jvm.study;

public class Test {
    public static void main(String[] args)  {     
    }   
    //局部final变量b
    public void test(final int b) {
        int a = 10;//局部变量a
        //匿名内部类
        new Thread(() -> {
            System.out.println(a);//JDK1.7及其之前版本 报错
            System.out.println(b);
            // a = 1; // 不可修改 Variable used in lambda expression should be final or effectively final
            // b = 1; // 不可修改 Cannot assign a value to final variable 'b'
        }).start();
    }
    /**
     * 上段代码中,在JDK1.7及其之前版本,如果把变量a和b前面的任一个final去掉,这段代码都编译不过。
     * 这段代码会被编译成两个class文件:Test.class和Test1.class。
     * 默认情况下,编译器会为匿名内部类和局部内部类起名为Outter1.class。
     * 原因是为什么呢?这是因为test()方法里面的参数a和b,在运行时,main线程快要结束,但是thread还没有开始。
     * 因此需要有一种机制,在使得运行thread线程时候能够调用a和b的值,怎办呢?java采用了一种复制的机制,
     * 也就说如果局部变量的值在编译期间就可以确定,则直接在匿名内部里面创建一个拷贝。
     * 如果局部变量的值无法在编译期间确定,则通过构造器传参的方式来对拷贝进行初始化赋值。
     */
}

匿名也会被当作普通的类处理,只不过编译器生成它构造方法的时候,除了将外部类的引用传递了过来,还将基本数据类型的变量复制了一份过来,并把引用数据类型的变量引用也传递了过来。

因此,基本数据类型的变量不能修改,不然就会跟外部的变量产生不一致,这样的话变量的传递也就变得毫无意义了。

JDK1.8之前局部内部类和匿名内部类访问的局部变量必须由final修饰,JDK1.8开始,可以不加final修饰符,由JVM默认添加。这个功能称为:Effectively final 功能,属于Java的一种语法糖,final关键字语法并没有发生变化。

8、总结

final关键字主要用在三个地方:变量、方法、类。
一句话概括:

final关键字修饰类,表示类不可被继承;final关键字修饰方法,表示方法不可被覆盖;final关键字修饰变量,表示变量一旦被赋值就不可以更改它的值。java中规定final修饰成员变量必须显示指定变量的值,并只能赋值一次。

相关文章

  • java SE目录

    java SE目录 java基础(一)java基础(二)关键字面向对象(一)面向对象(二)面向对象(三)集合(一)...

  • Java笔记

    Java基础 Java面试通关要点 1.面向对象的特征 封装 继承 多态 封装继承多态 2.final,final...

  • 2020-02-20 抽象类和接口

    抽象类 和 接口是面向对象编程中最重要的内容,没有之一 1.final 关键字 final 关键字在java ...

  • Java 面向对象2

    Java 面向对象 1. static 和 final static关键字---修饰成员变量 用static修饰的...

  • Java基础-面向对象-final关键字

    Java工程师知识树[https://www.jianshu.com/p/db77d19a25f6] / Ja...

  • 面向对象

    Java 语法基础 面向对象 ==面向对象有三宝:封装、继承和多态== 继承 关键字:extends 和 impl...

  • 面向对象

    一、类和对象 二、封装 三、继承 Java中final关键字的使用 final关键字: 使用final关键字做标识...

  • 知识体系

    体系 1. Java 语言技术栈复习纲要 Java基础(面向对象、四个特性、重载重写、static和final等等...

  • java - final 关键字

    java - final 关键字 java - final 关键字 在 java 中,final 关键字可以修饰类...

  • Java基础系列-final、finally关键字

    原创文章,转载请标注出处:《Java基础系列-final、finally关键字》 一、概述 final是Java关...

网友评论

    本文标题:Java基础-面向对象-final关键字

    本文链接:https://www.haomeiwen.com/subject/kjicoktx.html