java final对不同对象_java中Final关键字和Immutable Class以及Guava的不可变对象

大纲

写这篇文章的起因

java中Final关键字

如何构建不可变对象

Guava中不可变对象和Collections工具类的unmodifiableSet/List/Map/etc的区别

实验代码

写这篇文章的起因

java项目在使用FindBugs扫描的时候报了一个不能使用可变对象,记得报的是类似如下的信息:

MS: Field is a mutable collection (MS_MUTABLE_COLLECTION)

官方解释:

A mutable collection instance is assigned to a final static field, thus can be changed by malicious code or by accident from another package. Consider wrapping this field into Collections.unmodifiableSet/List/Map/etc. to avoid this vulnerability.

参考FindBugs的描述:http://findbugs.sourceforge.net/bugDescriptions.html

由于最近学习的东西较多,对有些基本的概念略有生疏,所以又温故了一下,顺便提供下上面问题的解决方案,仅供参考。

java中Final关键字

Final是java的一个关键字,可以修饰:变量、方法、类,大致用法,我写了一个测试类,注释也比较多。

package org.unrulylianzi.basis.javass.finalkeyword;

/**

* java final 基本用法

variable

method

class

* */

public class JavaFinalKeyWord {

/**

* 基本类型

* */

private final int a=3;

private final int b;//must be initialized at the time of declaration or inside constructor or block

{

//a=4;不能重复对final的变量赋值

System.out.println(a);

b=4;

}

/**

* 引用类型

* */

private final Person person = new Person("unrulylianzi");//must be initialized at the time of declaration or inside constructor

{

//person = new Person("unrulylianzi_change_final");//不能重复对final的变量赋值

System.out.println(person);

person.setName("unrulylianzi_change_value_not_reference");//可以修改引用类型的值,但是不能赋予新的Person对象

System.out.println(person);

}

/**

* method

* */

public  final String finalMethod(){

return "unrulylianzi_final";

}

/**

* method not final

* */

public  String notFinalMethod(){

return "unrulylianzi_notfinal";

}

}

final class  SubClass extends JavaFinalKeyWord {

@Override

public String notFinalMethod() {

// TODO Auto-generated method stub

return super.notFinalMethod();

}

/**

* final method can not be  overridden in Java

final的方法不能被继承

@Override

public String finalMethod() {

// TODO Auto-generated method stub

return super.finalMethod();

}

*/

}

/**

*

*Final class can not be inheritable in Java.

Final修饰的类不能被继承

class ExtendsFinalClass extends SubClass {

}

*/

其中Person类是一个简单的bean

public class Person {

private String name;

//getter&setter

}

当然Final对性能也有很多好处,这次不会讲到。

如何构建不可变对象

这个问题貌似没太在意过,也没深入思考过Final关键字和Immutable对象之间的关系。不可变对象就是对象一旦创建就是不能被改变的。下面列一下创建不可变类的步骤

声明class为Final,以免class被子类继承,关于多态的概念就不讲啦。

把所有类的属性声明成private,并且不提供set方法。

把所有可变的变量声明为Final,使得这些变量只能初始化一次。

暴露给外部的构造函数,在赋值的时候,要使用深拷贝。

在变量对应的get方法的时候要提供引用类型变量的clone,而不是直接返回。

我创建的一个不可变对象的示例代码如下:

package org.unrulylianzi.basis.javass.immutable;

import java.util.HashMap;

import java.util.Iterator;

/**

* 不变对象

1:Declare the class as final so it can’t be extended.

2:Make all fields private so that direct access is not allowed.

3:Don’t provide setter methods for variables

4:Make all mutable fields final so that it’s value can be assigned only once.

5:Initialize all the fields via a constructor performing deep copy.

6:Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference.

* */

public final class ImmutableClass {

private final int age;

private final String name;

private final HashMap testMap;

/**

* shallow copy

* */

//public ImmutableClass(int age, String name, HashMap testMap) {

//super();

//this.age = age;

//this.name = name;

//this.testMap = testMap;

//}

/**

* deep copy

* */

public ImmutableClass(int age, String name, HashMap testMap) {

super();

this.age=age;

this.name=name;

HashMap tempMap=new HashMap();

String key;

Iterator it = testMap.keySet().iterator();

while(it.hasNext()){

key=it.next();

tempMap.put(key, testMap.get(key));

}

this.testMap=tempMap;

}

/**

* @return the age

*/

public int getAge() {

return age;

}

/**

* @return the name

*/

public String getName() {

return name;

}

public HashMap getTestMap() {

//return testMap

return (HashMap) testMap.clone();

}

}

可见Final关键字是创建不可变对象的基础。

Guava中不可变对象和Collections工具类的unmodifiableSet/List/Map/etc的区别

guava是google的一个库,弥补了java语言的很多方面的不足,很多在java8中已有实现,暂时不展开。Collections是jdk提供的一个工具类。两者之间的区别:

当Collections创建的不可变集合的wrapper类改变的时候,不可变集合也会改变,而Guava的Immutable集合保证确实是不可变的。

测试代码如下:

//guava的实现

public static final List immutableList;

static {

immutableList = ImmutableList.of("a");

}

/**

* 改变immutableList

*

*/

public static void immutableListGuavaChange() {

try {

System.out.println("Try adding more elements to ImmutableList");

/**

* 改变immutableList已存在元素的值,添加新的元素,都会报错,抛出异常

*/

immutableList.set(0, "b");

// immutableList.add("b");

} catch (UnsupportedOperationException e) {

System.out.println(

"Throws UnsupportedOperationException, ImmutableList is immutable, won't allow adding elements");

}

}

Collections工具类的实现:

/**

* Collections工具类实现的不可变list的示例

*/

public class ImmutableListCollections {

public static final Collection unmodifiableList;

public static final List list;

static {

list = Arrays.asList("Once", "upon", "time", "there", "used", "to", "be", "king");

unmodifiableList = Collections.unmodifiableCollection(list);

}

/**

* 改变immutableList

*

*/

public static void immutableListCollectionsChange() {

System.out.println("Try adding more elements to ImmutableList");

/**

* 改变unmodifiableList已存在元素的值,添加新的元素,都会报错,抛出异常

*/

list.set(0, "b");

System.out.println("###修改wrapper类###" + unmodifiableList);

// immutableList.add("b");

}

}

Guava和Collections实现原理(只为说明不可变,未深入)

查看Guava和Collections的实现,发现add方法是如下设计的:

public final void add(int index, E element) {

throw new UnsupportedOperationException();

}

1、定义Final,防止子类改变父类的行为。

2、执行修改操作的时候,直接抛异常。

实验代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值