当前位置:   article > 正文

java final 修饰变量_Java笔记:final修饰符

final修饰的变量

本篇笔记主要是final修饰符修饰类、成员变量、方法的用法,不可变类,实例缓存的不可变类

final关键字可以用来修饰类、变量、方法。final变量不能重新赋值,子类不能覆盖父类的final方法,final类不能有子类。

1.final修饰的成员变量

(1)final修饰的成员变量一旦赋值后,不能被重新赋值。

(2)final修饰的实例Field,要么在定义该Field的时候指定初始值,要么在普通初始化块或构造器中指定初始值。但是如果在普通初始化块中为某个实例Field指定了初始值,则不能再在构造器中指定初始值。

(3)final修饰的类Field,要么在定义该Field的时候指定初始值,要么在静态代码块中定义初始值。

(4)如果在构造器或初始化块中对final成员变量进行初始化,则不要在初始化之前就访问该成员的值。

packagecn.lsl;public classFinalTest {final int a = 5; //直接赋值

final String str; //普通代码块中赋值

{

str= "zhangsan";

}final int b; //构造器中赋值

publicFinalTest(){

b= 7;

}final static int c = 8; //直接赋值

final static int d; //静态代码块中赋值

static{

d= 9;

}//如果在构造器或初始化块中对final成员变量进行初始化,则不要在初始化之前就访问该成员的值。

final intage;

{//System.out.println(age);

age = 22;

System.out.println(22);

}

}

2.final修饰的局部变量

(1)系统不会对局部变量进行初始化,布局变量必须要显示的初始化。所以使用final修饰的局部变量,既可以在定义的时候指定默认值,也可以不指定默认值。

(2)final修饰形参的时候,不能为该形参赋值。

3.final修饰基本数据类型变量和修饰引用类型变量的区别

使用final修饰基本类型的变量,一旦对该变量赋值之后,就不能重新赋值了。但是对于引用类型变量,他保存的只是引用,final只能保证引用类型变量所引用的地址不改变,但不保证这个对象不改变,这个对象完全可以发生改变。

eg:

final Person p = newPerson();

p.setAge(23); //改变了Person对象的age Field//p=null//编译出错

final修饰的引用类型变量不能被重新赋值,但是可以改变引用变量所引用对象的内容。

4.final的“宏变量”

(1)final修饰符的一个重要用途就是“宏变量”。当定义final变量时就该为该变量指定了初始值,而且该初始值可以在编译时就确定下来,那么这个final变量本质上就是一个“宏变量”,编译器会把程序中

所有用到该变量的地方直接替换成该变量的值。

packagecn.lsl;public classFinalTest {public static voidmain(String[] args){final String name = "小明" + 22.0;final String name1 = "小明" + String.valueOf(22.0);

System.out.println(name== "小明22.0");

System.out.println(name1== "小明22.0");

}

}

final String name1 = "小明" + String.valueOf(22.0);中调用了String类的方法,因此编译器无法再编译的时候确定name1的值,所以name1不会被当成“宏变量”。

packagecn.lsl;public classFinalTest {public static voidmain(String[] args){

String s1= "小明";

String s2= "小" + "明";

System.out.println(s1== s2); //true

String str1= "小";

String str2= "明";

String s3= str1 +str2;

System.out.println(s1== s3); //false//宏替换

final String str3 = "小";final String str4 = "明";

String s4= str3 +str4;

System.out.println(s1== s4); //true

}

}

分析:1.java会使用常量池量管理曾经使用过的字符串直接量。String a = "hello";  那么字符串池中会缓存一个字符串"hello",当执行String b = "hello";会让b直接指向字符串池中的"hello"字符串。所以a==b返回true。

2.String s3 = str1 + str2;编译时无法确定s3的值

3.String s4 = str3 + str4;因为执行了宏替换,所以在编译的时候就已经确定了s4的值

5.用final修饰的方法不能被重写。用final修饰的类不能有子类。

6.不可变类

不可变类是指创建该类的实例后,该实例的Field是不可改变的。

如果创建自定义的不可变类,应该遵循如下规则

(1)使用private和final修饰符来修饰该类的Field。

(2)提供带参数的构造器,用于传入参数来初始化类里的Field。

(3)仅为该类的Field提供getter方法,不要为该类的Field提供setter方法。

(4)如果有必要,重写Object类的hashCode和equals方法。

packagecn.lsl;public classAddress {private finalString detail;private finalString postCode;publicAddress() {this.detail = "";this.postCode = "";

}publicAddress(String detail, String postCode) {this.detail =detail;this.postCode =postCode;

}publicString getDetail() {returndetail;

}publicString getPostCode() {returnpostCode;

}public booleanequals(Object obj){if(this ==obj){return true;

}if(obj !=null && obj.getClass() == Address.class){

Address ad=(Address)obj;if(this.getDetail().equals(ad.getDetail()) && this.getPostCode().equals(ad.getPostCode())){return true;

}

}return false;

}public inthashCode(){return detail.hashCode() + postCode.hashCode() * 31;

}

}

因为final修饰引用类型变量时,表示这个引用变量不可重新被赋值,但引用类型变量所指向的对象依然可被改变。所以在创建不可变类的时候,如果包含的Field类型是可变的,那么这个不可变类就创建失败了。

如下:

packagecn.lsl;className{privateString firstName;privateString lastName;publicName() {super();//TODO Auto-generated constructor stub

}publicName(String firstName, String lastName) {super();this.firstName =firstName;this.lastName =lastName;

}publicString getFirstName() {returnfirstName;

}public voidsetFirstName(String firstName) {this.firstName =firstName;

}publicString getLastName() {returnlastName;

}public voidsetLastName(String lastName) {this.lastName =lastName;

}

}public classPerson {private finalName name;publicPerson(Name name){this.name =name;

}publicName getName(){returnname;

}public static voidmain(String[] args) {

Name n= new Name("明","小");

Person p= newPerson(n);

System.out.println(p.getName().getFirstName());

n.setFirstName("君");

System.out.println(p.getName().getFirstName());

}

}

通过n.setFirstName("君");改变了firstName。

为了保证对象的不可变性

可以修改为如下代码

packagecn.lsl;className{privateString firstName;privateString lastName;publicName() {super();//TODO Auto-generated constructor stub

}publicName(String firstName, String lastName) {super();this.firstName =firstName;this.lastName =lastName;

}publicString getFirstName() {returnfirstName;

}public voidsetFirstName(String firstName) {this.firstName =firstName;

}publicString getLastName() {returnlastName;

}public voidsetLastName(String lastName) {this.lastName =lastName;

}

}public classPerson {private finalName name;publicPerson(Name name){//this.name = name;

this.name = newName(name.getFirstName(), name.getLastName());

}publicName getName(){//return name;

return newName(name.getFirstName(), name.getLastName());

}public static voidmain(String[] args) {

Name n= new Name("明","小");

Person p= newPerson(n);

System.out.println(p.getName().getFirstName());

n.setFirstName("君");

System.out.println(p.getName().getFirstName());

}

}

7.实例缓存的不可变类

如果程序需要经常使用想用的不可变类实例,则应该考虑缓存这种不可变类的实例,因为重复创建相同的对象没有太大的意义,而且加大系统的开销。

可以使用一个数组来作为缓存池,实现不可变类。

packagecn.lsl;classCacheImmutale {private static int MAX_SIZE = 10;//使用数组来缓存实例

private static CacheImmutale[] cache = newCacheImmutale[MAX_SIZE];private static int pos = 0;private finalString name;privateCacheImmutale(String name){this.name =name;

}publicString getName(){returnname;

}public staticCacheImmutale valueOf(String name){for(int i=0; i < MAX_SIZE; i++){if(cache[i] != null &&cache[i].getName().equals(name)){returncache[i];

}

}if(pos ==MAX_SIZE){

cache[0] = newCacheImmutale(name);

pos= 1;

}else{

cache[pos++] = newCacheImmutale(name);

}return cache[pos-1];

}public booleanequals(Object obj){if(this ==obj){return true;

}if(obj != null && obj.getClass() == CacheImmutale.class){

CacheImmutale ci=(CacheImmutale)obj;returnname.equals(ci.getName());

}return false;

}public inthashCode(){returnname.hashCode();

}

}public classCacheImmutaleTest{public static voidmain(String[] args) {

CacheImmutale c1= CacheImmutale.valueOf("hello");

CacheImmutale c2= CacheImmutale.valueOf("hello");

System.out.println(c1==c2);

}

}

分析:以上程序缓存池采用“先进先出”规则来决定哪个对象被移除缓存池。

程序中还使用了private修饰来隐藏该类的构造器,通过提供该类的valueOf方法来获取实例。

Java提供的java.lang.Integer类也是采用类似的策略来处理的,但是只能Integer缓存-128~127之间的Integer对象。

packagecn.lsl;public classIntegerTest {public static voidmain(String[] args) {

Integer a= new Integer(23);

Integer b= Integer.valueOf(23);

Integer c= Integer.valueOf(23);

System.out.println(a==b);

System.out.println(b==c);//Integer只能缓存-128~127之间的Integer对象

Integer d = Integer.valueOf(230);

Integer e= Integer.valueOf(230);

System.out.println(d==e);

}

}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/574341
推荐阅读
相关标签
  

闽ICP备14008679号