final关键字

final可以修饰非抽象类、非抽象类成员方法和变量。

(1)final类:不能被继承,没有子类,final类中的方法默认是final的;

(2)final方法:不能被子类的方法覆盖,但可以被继承;

(3)final成员变量:表示常量,只能被赋值一次,赋值后值不再改变;

(4)final不能用于修饰构造方法。

(父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final的)

1.final类

final类不能被继承,因此final类的成员方法没有机会被覆盖,默认是final的,在设计类的时候,如果这个类不需要有子类,类的实现细节不允许变动,并且确定这个类不会再被扩展,可以将这个类设置为final类。

2.final方法

如果一个类不允许子类覆盖某个方法,可以将这个方法设置为final方法。

  将方法声明为final的原因主要有两个:

    ①将方法锁定:防止任何子类修改它的意义和实现;

    ②高效:编译器遇到调用final方法的时候,会转入内嵌机制,大大提高执行效率。

父类Test1.java

package EmployeeTest_4_2;

public class Test1 
{
	public static void main(String[] args)
	{
		
	}
	
	public void f1()
	{
		System.out.println("父类的f1");
	}
	
	public final void f2()
	{
		System.out.println("父类的f2");
	}
	
	public void f3()
	{
		System.out.println("父类的f3");
	}
	
	public void f4()
	{
		System.out.println("父类的f4");
	}
	
}

子类Test2.java

package EmployeeTest_4_2;

public class Test2 extends Test1
{
	public void f1()
	{
		System.out.println("父类的f1方法被覆盖!");
	}

	//这种声明f2的方法会报错,因为在Test1中已经将f2方法声明为final
//	public void f2()
//	{
//		System.out.println("父类的f2方法被覆盖!");
//	}
	
	public void f3()
	{
		System.out.println("父类的f3方法被覆盖!");
	}
	
	
	public static void main(String[] args)
	{
		Test2 t = new Test2();
		t.f1();
		t.f2();
		t.f3();
		t.f4();
	}

}

输出的结果为:

父类的f1方法被覆盖!
父类的f2
父类的f3方法被覆盖!
父类的f4

  由于父类中f2方法已经被声明为final,所以如果在子类Test2中重写f2方法的时候,会报错,这时候会提示将父类Test1中的f2方法声明为“非final”方法。

Exception in thread "main" java.lang.VerifyError: class EmployeeTest_4_2.Test2 overrides final method f2.()V
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.access$100(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

3.final变量

用final修饰的成员变量表示常量,值一旦给定就无法改变。

  总共可以修饰三种变量:静态变量、实例变量和局部变量。

  final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是,final空白在final关键字final的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。

package EmployeeTest_4_2;

public class Test3 { private final String s = "final变量"; private final int A = 100; public final int B = 90; public static final int C = 80; public static final int D = 70; public final int E;//final空白,必须在初始化对象的时候赋初值 public Test3(int x) { E = x; } public static void main(String[] args) { Test3 t = new Test3(2); // t.A = 101;//final变量的值一旦给定就无法改变 // t.B = 91; // t.C = 81; // t.D = 71; System.out.println(t.A); System.out.println(t.B); System.out.println(t.C); //不推荐用对象方式访问静态字段 System.out.println(t.D); System.out.println(Test3.C); System.out.println(Test3.D); //System.out.println(Test3.E);//出错,因为E为final空白,依据不同对象值有所不同. System.out.println(t.E); Test3 t1 = new Test3(3); System.out.println(t1.E);//final空白变量E依据对象的不同而不同 } private void test() { System.out.println(new Test3(1).A); System.out.println(Test3.C); System.out.println(Test3.D); } public void test2() { final int a;//final空白,在需要的时候才赋值 final int b = 4;//局部常量--final用于局部变量的情形 final int c;//final空白,一直没有给赋值. a = 3; //a=4; 出错,已经给赋过值了. //b=2; 出错,已经给赋过值了. } }

输出结果:

100 90 80 70 80 70 2 3

4. final参数

当函数参数为final类型的时候,可以读取使用该参数,但是无法修改该参数的值。

package EmployeeTest_4_2;

public class Test4 
{
	public static void main(String[] args)
	{
		new Test4().f1(1);
	}
	
	public void f1(final int i)
	{
		System.out.println(i);
	}

}

总结:

  1、final修饰类

final修饰的类不允许被继承。一个类不能既是final的,又是abstract的,因为抽象类的目的就是为了让子类去实现其中的方法,而final修饰的类不能被继承,所以产生了矛盾。

2、final修饰方法

final修饰方法,表示该方法不能被子类重写Override。

3、final修饰变量

final成员变量表示常量,只能被赋值一次,赋值后的值不能改变。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏DannyHoo的专栏

为什么NSString要用Copy来修饰?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

19220
来自专栏积累沉淀

Python快速学习第一天

第一天: Python是一种解释型的、面向对象的、带有动态语义的高级程序设计语言 一、运行Python: 1、 在交互式环境下,直接输入Python进入Pyth...

22350
来自专栏我的博客

插入排序

原理: 1. 从第一个元素开始,该元素可以认为已经被排序 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描 3. 如果该元素(已排序)大于新元素,...

26260
来自专栏python学习指南

Python迭代

本篇将介绍Python的迭代,更多内容请参考:Python学习指南 简介 在Python中,如果给定一个list或者tuple,我们可以通过for循环来遍...

21790
来自专栏前端知识分享

第191天:js---Array常用属性和方法总结

13820
来自专栏web前端

JavaScript基础学习--14 json、数组

Demos:   https://github.com/jiangheyan/JavaScriptBase 一、json      1、格式与取值:{key:...

280100
来自专栏blackheart的专栏

[C#1] 2-类型基础

1.System.Object CLR要求每个类型都要继承自System.Object[直接或者间接方式],如果不显示继承,编译器会自动为我们添加对System...

20570
来自专栏深度学习思考者

C++常见问题(二)——虚函数、类与结构、引用与值传递

一 文件输入输出的方式 C++定义了ifsteam、ofstream和fstream 3种类型以用来支持文件的输入输出。 二 异常 异常就是程序运行时出...

20160
来自专栏Python爬虫实战

Python指南:组合数据类型

Python提供了5中内置的序列类型:bytearray、bytes、list、str与tuple,序列类型支持成员关系操作符(in)、大小计算函数(len()...

17310
来自专栏土豆专栏

Java面试之数据类型(一)

封装类是引用类型,基本类型在传递参数的时候都是按值传递,而封装类型是按引用传递的(其实引用也是按值传递的,但是传递的是对象的地址)

20420

扫码关注云+社区

领取腾讯云代金券