美文网首页
Sting的实例化与static final修饰符

Sting的实例化与static final修饰符

作者: VincentLeon | 来源:发表于2019-11-14 16:57 被阅读0次

[String的实例化与static final修饰符]

转载自(https://www.cnblogs.com/acm-bingzi/p/javaStringStatic.html)

String两种实例化方式

一种是通过双引号直接赋值的方式,另外一种是使用标准的new调用构造方法完成实例化。如下:
  String str = "abcd";
  String str = new String("1234);

第一种方法:
  使用直接赋值后,只要是以后声明的字符串内容相同,则不会再开辟新的内存空间。对于String的以上操作,在java中称为共享设计。这种设计思路是,在java中形成一个字符串对象池,在这个字符串对象中保存多个字符串对象,新实例化的对象如果已经在池中定义了,则不再重新定义,而从池中直接取出继续使用。String就是因为采用了这样的设计,所以当内容重复时,会将对象指向已存在的实例空间。

一个双引号包含字符串就是一个String类的匿名对象,但是这种方式使用String不一定创建新对象。在执行到这个字符串的语句时,如String a = "123",JVM会先到常量池里查找,如果有的话返回常量池里的这个实例的引用,否则的话创建一个新实例并置入常量池里。

第二种方法:
  使用new关键字,不管如何都会再开辟一个新的空间。
  new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则,将使得堆中的字符串永远是池中的子集,导致浪费池的空间)!

String实例化的时机

(1)单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
(2)使用new String("")创建的对象会存储到堆区(heap)中,是运行期新创建的;
(3)使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
(4)使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在堆区(heap)中;

注意:上面第(3)句话,编译后合并的字符串会保存在JVM的字符串池中,而不是再生成的class文件中把字符串合并。
  String s = "a" + "b" + "c"; 创建的是一个对象,而不是是四个对象,在字符串常量池中只生成一个字符串对象

字符串池的优缺点

字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。

static final修饰的字符串好吗?

工作后发现,大型的项目里,常常会见到定义字符串使用 private static final String = "abc" 的方式。这种方式有好处吗?

首先使用直接赋值的字串的方式,字符串会在编译期生成在字符串池中。

然后final标记的变量(成员变量或局部变量)即成为常量,只能赋值一次。它应该不影响内存的分配。(查看资料多了,说法不一,在下对此也有点怀疑了,如果final影响内存分配,烦请各位大侠告知)

最后看static修饰符:
static修饰符能够与属性、方法和内部类一起使用,表示静态的。类中的静态变量和静态方法能够与类名一起使用,不需要创建一个类的对象来访问该类的静态成员,所以,static修饰的变量又称作“类变量”。
  “类变量”属于类的成员,类的成员是被储存在堆内存里面的。一个类中,一个static变量只会有一个内存空间,即使有多个类实例,但这些类实例中的这个static变量会共享同一个内存空间。

static修饰的String,会在堆内存中复制一份常量池中的值。所以调用 static final String 变量,实际上是直接调用堆内存的地址,不会遍历字符串池中的对象,节省了遍历时间。

所以使用static final修饰的字符串还是有好处的。

代码测试

<pre>
1 public class Test
2 {
3 public static final String A="ab";
4 public static final String B="cd";
5
6 public static final String C;
7 public static final String D;
8 static{
9 C = "ab";
10 D = "cd";
11 }
12 public static void main(String[] args) {
13 String t = "abcd";//指向池
14
15 String s1 = "ab";//指向池
16 String s2 = "cd";//指向池
17
18 String s = s1+s2;//指向堆
19 System.out.println(s==t);//false
20
21 String ss = "ab"+s2;//指向堆
22 System.out.println(ss==t);//false
23
24 String sss = "ab"+"cd";//指向池
25 System.out.println(sss==t);//true
26
27 String ssss = A+B;//指向池
28 System.out.println(ssss==t);//true
29
30 System.out.println((C+D)==t);//false
31 }
32 }
</pre>

字符串对象可以存放在两个地方,字符串池(pool)和堆,编译期确定如何给一个引用变量赋值

  1. String s="abc";这种形式决定将从pool中寻找内容相同的字符串并返回地址给s,pool中没有就会在pool中新建并返回地址给s
  2. String s = new String("abc");这种形式决定运行期将在堆上新建字符串对象并返回给s,但这个对象不会加入到pool中
  3. String s=s1+s2;s1和s2都是变量,这种形式决定将在堆上创建s1和s2(即便s1和s2指向的对象在池中已经存在,也会将值拷贝到对象创建新对象),然后创建s1+s2并赋给s
  4. String s = "ab"+"cd";同1),都是来自于池
  5. String s = "ab"+s1;类似3)
  6. String s = S1+S2;S1和S2是常量,常量只能赋值一次,S1,S2如果在声明的地方就赋值,那么这个值在编译期就是确定的,后面无法更改,S1+S2在执行前可确定S1/S2已经在池中存在,当然在池中进行,所以s指向pool;但是若S1,S2如果是实例常量在构造器中赋值,或是类常量在静态块中赋值,S1+S2无法确定二者皆来自于池,于是在堆上进行

相关文章

  • 修饰符和访问控制符的区别

    修饰符有三个,static,final,abstract; final可以修饰类、方法、变量; static修饰变...

  • jvm类加载机制

    首先举个例子final static变量会在jvm启动的时候编译好final 实例变量会在获取实例的时候被初始化好...

  • Java 权限修饰符

    修饰符:权限修饰符:private,默认的,protected,public状态修饰符:static,final抽...

  • 13-面向对象

    内容: final static 匿名对象 内部类 包的声明与访问 四种访问修饰符 代码块 1. final关键字...

  • 接口与抽象

    接口 对行为抽象成员变量修饰符public static final方法修饰符public abstract没有具...

  • 优化android程序

    优化java代码 1.尽量使用static和final修饰符 对于一些固定的类和方法尽量使用static修饰符,调...

  • 如何对Java代码进行基本优化

    1、尽量不要使用static、final修饰符和局部变量 final修饰符修饰的变量值不可以修改,修饰的方法不可以...

  • private/final/static 则子类就不能重写该方法

    如果父类方法访问修饰符为 private/final/static 则子类就不能重写该方法,但是被 static ...

  • static 修饰符

    static 修饰符 静态变量: static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的...

  • C#:静态成员和非静态成员的区别

    静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类进行访问 不带有 static 修饰符声明的...

网友评论

      本文标题:Sting的实例化与static final修饰符

      本文链接:https://www.haomeiwen.com/subject/plcsictx.html