本节内容
1.匿名对象
2.String的实例化两种方式
3.字符串的比较
4.字符串常量是匿名对象
5.String类对象两种实例化方式的区别
6.String、StringBuffer、StringBuilder之间的关系与区别
一、匿名对象
.匿名对象:没有名字的实体,也就是该实体没有对应的变量名引用。
二.匿名对象的用途
1,当对象对方法进行一次调用的时候,可以使用匿名对象对代码进行简化。
为什么只对方法,而不调用属性呢?因为匿名对象调用属性没意义。
如果对象要多成员进行多次调用,必须给对象起个名字。不能在使用匿名对象。
2,匿名对象可以实际参数进行传递。
三.匿名对象的简单演示
new Car().run();
四.简单的例子
需求
将小汽车改装成3个轮子的黑车。
1:汽车类。
2:汽车修理厂
* 匿名对象 匿名信 修黑车 汽车类 黑车厂类 把汽车的改成黑色3轮车。 */ class Car { String name = "smart"; String color = "red"; int num = 4; void run() { System.out.println(name + ":" + color + ":" + num + ":跑起来了。。。。"); } } class BlackCarFactory { String name; String addr; Car repairCar(Car c) { c.num = 3; c.color = "黑色"; System.out.println("改装成功啦。。。"); } } class Demo1 { public static void main(String[] args) { BlackCarFactory bcf = new BlackCarFactory(); bcf.name = "幸福修理厂"; bcf.addr = "天河区棠东东路御富科贸园a栋206"; // 非匿名对象 Car c = new Car(); c.run(); // 改装 bcf.repairCar(c); // 取车 c.run(); // 匿名对象一,只使用一次: // 如下创建了2个对象 /* * new Car().run(); * * new Car().run(); */ // 匿名对象二,作为实际参数传递 Car c2 = bcf.repairCar(new Car()); c2.run(); System.out.println(); } }
1. 匿名对象设置的属性永远无法获取? 没有引用变量指向那个对象。
2. 任何两个匿名对象使用==比较,永远返回false。
3. 匿名对象主要应用于实参
二、String的实例化两种方式
1、直接赋值实例化:
String name="Drango war"
以上是String对象的直接赋值,以上的代码并没有使用关键字new进行。String类也是类,所以也有构造方法
2、使用构造方法实例化
String str =new String("Drango war");
可以通过构造方法为String类对象实例化,但在构造里面依然要接收一个本类对象
Java中的比较: "=="的使用
在Java中如果是基本类型的比较:
”==“比较的是基本类型的值。而不是内存地址。
如果使用”==“比较的是引用数据类型,比较的是内存地址。而在String中也可以使用”==“来比较
int a=10; int b=10; System.out.println(a==b); String name="Drango war"; String name1= new String("Drango war"); String name2=name1; System.out.println(name==name1); System.out.println(name2==name1); 运行结果: true false true
通过以上分析可以发现,“==”比较的不是字符串对象包含的内容,而是两个对象所在的的内存对象的数值。所以“==”属于数值比较,比较的是内存地址。
如果想比较字符串的内容,可以使用String类的equals()方法。
String name="Drango war"; String name1= new String("Drango war"); String name2=name1; System.out.println( name.equals(name1)); System.out.println(name2.equals(name1)); 运行结果 true true
于是,现在比较的不是字符串的内存地址的数值,而是字符串的内容。
小结:
(1) ==:比较的是两个字符串内存地址的数值是否相等,属于数值比较;
(2)equals():比较的是两个字符串的内容,属于内容比较。
三、字符串常量是匿名对象
在各个语言中并没有提供字符串的数据类型定义,很多语言都是使用字符数组来描述字符串的概念,在Java中也没有字符串的概念,只是Java自己做了简单处理。但是在Java中字符串依然不属于基本数据类型,字符串是作为String类的匿名对象的形式存在的。
String name="Drango war"; System.out.println("Drango war".equals(name)); 运行结果: true
匿名对象可以调用类中的方法与属性,而以上的字符串调用了equals()方法,所以它一定是一个对象。
四、String类对象两种实例化方式的区别
1、直接赋值的实例化方式:
String str = "Hello" ;
此时,只分配了一块堆内存空间和一块栈内存空间:
String str1 = "Hello" ; String str2 = "Hello" ; String str3 = "Hello" ; System.out.println(str1 == str2) ; System.out.println(str1 == str3) ; System.out.println(str2 == str3) ; 运行结果 true true true
我们发现以上所有直接赋值的String类对象的内存地址完全相同,内存分配图如下:
在设计String类的时候采用了一种称为共享设计模式的概念。在运行的JVM底层存在一个字符串的对象池(Object Pool),如果用户采用了直接赋值的方式时,会将字符串的内容放入池保存,如果以后其他String对象继续使用直接赋值方式实例化,并且设置了同样的内容时,那么将不会分配新的堆内存空间,而是使用已有对象的引用进行分配继续使用。如果新声明的字符串内容不在对象池中,则会分配一个新的,然后继续放到池中以供下次使用。
2、采用构造方法实例化的方式:
使用构造方法实例化一定要用到new关键字,而一旦使用了new就表示要分配新的内存空间。
String str = new String("Hello") ;
从上可以发现,分配了两块堆内存空间,其中一块是垃圾。这样处理内存的浪费外,使用构造方法定义的String类对象,其内容不会保存在对象中(因为重新分配了新的一块堆内存)。
现在希望使用构造方法定义的String类对象,其内容要保存在对象中,该怎么办么?我们可以使用String类定义的一个手工入池的方法:
public String intern()
小结:String类对象两种实例化的区别?
(1)直接赋值实例化方式(String str = “xxx”):只会分配一块堆内存空间,并且对象内容自动入池,以供重复使用;
(2)构造方法实例化方式(String str = new String(“xxx”)):会分配两块堆内存空间,其中有一块是垃圾,并且不会自动入池,用户可以使用intern()方法手动入池。
String、StringBuffer、StringBuilder之间的关系与区别
1.可变与不可变
1)String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
private final char value[];
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。
2)StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。
StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
StringBuffer和StringBuilder类功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。对于经常要改变值的字符串应该使用StringBuffer和StringBuilder类
2.是否多线程安全
String中的对象是不可变的,也就可以理解为常量,显然线程安全。
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的
3.StringBuffer和StringBuilder类的速度比较
一般情况下,速度从快到慢:StringBuilder>StringBuffer>String,这种比较是相对的,不是绝对的。(要考虑程序是单线程还是多线程)
不考虑多线程,采用String对象时,执行时间比其他两个都要高得多,而采用StringBuffer对象和采用StringBuilder对象的差别也比较明显;而以String类为例,操作字符串对象引用相加类型使用的时间比直接/操作字符串相加使用的时间也多得多。由此可见,如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是StringBuffer;能直接操作字符串不用字符串引用就直接操作字符串。