
正文
java不可变代码 java不可变类型有哪些
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
为什么说Java的String对象是不可变的
今天晚上部门领导开会java不可变代码的时候java不可变代码,又突然想起来这个问题,这里记录下来自己java不可变代码的理解,期待以后会有更深刻的收获。
根据JDK中java.lang.String的源码进行分析,从中可以得出String类型的对象不可变的原因,大致上有如下两个java不可变代码:
1、java.lang.String类型在实现时,其内部成员变量全部使用final来修饰,保证成员变量的引用值只能通过构造函数来修改java不可变代码;
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的实现和应用场景。
相关问答
Q1: 昆明Java培训:Java如何创建不可变类?
class:java中class确切的表示为一个类object:java中object确切的表示为一个对象,也称为类的实例其实,如果一个类被设计成不可变的类,那么这个类的实例化对象也是不可变的。
不可变类:当java不可变代码你获得这个类的一个实例引用时,java不可变代码你不可以改变这个实例的内容。
那么,什么是不可变对象?一旦一个类的实例化对象被创建并初始化,那么它就不可以被改变。
我们可以调用访问器方法(getter),复制对象,或者传递对象,但是不允许任何方法改变这个对象的状态。
包装类(e.g.Integer或Float)和String类是不可变类的代表。
访问器方法(accessormethod):对成员变量做出访问的方法,e.g.getter()方法。
修改器方法(mutatormethod):对成员变量做出修改的方法,e.g.setter()方法。
定义一个不可变类如果我们要自己创建一个不可变类,需要遵守下面的规则:将成员变量(field:在一些书中也翻译为域)声明成final并在构造器中初始化。
对于基本类型的成员变量,用final修饰,一旦它被初始化,就不能被改变java不可变代码了。
而对于引用类型的成员变量,不能够改变它的引用。
成员变量如果被声明称final,那么构建对象时,必须要初始化这样的域引用类型是可变的,我们需要采取一些措施来保证它的不可变性。
为什么?如果我们只是声明了一个final的可变引用类型,那么这个引用可以去引用外部的类,或者被其他外部类引用。
在这种情况下,我们要做到:1.这些方法不会改变这些可变对象中的内容2.不要将这些引用分享到外部供其他类使用,例如,如果对成员变量的引用是可以被其他类改变的,那么这些外部类就可以改变这个类中的内容。
3.如果必须要返回一个引用,那么就返回一个对象的深度拷贝,这样尽管返回的对象内容改变了,但也保存着原始的内容。
只提供访问器方法(i.e.getter方法)不提供修改器方法(i.e.setter方法)如果一定要改变这个对象的内容,那就创建一个新的不可变对象内容做相应的修改,返回修改后的对象的引用声明类是final的。
如果一个类可以被继承,那么它子类就可以重载它的方法,并且修改成员变量JavaAPI中不可变类的例子让我们来回顾一下String类,用它来理解上述的几个方面在String类实现中的体现:所有在Stirng类中成员变量都被声明成private,这些成员变量都在构造器中在构建对象时被初始化。
trimconcatsubstring都可以改变String的对象,为了保证String的不可变性,这些方法都返回的是一个改变相应内容后新的对象。
string类被声明称final,所以任何类都不能继承,重载它的方法。
自己实现一个不可变类接下来我们自己实现一个不可变类ImmutableCircle。
//ImmutableCircle.java//PointisamutableclassclassPoint{privateintxPos,yPos;publicPoint(intx,inty){xPos=x;yPos=y;}publicStringtoString(){return"x="+xPos+",y="+yPos;}intgetX(){returnxPos;}intgetY(){returnyPos;}}//ImmutableCircleisanimmutableclass_thestateofitsobjects//cannotbemodifiedoncetheobjectiscreatedpublicfinalclassImmutableCircle{privatefinalPointcenter;privatefinalintradius;publicImmutableCircle(intx,inty,intr){center=newPoint(x,y);radius=r;}publicStringtoString(){return"center:"+center+"andradius="+radius;}publicintgetRadius(){returnradius;}publicPointgetCenter(){//returnacopyoftheobjecttoavoid//thevalueofcenterchangedfromcodeoutsidetheclassreturnnewPoint(center.getX(),center.getY());}publicstaticvoidmain(String[]s){System.out.println(newImmutableCircle(10,10,20));}//othermembersareelided...}上面的程序运行之后,打印:center:x=10,y=10andradius=20上面的程序体现了不可变类的以下几点:·这个类被声明成final,不可以被继承,也不可以重载它的方法·这个类的成员变量都是final并且是私有的·因为成员变量center是一个引用类型,是可变的,所以在他的getter方法中,返回的是对point对象的拷贝设计一个不可变的类最关键的一点:要注意引用类型的成员变量,如果成员变量的类型是可变的引用类型,就必须要采取必要的措施来保护这个成员变量不会被修改不可变类不足的地方不可变对象同样也有不足的地方。
为了保证不可变性,不可变类中的方法会创建出一定量的对象的拷贝。
例如,在上面的代码中,每次调用getcenter方法都会新建并返回一个point对象的拷贝。
而假如我们只需要调用一次,返回一个point对象,就没必要费尽心神的去设计一个不可变类,仅仅只需要一个可变的immutablecircle类就可以了。
String类在很多应用场景中都会用到,如果我们调用String类中trim,concat,或者是在循环中调用substring方法,都会创建一个新的临时String对象。
同时,java也提供了Stringbuffer和Stringbuilder的可变类。
他们同String一样,但是却可以改变这个对象的内容。
所以,我们可以根据不同的场景使用String类或者Stringbuffer/Stringbuilder类。
总结,文章的最后还是那句话,要根据自己的实际需要,去设计代码,而不要过度设计。
Q2: java编程 这个类是不可变类吗?如果不是,给出修改代码(审题)
A是可变类
不可变类特征:
1:所有成员都是 private final 标识
2:不提供对成员的改变方法
3:确保所有的方法不会被重载
4:如果某一个类成员不是基本类型(primitive type)或不可变类,必须通过在成员初始化(in)或者getter方法(out)时通过深度拷贝(即复制一个该类的新实例而非引用)方法,来确保类的不可变。
Q3: Java的string类为什么是不可变的
这是String类定义时控制是final所以它是不可变java不可变代码的java不可变代码,如下语句
String s = "abc";
s = s + "edf";
这两行代码里面声明了一个String的事例s给他赋值abcjava不可变代码,后面又给它赋值abcdef,但是如果打印出内存地址的哈希码会发现不是同一个,也就是说第一行的s和第二行的s不是同一个对象,是把一个新的String对象引用给了s
Q4: 如何让Java类不可变
不可变类的唯一判断条件是java不可变代码:
“ 不可变类的实例在实例的整个生命周期中永远保持初始化的状态”
比如一个类里面有个属性是private List list,然后只提供java不可变代码了getList()方法,但是你还是可以通过getList().add(XXX)来修改list的内容。即是,它没有保持“初始化”状态,它是个可变类。
来自百度:
可变类和不可变类(Mutable and Immutable Objects)的初步定义:
可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容。
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。不可变类的实例一但创建,其内在成员变量的值就不能被修改。
如何创建一个自己的不可变类:
.所有成员都是private
.不提供对成员的改变方法,例如:setXXXX
.确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。
.如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。
Q5: java字符串为什么是不可变对象
从代码层面 , 看String类的源码java不可变代码你会发现 , 一个字符串对象, 其元素是一个final 修饰的byte数组 , 那么就意味着这个字符串对象初始化之后 , 其元素(byte数组)就无法重新赋值java不可变代码了 , 而且String类中并没有getValue 获取这个数组元素的方法 , 所以就无法从数组内更改字符串对象的值 , 另外 , 字符串是放在字符串常量池的 , 既然是常量 , 自然应该是无法更改的 .
通常代码中 对 String 的重新赋值 , 都是更改对象引用 ,就是说重新赋值之后的字符串对象 , 指向java不可变代码了另外一个字符串的内存地址 , 而原本字符串初始值的内存地址 , 并没有发生改变 , 值也没有发生改变 , 改变的是对象的引用地址 .
java不可变代码的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java不可变类型有哪些、java不可变代码的信息别忘了在本站进行查找喔。







