您的位置:首页 > 编程语言 > Java开发

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

2016-05-18 15:25 531 查看
本文内容部分来源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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: