「java不可变对象」什么是不可变对象,如何创建
本篇文章给大家谈谈java不可变对象,以及什么是不可变对象,如何创建对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、java中String 和StringBuffer有什么区别
- 2、java中string为什么不可变
- 3、昆明Java培训:Java如何创建不可变类?
- 4、java 包装类对象的之不可变
- 5、java中是什么是不可变对象和可变对象
java中String 和StringBuffer有什么区别
String和StringBuffer的区别,网上资料可以说是数不胜数,但是看到这篇文章,感觉里面做的小例子很有代表性,所以转一下,并自己做了一点总结。
在java中有3个类来负责字符的操作。
1.Character 是进行单个字符操作的
2.String 对一串字符进行操作。不可变类。
3.StringBuffer 也是对一串字符进行操作,但是可变类。
String:
是对象不是原始类型.
为不可变对象,一旦被创建,就不能修改它的值.
对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.
String 是final类,即不能被继承.
StringBuffer:
是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象
它只能通过构造函数来建立,
StringBuffer sb = new StringBuffer();
note:不能通过付值符号对他进行付值.
sb = "welcome to here!";//error
对象被建立以后,在内存中就会分配内存空间,并初始保存一个null.向StringBuffer
中付值的时候可以通过它的append方法.
sb.append("hello");
字符串连接操作中StringBuffer的效率要比String高:
String str = new String("welcome to ");
str += "here";
的处理步骤实际上是通过建立一个StringBuffer,然后调用append(),最后
再将StringBuffer toSting();
这样的话String的连接操作就比StringBuffer多出了一些附加操作,当然效率上要打折扣.
并且由于String 对象是不可变对象,每次操作Sting 都会重新建立新的对象来保存新的值.
这样原来的对象就没用了,就要被垃圾回收.这也是要影响性能的.
看看以下代码:
将26个英文字母重复加了5000次,
Java代码
1.String tempstr = "abcdefghijklmnopqrstuvwxyz";
2.int times = 5000;
3.long lstart1 = System.currentTimeMillis();
4.String str = "";
5.for (int i = 0; i times; i++) {
6. str += tempstr;
7.}
8.long lend1 = System.currentTimeMillis();
9.long time = (lend1 - lstart1);
10.System.out.println(time);
String tempstr = "abcdefghijklmnopqrstuvwxyz";
int times = 5000;
long lstart1 = System.currentTimeMillis();
String str = "";
for (int i = 0; i times; i++) {
str += tempstr;
}
long lend1 = System.currentTimeMillis();
long time = (lend1 - lstart1);
System.out.println(time);
可惜我的计算机不是超级计算机,得到的结果每次不一定一样一般为 46687左右。
也就是46秒。
我们再看看以下代码
Java代码
1.String tempstr = "abcdefghijklmnopqrstuvwxyz";
2.int times = 5000;
3.long lstart2 = System.currentTimeMillis();
4.StringBuffer sb = new StringBuffer();
5.for (int i = 0; i times; i++) {
6. sb.append(tempstr);
7.}
8.long lend2 = System.currentTimeMillis();
9.long time2 = (lend2 - lstart2);
10.System.out.println(time2);
String tempstr = "abcdefghijklmnopqrstuvwxyz";
int times = 5000;
long lstart2 = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for (int i = 0; i times; i++) {
sb.append(tempstr);
}
long lend2 = System.currentTimeMillis();
long time2 = (lend2 - lstart2);
System.out.println(time2);
得到的结果为 16 有时还是 0
所以结论很明显,StringBuffer 的速度几乎是String 上万倍。当然这个数据不是很准确。因为循环的次数在100000次的时候,差异更大。不信你试试。
根据上面所说:
str += "here";
的处理步骤实际上是通过建立一个StringBuffer,让侯调用append(),最后
再将StringBuffer toSting();
所以str += "here";可以等同于
StringBuffer sb = new StringBuffer(str);
sb.append("here");
str = sb.toString();
所以上面直接利用"+"来连接String的代码可以基本等同于以下代码
Java代码
1.String tempstr = "abcdefghijklmnopqrstuvwxyz";
2.int times = 5000;
3.long lstart2 = System.currentTimeMillis();
4.String str = "";
5.for (int i = 0; i times; i++) {
6. StringBuffer sb = new StringBuffer(str);
7. sb.append(tempstr);
8. str = sb.toString();
9.}
10.long lend2 = System.currentTimeMillis();
11.long time2 = (lend2 - lstart2);
12.System.out.println(time2);
String tempstr = "abcdefghijklmnopqrstuvwxyz";
int times = 5000;
long lstart2 = System.currentTimeMillis();
String str = "";
for (int i = 0; i times; i++) {
StringBuffer sb = new StringBuffer(str);
sb.append(tempstr);
str = sb.toString();
}
long lend2 = System.currentTimeMillis();
long time2 = (lend2 - lstart2);
System.out.println(time2);
平均执行时间为46922左右,也就是46秒。
总结: 如果在程序中需要对字符串进行频繁的修改连接操作的话.使用StringBuffer性能会更高
本文来自CSDN博客,转载请标明出处:
--------------------------------------------------------------------------------------------------------------------------------------------
另外一段网上对String与StringBuffer区别的注解:
String和StringBuffer
String 是不可以变的字符串.
StringBuffer 是可变的字符串.
对StringBuffer进行操作,是在原来的对象之上进行改变. 而对String进行操作,是创建新的对象。
Java代码
1.public class StringTest {
2. public static void stringReplace(String text) {
3. text = text.replace('j', 'i');
4. }
5.
6. public static void bufferReplace(StringBuffer text) {
7. text = text.append("C");
8. }
9.
10. public static void main(String args[]) {
11. String textString = new String("java");
12. StringBuffer textBuffer = new StringBuffer("java");
13.
14. stringReplace(textString);
15. bufferReplace(textBuffer);
16.
17. System.out.println(textString + textBuffer);
18. }
19.}
public class StringTest {
public static void stringReplace(String text) {
text = text.replace('j', 'i');
}
public static void bufferReplace(StringBuffer text) {
text = text.append("C");
}
public static void main(String args[]) {
String textString = new String("java");
StringBuffer textBuffer = new StringBuffer("java");
stringReplace(textString);
bufferReplace(textBuffer);
System.out.println(textString + textBuffer);
}
}
输出结果
javajavaC
String实例化以后所有的属性都是final的,而StringBuffer确不是,这就是可变与不可变。
这是因为第七行text = text.append ("C"),append方法会改变text中的值,而text与textBuffer指向的地址是相同的。因此会打印javaC
再举个例子:
String a = "a"; //假设a指向地址0x0001
a = "b"; //重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的。
因此String的操作都是改变赋值地址而不是改变值操作。
具体:
String:在String类中没有用来改变已有字符串中的某个字符的方法,由于不能改变一个java字符串中的某个单独字符,所以在JDK文档中称String类的对象是不可改变的。然而,不可改变的字符串具有一个很大的优点:编译器可以把字符串设为共享的。
StringBuffer:StringBuffer类属于一种辅助类,可预先分配指定长度的内存块建立一个字符串缓冲区。这样使用
StringBuffer类的append方法追加字符比String使用 + 操作符添加字符到一个已经存在的字符串后面有效率得多。因为使用 + 操作符每一次将字符添加到一个字符串中去时,字符串对象都需要寻找一个新的内存空间来容纳更大的字符串,这无凝是一个非常消耗时间的操作。添加多个字符也就意味着要一次又一次的对字符串重新分配内存。使用StringBuffer类就避免了这个问题.
java中string为什么不可变
为什么不可变,回答这个问题,你就要理解把它设计为不可变的好处,String作为java中最常用的一种类,提供了很多操作方法。把它设计为final有以下好处:
1:稳定性和节省内存开销
final型会在jvm进行类加载的时候就直接进行实例化,这样就节省以后去不断new带来的内存开辟成本了。实例化后固定不可变了,这样它就是很稳定的。java程序员每天都在使用String,如果String不稳定,你想java最基本的操作还能实现吗?
2:防篡改
final是无法被继承的,这样它是独立存在的,自身封装的很好,就不会有子类去修改它本身的方法,不会有外界来打扰它,自身结构也不会被篡改了。
3:安全性:
这和它不能被继承这个息息相关,没有任何类可以继承它,就不会暴露给外部访问它内部方法的机会,这样它自身就比较安全了。
4:方便jvm优化
比如:String str1=“a"+"b"+1; String str2="ab1";为final的话,jvm就可以很方便的把str1的内容优化为str2,并指向同一个引用。这样就不用再去内存中new了。
当然还有很多好处了,java设计者这样做的根本目的就是为了保证java体系基本类的稳固和安全。
昆明Java培训:Java如何创建不可变类?
class:java中class确切的表示为一个类object:java中object确切的表示为一个对象,也称为类的实例其实,如果一个类被设计成不可变的类,那么这个类的实例化对象也是不可变的。
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。
那么,什么是不可变对象?一旦一个类的实例化对象被创建并初始化,那么它就不可以被改变。
我们可以调用访问器方法(getter),复制对象,或者传递对象,但是不允许任何方法改变这个对象的状态。
包装类(e.g.Integer或Float)和String类是不可变类的代表。
访问器方法(accessormethod):对成员变量做出访问的方法,e.g.getter()方法。
修改器方法(mutatormethod):对成员变量做出修改的方法,e.g.setter()方法。
定义一个不可变类如果我们要自己创建一个不可变类,需要遵守下面的规则:将成员变量(field:在一些书中也翻译为域)声明成final并在构造器中初始化。
对于基本类型的成员变量,用final修饰,一旦它被初始化,就不能被改变了。
而对于引用类型的成员变量,不能够改变它的引用。
成员变量如果被声明称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类。
总结,文章的最后还是那句话,要根据自己的实际需要,去设计代码,而不要过度设计。
java 包装类对象的之不可变
先看下面一个例子:
import java.math.BigInteger;
public class BigProblem {
public static void main(String[ ] args) {
BigInteger fiveThousand = new BigInteger("5000");
BigInteger fiftyThousand = new BigInteger("50000");
BigInteger fiveHundredThousand = new BigInteger("500000");
BigInteger total = BigInteger.ZERO;
total.add(fiveThousand);
total.add(fiftyThousand);
total.add(fiveHundredThousand);
System.out.println(total);
}
}
可能会认为这个程序会打印出555000。毕竟,它将total设置为用BigInteger表示的0,然后将5,000、50,000和500,000加到了这个变量上。如果运行该程序,就会发现它打印的不是555000,而是0。很明显,所有这些加法对total没有产生任何影响。
对此有一个很好理由可以解释:BigInteger实例是不可变的。String、BigDecimal以及包装器类型:Integer、Long、Short、Byte、Character、Boolean、Float和Double也是如此,不能修改它的值。不能修改现有实例的值,对这些类型的操作将返回新的实例。起先,不可变类型看起来可能很不自然,但是它具有很多胜过与其向对应的可变类型的优势。不可变类型更容易设计、实现和使用;它出错的可能性更小,并且更加安全[EJ Item 13]。
为了在一个包含对不可变对象引用的变量上执行计算,需要将计算的结果赋值给该变量。这样做就会产生下面的程序,它将打印出所期望的555000:
代码如下:
import java.math.BigInteger;
public class BigProblem {
public static void main(String[] args) {
BigInteger fiveThousand = new BigInteger("5000");
BigInteger fiftyThousand = new BigInteger("50000");
BigInteger fiveHundredThousand = new BigInteger("500000");
BigInteger total = BigInteger.ZERO;
total = total.add(fiveThousand);
total = total.add(fiftyThousand);
total = total.add(fiveHundredThousand);
System.out.println(total);
}
}
java中是什么是不可变对象和可变对象
可变对象(mutable Objects),不可变对象(Immutable ojbects)
不可变对象意味着这个对象是final的,对象中所有的公共属性是final的。同时说明这个对象是线程安全的,这意味着他们可以在多线程中使用,而不需要使用synchronization。
可变对象和不可变对象相反,Java中大部分都是可变对象。
不可变对象有哪些
String,Integer以及其他的封装类型都是不可变对象。
关于java不可变对象和什么是不可变对象,如何创建的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。