重读java编程思想之复用类之final

本文内容部分来源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.









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值