Java复习3.变量.常量.String.

Java 中的变量常量数据类型 20131004

前言:

还是国庆节,无聊的很,就没事复习点Java的知识,其实C/C++基本上是现在大型企业面试的语言,但是多学习点Java是没有坏处的,而且,将来工作的话,不可能只会一门C++就不管了,现在的开发工程师都是会使用C++和Java两者都是精通的。

话说国庆节结束之后,有一大群公司来招聘,还很多是IT的,那我是去呢,还是去呢?首先声明,我去的话绝对不是篡你们的,可能是考虑到自己的工作地点吧,我想去工作的地方是成都,至于为什么,就是喜欢了,也说不出来为什么(你信吗?)

说道正题,本文是关于常见的Java一些知识点总结,重点是Java中的String类的知识。Java中的String研究了好久好久,收获蛮大的。

1.常量

final String str =”yang”; 不可以改变,如果不加上static,就是存储在stack中的一个常量;其中的yang是在String Pool中的,str指向的是String Pool在内存中的一个副本的地址。

2.变量

局部变量:存储在stack中,当超出变量作用域的时候,自动清退;

全局变量:其实在Java中没有全局变量的概念,只是他们比局部变量的范围大了一点,放在程序的类中,作为类的属性,对于使用static修饰的类的静态变量,可以使用ClassName访问,也可以使用对象访问,但是访问权限应该是public。

3.数据类型的大小

只有char和C++不同,在Java中一个char类型的数据大小是2个byte

4.标识符和关键字

可以使用$开头

5.运算符(我们不常见的)

~按照位取反

& 按位与

|按位或

^按位异或

>> 右移

>>> 右移使用0填充

<< 左移

byte a = 7;

System.out.print(a);

a = (byte) (a>>1);

System.out.print(a);

a = (byte) (a<<1);

System.out.print(a);

6运算符的优先级

! > && > ||

[] > ()

7.Java中的字符串

7.1字符串的初始化:

String a = new String();

a=”yangtengfei”;

或者String a = new String(“yangtengfei”);

String是不可以改变的数据类型,一旦生成就不可以对字符串内容进行修改。这样的好处就是当一个对象需要被多个线程共享的时候,并且访问频繁,可以省略同步和锁的等待时间,提高系统的性能。

String a = new String(“yangtengfei”);

这句代码实际上是生成了两个String对象,一个是”yangtengfei”直接的字符串对象,另一个就是new String返回的空字符串对象。

我们研究一下JVM对于字符串操作的机制:

对于Java的直接字符串对象(String a = “yangtengfei”),JVM会将字符串保存在缓冲池中,同时在内存(在堆中)中有一个副本,变量a指向的是该副本,也就是当第一次使用该直接字符串量的时候,JVM会将他们放字符串缓冲池中;当再次使用该直接字符串量的时候,,无需在创建一个字符串,只需要引用变量执行缓冲池中已经存在字符串的即可。

但是对于String b = new String(“yangtengfei”); 通过new构造器生成的对象都需要在内存中(堆中)开辟新的空间,分配新的地址空间给该对象,但是在缓冲池中依旧是这个对象的引用。

String a = new String("yangtengfei");

String b = new String("yangtengfei");

String c = "yangtengfei";

String d = "yangtengfei";

System.out.println("a==b:" + (a==b)); // false 堆中不用的引用

System.out.println("a==c:" + (a==c));//false 一个是堆新建的,另一个不是

System.out.println("c==d:" + (c==d));//true 都是对堆中同一个对象的引用

System.out.println("a==c.intern():"+ (a.intern()==c.intern()));

System.out.println("a.intern()==b.intern():"+ (a.intern()==b.intern()));

其中intern返回的是对象在String Pool中的引用,他们这些字符串中都是同一个对象,但是在内存中,yangtengfei字符串是在堆中,只是new的对象都是重新分配内存,而直接字符串都是在堆中的同一个引用。最终都是String Pool中的同一个字符串. (有点晕菜的感觉,给你一张图解释一下就明白了).

(图片原创)

字符串初始化的多种情况:

String a = “yang”+ “teng” + “fei”;这个过程中,创建的字符创对象有几个:只有一个,为什么呢 ?

看一下JVM编译器的编译原理:

如果一个字符串是连接表达式,并且可以在编译期间确定下来的话,那么JVM编译器会在编译的时候计算字符串的值,并且将它指向String Pool中的值;但是如果字符串连接的时候使用了方法,或者是变量,那么就只能够等到运行期间才可以知道字符串的值,在编译期间是无法得知的,这样的话就无法利用String Pool

对于String Pool,只有在编译期间确定的字符串才会保存在缓冲池中,而运行期间确定的字符串是不会在缓冲池中保存的

String name = “yang”; name = name + “tengfei”; 这两句代码创建的字符串有几个,三个,一个是yang,一个是 “tengfei”,最后一个是 “yangtengfei”, 这三个字符串是在内存中,更精确地说实在堆中的,而在栈中只有一个变量就是name,指向不同的字符串。

但是在String Pool中存在的字符串只有yang 和tengfei, 而对于字符串 yangtengfei 是不会缓存在String Pool中的,因为是在运行期间才确定的字符串。这样在Heap中会生成垃圾,会被GC自动回收。

使用字符串缓冲池,就是为了节省内存,提高资源的利用率,在缓冲池中的数据是不会被GC回收的,基本上就是常驻内存,所以过多的使用String Pool可能会造成内存溢出(这里不是内存泄露,而是占用了大量的内存空间导致内存爆掉了)。

StringBuffer和StringBuilder去操作可变的字符串的时候,不会在新建一个字符串对象,引用的是同一个字符串对象,减少了字符串的弊端。StringBuilder是线程不安全的,适合于单线程的程序,StringBuffer是线程安全的,因为其中的方法大部分添加了synchronized机制,但是降低了他的效率。

StringBuilder sb = new StringBuilder();

System.out.println(System.identityHashCode(sb));

sb.append("yang");

System.out.println(System.identityHashCode(sb));

sb.append("teng");

System.out.println(System.identityHashCode(sb));

追梦的飞飞

于广州中山大学 20131004

HomePage: http://yangtengfei.duapp.com

上一篇:变量和数据类型&运算符


下一篇:Python学习笔记之模块与包