本文内容部分来源java编程思想
final:不可改变的
然而不可改变可能处于两种理由:设计和效率,由于两种原因不一样,可能存在误用;
下面是final使用的三种情况:数据、方法、类
1.数据:
例如:一个不可改变的常量或在运行时被初始化的值,但不想让其改变
一个基本类型运用final时,final使其恒定不变,而相对于对象而言,final使引用恒定不变(即一旦被对象初始化指向一个对象,就无法将其改为另一个对象,但是对象本身却是可以修改的,java并未提供任何对象恒定不变的方法)
public class Final {
private static Random rand = new Random(47);
private String id;
public Final(String id){
this.id = id;
}
//final valueone = 9
private final int valueone = 9;
// static final 一起使用,一般变量名字大写,是static域 又是fianl域只占据一段不能改变的存储空间
// final与static final的区别是:final在一个对象类唯一,static final在多个对象中都唯一;
private static final int VALUE_TWO = 99;
public static final int VALUE_THREE = 39;
private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
//**********************************************
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value VAL_3 = new Value(33);
private final int[] a = {1,2,3,4,5,6};
public String toString(){
return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;
}
/**
* <b>方法说明:</b>
* <ul>
* final关键字
* </ul>
* @param args
*/
public static void main(String[] args) {
Final fd1 = new Final("fd1");
// 不能改变值 final
//fd1.valueone ++ ;
//v2只是对象value的一个引用,不可以把v2指向其他对象,但是可以改变对象value里面的i值
//fd1.v2 = new Value(1);// error final
System.out.println("原始值:"+fd1.v2.i);
fd1.v2.i ++ ;
System.out.println("改变值: "+fd1.v2.i);
// 可以把v1执行新的对象 v1 不是final
System.out.println("未改变对象前:"+fd1.v1.i);
fd1.v1 = new Value(9);
System.out.println("改变对象引用后:"+fd1.v1.i);
// 数据一样,不可改变数组fd1.a的引用指向其他数组,但是可以改变数据里面本身的值
//fd1.a = new int[]{2,3,4,5,6}; error final
System.out.println("改变前:"+Arrays.toString(fd1.a));
for (int i = 0; i < fd1.a.length; i++) {
fd1.a[i] ++ ;
}
System.out.println("改变后:"+Arrays.toString(fd1.a));
System.out.println(fd1);
System.out.println(" 创建第二个对象 ");
Final fd2 = new Final("fd2");
System.out.println(fd1);
System.out.println(fd2);
}
}
class Value{
int i;
public Value(int i){
this.i = i;
}
}
console 打印:
原始值:22
改变值: 23
未改变对象前:11
改变对象引用后:9
改变前:[1, 2, 3, 4, 5, 6]
改变后:[2, 3, 4, 5, 6, 7]
fd1: i4 = 15, INT_5 = 18
创建第二个对象
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
注意的是:在创建的两个对象之中, i4 的值是在创建新对象时改变了,但是INT_5的值是固定的,因为全局INT_5是static,在装载时被初始化,适用于多个类,而不是每次创建类在初始化,可以说是在main之前就初始化。
=================================================================================================
空白final: java允许生成空白的final,所谓的空白的final就是申明final但未给定初始值的域,编译器需要保证空白final在使用前被初始化,空白final可以依据不同的对象使用而灵活改变,也就是通过类的构造函数来初始化
例如:
public class BlankFinal {
// 初始化的final
private final int i =0;
// blank final
private final int j;
private final Example p;
public BlankFinal(){
j = 2;
p = new Example(3);
}
public BlankFinal(int i){
j = i;
p = new Example(i);
}
/**
* <b>方法说明:</b>
* <ul>
* 空白final
* </ul>
* @param args
*/
public static void main(String[] args) {
BlankFinal m = new BlankFinal();
BlankFinal m2 = new BlankFinal(47);
System.out.println("j: "+m.j+" p:"+m.p.i);
System.out.println("j2: "+m2.j+" p2:"+m2.p.i);
}
}
class Example{
int i;
Example(int i){
this.i = i;
}
}
console:
j: 2 p:3
j2: 47 p2:47
========================================================================================
final参数:java允许参数列表中以申明的方式将参数指明为final,意味着在方法中不能更改参数指向的引用
/*
* <b>类说明:</b>
* <p>
* 参数列表final变量
* </p>
*/
public class FinalArguments {
void with(final Gizmo g){
//不能改变 g是final
//g = new Gizmo();//error final
}
void without(Gizmo g){
g = new Gizmo();
g.spin();
}
void f(final int i){
// 只能读不可改变,i是final
//i++;
}
int g(final int i){
//i = i+1; //can't change
return i+1;
}
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
FinalArguments b = new FinalArguments();
b.without(null);
b.with(null);
}
}
class Gizmo{
public void spin(){
System.out.println("Gizmo");
};
}
==========================================================================================================
二:final方法:
作用:锁定方法,防止任何继承类修改它
类中的所有的private方法都隐式的指定为final,由于无法取用private方法,所以也就无从覆盖和更改它,在private方法上添加final,没有任何意义
e.g:
* <b>类说明:</b>
* <p>
* final方法
* </p>
*/
public class FinalsImpl{
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
OverridingPrivate2 op2 = new OverridingPrivate2();
op2.f();
op2.g();
OverridingPrivate op = op2;
// 不能够调用
/*op.f();
op.g();*/
WithFinals wf = op2;
// 不能调用
// wf.f();
// wf.g();
}
}
class WithFinals{
private final void f(){
System.out.println("WithFinals.f(),this is a private final method");
}
private void g(){
System.out.println("WithFinals.g(),this is a private method");
}
}
class OverridingPrivate extends WithFinals{
private final void f(){
System.out.println("this is a overriding method,extends WithFinals.f()");
}
private void g(){
System.out.println("this is a overriding method,extends WithFinals.g()");
}
}
class OverridingPrivate2 extends OverridingPrivate{
public final void f(){
System.out.println("OverridingPrivate2.f()");
}
public void g(){
System.out.println("OverridingPrivate2.g()");
}
}
"覆盖":只有在某方法是基类的接口的一部分时才会出现,即,必须能将一个对象向上转型为它的基本类型并调用相同方法,private修饰的方法只是隐藏在类中的程序代码,只不过是具有相同名称罢了;但如果是public、protected或者包访问权限,且具有相同名称,那么则是覆盖
************************************************************************************************************************************************************************************************
三:final 类:表示这个类不打算在进行继承,而且也不允许别人这样做,换而言之,就是对于该类的设计永不需要做任何变动,或者说是出于安全的考虑,不希望它拥有子类
注意:
1.设计类的时候,把方法指明为final,是一个明智的,对于一些不可改变的方法,不要抱有一种没有人会覆盖你的方法的想法;(特别是一些通用类)
2.