java基本功16课:(5)表达式中的陷阱

1.字符串陷阱

1.1 java创建对象的常见方式如下:

  • 通过new调用构造器创建Java对象。
  • 通过Class对象的newInstance()方法调用构造器创建Java对象。
  • 通过Java的反序列化机制从IO流中恢复Java对象。

使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,** 对象序列化不会关注类中的静态变量**。

  • 通过Java对象提供的clone()方法复制一个新的Java对象。
  • 对于字符串以及Byte,Short,Integer,Long,Character,Float,Double和Boolean这些基本类型的包装类。
  • 直接量的方式创建java对象.String str="abc";
  • 通过简单的算法表达式,连接运算来创建Java对象。String str2="abc"+"ddd";

1.2 JVM对字符串的处理

  • String java=new String("给我丶鼓励"); 该语句实际创建了2个字符串对象,一个是“给我丶鼓励”这个直接量对应的字符串对象,一个是由new String()构造器返回的字符串对象。测试代码如下:
        String java=new String("给我丶鼓励"); 
        //test1
        String test1="给我丶鼓励";
        System.out.println(test1==java); //false 一个是在常量区,一个是new出来的内存区   
        //test2
        System.out.println(java.intern()==test1); //true intern()方法是从常量区里返回该对象。
       
  • 如果字符串连接表达式的值在编译的时候可以确定下来,那么JVM会在编译时计算该字符串变量的值,并让它指向字符串池中对应的字符串。也就是说如果一开始,这些算法表达式是字符串直接量、整数直接量,没有变量和方法参与,“宏替换”(使用 final 修饰的变量),那么就可以在编译期就可以确定字符串的值;如果使用了变量、调用了方法,那么只有等到运行时才能确定字符串表达式的值。例子如下:
  
        String hello="hello";
        String java="java";
        final String str1Final="java";
        final String str2Final=java;

        String str1="hellojava";
        String str2="hello"+"java";   
        String str3=hello+java;
        String str4="hello"+str1Final;
        String str5="hello"+str2Final;

        //test
        //字符串直接量
        System.out.println(str1==str2);  //ture 
        //使用了变量
        System.out.println(str1==str3);  //false 
        //宏替换
        System.out.println(str1==str4);  //true 
        //虽然是final 但不是宏替换
        System.out.println(str1==str5);  //false

解释:为什么第二条是false,其实要理解

      String hello="hello";
      String java="java";
      String str3=hello+java;
      //相当于:
      String str3=(new StringBuilder().append("hello").append("java").toString());

因为new了一个新对象,所以比较肯定是false。
反编译后代码是这样的

        String s = "hello";
        String s1 = "java";
        String s2 = (new StringBuilder()).append(s).append(s1).toString();
        String s3 = (new StringBuilder()).append("hello").append("java").toString();

为什么第4条也是false呢?因为没有在编译期就确定下来的值,所以这个final不是宏替换,只能当不变的"变量"对待,所以接下来跟第二条原理一样了。

  • 字符串比较
    如果要比较两个字符串是否相同,用==进行判断就可以了,但如果要判断两个字符串所含的字符序列是否相同,则应该用String重写过的equals()方法进行比较,代码如下:
  //r如果两个字符串相同,返回true
  if(this==anObject){
      retrun true;
}
//如果anObject是String类型
if(anObject instanceof String){
   String anotherString =(String)anObject;
   //n代表当前字符串的长度
   int n=count;
   //如果两个字符串的长度相等
  if(n==anotherString.count){
    //获取当前字符串,anotherString底层封装的字符数组
    char v1[]=value;
    char v2[]=anotherString.value;
   int i =offset;
   int j =anotherString.offset;
   //逐渐比较v1数组和v2数组里的每个字符
   while(n--!=0){
    if(v1[i++]!=v2[j++])
       return false;
}
   return true;
}
     return false;
}

String 类还实现了Comparable接口,因此程序还可通过String提供的compareTo()方法来判断两个字符串之间的大小,当两个字符串所包含的字符序列相等时,程序通过compareTo()比较,将返回0.

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

2.表达式类型的陷阱

2.1 表达式类型

  • 所有 byte、short、char类型将被提升到 int 类型参与运算

  • 整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型,操作数的等级排列如下:

    • char -> int -> long ->float -> double

    • byte -> short -> int -> long ->float -> double

2.2 复合赋值运算符

  • 复合赋值运算符中包含的隐式类型转换,例如
   a=a+5;
   a+=5; //实际上等价于 a=(a的类型)(a+5);
  • 复合赋值运算的时候,小心“溢出”,如果"溢出",会进行高位”截断“。例如:
  short st=5;
  st+=90010;
  System.out.println(st); //将会输出24479
//此时会"溢出",因为系统有一个隐式的类型转换,short只能接受-32768~32767之间的整数,所以就会"溢出",因此会进行高位截断。
  • 如果把+当成字符串连接运算符使用,则+=运算符左边的变量只能是String类型,而不可能是String的父类型(如Object或CharSequence等)。

3.转义字符的陷阱

  • 慎用字符的 Unicode 转义形式
  • 中止行注释的转义字符

4.泛型可能引起的错误

4.1原始类型变量的赋值

  • 当程序把一个原始类型的变量赋给一个带有泛型信息的变量时,总是可以通过编译(只是会提示警告信息)
  • 当程序试图访问带泛型声明的集合的集合元素时,编译器总是把集合元素当成泛型类型处理(它并不关心集合里集合元素的实际类型)
  • 当程序试图访问带泛型声明的集合的集合元素时,JVM会遍历每个集合元素自动执行强制转型,如果集合元素的实际类型与集合所带的泛型信息不匹配,运行时将引发 ClassCastException

4.2原始类型带来的擦除

  • 当把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,所有在尖括号之间的类型信息都会丢弃。

4.3创建泛型数组的陷阱

  • Java 中不允许创建泛型数组

5.正则表达式陷阱

5.1String类的一些方法支持正则表达式

  • matches(String regex);判断该字符串是否匹配指定的正则表达式。
  • String replaceAll(String regex,String replacement);将字符串中所以匹配指定正则表达式的子串替换成replacement后返回
  • String replaceFirst(String regex,String replacement);将字符串中第一个匹配指定正则表达式的子串替换成replacement后返回
  • String[] split(String regex);以regex正则表达式匹配的子串作为分割符来分割该字符串

6.多线程的陷阱

6.1不要调用 RUN 方法

开启线程是用 start() 方法,而不是 run() 方法。

6.2静态的同步方法

对于同步代码块而言,程序必须显式为它指定同步监视器;对于同步非静态方法而言,该方法的同步监视器是 this —— 即调用该方法的 Java 对象;对于静态的同步方法而言,该方法的同步监视器不是 this,而是该类本身。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容