「java可变对象」java可变对象有哪些

博主:adminadmin 2022-11-26 10:32:07 61

今天给各位分享java可变对象的知识,其中也会对java可变对象有哪些进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

为什么Java字符串是不可变对象

从代码层面 , 看String类的源码你会发现 , 一个字符串对象, 其元素是一个final 修饰的byte数组 , 那么就意味着这个字符串对象初始化之后 , 其元素(byte数组)就无法重新赋值了 , 而且String类中并没有getValue 获取这个数组元素的方法 , 所以就无法从数组内更改字符串对象的值 , 另外 , 字符串是放在字符串常量池的 , 既然是常量 , 自然应该是无法更改的 .

通常代码中 对 String 的重新赋值 , 都是更改对象引用 ,就是说重新赋值之后的字符串对象 , 指向了另外一个字符串的内存地址 , 而原本字符串初始值的内存地址 , 并没有发生改变 , 值也没有发生改变 , 改变的是对象的引用地址 .

java 什么是不可变对象

不可变对象是指一个对象的状态在对象被创建之后就不再变化。不可变对象对于缓存是非常好的选择,因为你不需要担心它的值会被更改。

创建一个不可变类:

将类声明为final,所以它不能被继承;

将所有的成员声明为私有的,这样就不允许直接访问这些成员;

对变量不要提供setter方法;

将所有可变的成员声明为final,这样只能对它们赋值一次;

通过构造器初始化所有成员,进行深拷贝(deep copy);

在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝;

示例:

public final class Immutable {  

    private final int id;  

    private final String name;  

    private final HashMap map;  

   

    public int getId() {  

        return id;  

    }  

   

    public String getName() {  

        return name;  

    }  

   

    /** 

     * 可变对象的访问方法 

     */  

    public HashMap getMap() {  

        return (HashMap) testMap.clone();  

    }  

   

    /** 

     * 实现深拷贝的构造器*/  

    public Immutable(int i, String n, HashMap hm){this.id=i;  

        this.name=n;  

        HashMap tempMap=new HashMap();  

        String key;  

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

        while(it.hasNext()){  

            key=it.next();  

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

        }  

        this.map = tempMap;  

    }  

  

}

不变模式有两种形式:弱不变模式和强不变模式。

弱不变模式,指类实例的状态是不可改变,但是这个类的子类的实例具有可能会变化的状态,要实现弱不变模式,一个类必须满足下面条件:

对象没有任何会修改对象状态的方法 ,这样一来当对象的构造函数将对象的状态初始化之后,对象的状态便不再改变;

属性都是私有的,以防客户端对象直接修改内部状态;

这个对象所引用的其他对象如果是可变的话,必须设法限制外界对这些可变对象的访问,以防止外界修改这些对象,尽量在不可变对象内部初始化这些被引用的对象,而不要在客户端初始化再传入到不可变对象内部来,如果某个可变对象必须在客户端初始化,然后再传入到不变对象里的话,就应当考虑在不可变对象初始化的时候,将这个可变对象进行拷贝。

弱不变模式的缺点是,一个弱不变对象的子对象可能是可变的,这个可变的子对象可能可以修改父对象的状态,从而可能允许外界修改父对象的状态。

强不变模式:一个类的实例不会改变,同时它的子类的实例也具有不可变化的状态。一个类必须首先满足弱不变模式所要求的所有条件,并且还有满足下面条件之一:

类所有的方法都应当是final,这样这个类的子类不能够重写此类的方法;

此类本身就是final的,那么这个类就不可能会有子类,从而也就不可能有被子类修改的问题;

不变和只读的区别:当一个变量是只读时,变量的值不能直接改变,但是可以在其他变量发生改变的时候改变;比如生日是不变属性,而年龄是只读的,年龄会随着时间发生变化,生日则不会变化。(用final声明的变量是只读的)

不可变对象的好处:

不可变对象更容易构造,测试与使用;

真正不可变对象都是线程安全的;

不可变对象的使用没有副作用(没有保护性拷贝);

对象变化的问题得到了避免;

不可变对象的失败都是原子性的;

不可变对象更容易缓存,且可以避免null引用;

不可变对象可以避免时间上的耦合;

String,StringBuffer,StringBuilder,都是final类,不允许被继承,在本质上都是字符数组,不同的是,String的长度是不可变的而后两者长度可变,在进行连接操作时,String每次返回一个新的String实例,而StringBuffer和StringBuilder的append方法直接返回this,所以当进行大量的字符串连接操作时,不推荐使用String,因为它会产生大量的中间String对象。

StringBuffer和StringBuilder的一个区别是,StringBuffer在append方法前增加了一个synchronized修饰符,以起到同步的作用,为此也降低了执行效率;若要在toString方法中使用循环,使用StringBuilder。

java map表里,key值能否映射到多个Value?

map中的key和value是一一对应的,但是这里的value可以是一个集合,里面可能包含很多值,这样可以实现。使用时,要循环来访问。

Map的可以唯一无序,value无序且不唯一,所以不同的key会有相同的value,但是他的对内存中还是存储着多个相同的value,这是因为在存到里面的时候是根据hash码存的,hash是唯一的。

扩展资料:

注:将可变对象用作映射键时必须格外小心。当对象是映射中某个键时,如果以影响 equals比较的方式更改了对象的值,则映射的行为将是不确定的。此项禁止的一种特殊情况是不允许某个映射将自身作为一个键包含。虽然允许某个映射将自身作为值包含,但请格外小心:在这样的映射上 equals 和 hashCode方法的定义将不再是明确的。

参考资料来源:百度百科-Map

Java中的String对象是不可变的吗

根据JDK中java.lang.String的源码进行分析,从中可以得出String类型的对象不可变的原因,大致上有如下两个:

1、java.lang.String类型在实现时,其内部成员变量全部使用final来修饰,保证成员变量的引用值只能通过构造函数来修改;

2、java.lang.String类型在实现时,在外部可能修改其内部存储值的函数实现中,返回时一律构造新的String对象或者新的byte数组或者char数组;

第2的重要性在于,假如通过String类型的toCharArray方法可以直接访问String类型内部定义的char数组,那么即便String类型内部的char数组使用了final来修饰,也仅仅保证这个成员变量的引用不可变,而无法保证引用指向的内存区域不可变。由上述两点,保证外部不可能修改java.lang.String类型对象的内部属性,从而保证String对象是不可变的。

提到String,就不得不提一下JDK中存在另外两个常用来表示字符串的类,StringBuffer和StringBuilder。根据注释,StringBuffer可谓老资格了,从JDK1.0时即伴随Java征战世界,而StringBuilder直到JDK1.5时才出现。

面试时,StringBuffer和StringBuilder的区别也是常问的话题,有些没有开发经验,对多线程编码不了解、对synchronized的使用不熟悉的兄弟,很容易在这个问题上吃亏。

StringBuffer和StringBuilder的共同点:

1、都是可变对象,对象内的字符缓存会随着拼接操作而动态扩展;

2、用来完成字符串拼接操作;

3、构造时传入内部缓存大小时,可以降低缓存扩展的次数,明显提升字符串拼接操作的效率;

StringBuffer和StringBuilder的区别:

1、StringBuilder的方法都是线程不安全的,从另外一个角度讲,StringBuilder类型的对象在做字符串拼接操作时,由于少了线程同步的操作,执行效率上有很大提升;

2、StringBuffer的方法都加上了synchronized关键字,因而在一定的场景下,StringBuffer类型的对象都是线程安全的,但在执行效率上,由于多了线程同步的操作,因而会有少许的损失;

在大多数场景下,字符串拼接操作都是不需要考虑多线程环境下对结果的影响的,因而使用StringBuilder类型可以提升代码的执行效率。

在多个线程的代码中共享同一个StringBuffer类型的对象时,需要关注synchronized关键字对最终结果的影响。由于StringBuffer类的实现中,仅仅对每个方法使用了synchronized修饰,这只能保证在多线程场景下,访问StringBuffer对象的同一个方法时可以保证最终结果的一致性,假如一个线程访问A方法,另外一个线程方法B方法,则由于加锁对象的不同,可能会出现不一致的现象,这是需要程序员特别要注意的地方。类似的,可以参考Vector的实现和应用场景。

java可变对象的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java可变对象有哪些、java可变对象的信息别忘了在本站进行查找喔。

The End

发布于:2022-11-26,除非注明,否则均为首码项目网原创文章,转载请注明出处。