天天看点

JavaSE Day7

本节内容

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" ;

此时,只分配了一块堆内存空间和一块栈内存空间:

JavaSE Day7
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类对象的内存地址完全相同,内存分配图如下:

JavaSE Day7

在设计String类的时候采用了一种称为共享设计模式的概念。在运行的JVM底层存在一个字符串的对象池(Object Pool),如果用户采用了直接赋值的方式时,会将字符串的内容放入池保存,如果以后其他String对象继续使用直接赋值方式实例化,并且设置了同样的内容时,那么将不会分配新的堆内存空间,而是使用已有对象的引用进行分配继续使用。如果新声明的字符串内容不在对象池中,则会分配一个新的,然后继续放到池中以供下次使用。

2、采用构造方法实例化的方式:

使用构造方法实例化一定要用到new关键字,而一旦使用了new就表示要分配新的内存空间。

String str = new String("Hello") ;

JavaSE Day7

从上可以发现,分配了两块堆内存空间,其中一块是垃圾。这样处理内存的浪费外,使用构造方法定义的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;能直接操作字符串不用字符串引用就直接操作字符串。

转载于:https://www.cnblogs.com/wuzhilong/p/9377946.html