zoukankan      html  css  js  c++  java
  • Java五道输出易错题解析(进来挑战下)

    收集了几个易错的或好玩的Java输出题,分享给大家,以后在编程学习中略微注意下就OK了。

    1. 看不见的空格?

    以下的输出会正常吗?

    package basic;
    
    public class IntegerTest {
    
        public static void main(String[] args) {
            System.out.println(Integer.parseInt("1"));
            System.out.println(Integer.parseInt("2"));
     }
    }

    解析:将上面代码复制下(不要自己手敲)在自己的环境里执行看看,是不是输出以下错误来了:

    1
    Exception in thread "main" java.lang.NumberFormatException: For input string: "2"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at basic.IntegerTest.main(IntegerTest.java:7)

    居然说第二条语句有问题,表面上全然看不出来不论什么问题是不是!


    实际上这里的错误原因涉及到一个概念 — 零宽度空格,可能有人接触过,但相信很多其它的人甚至都没听过,什么是零宽度空格?它实际上是一个Unicode字符,是一个空格。关键是它没有宽度,因此我们一般肉眼看不到。

    但能够在vim下看到,上面的第二条语句中的2前面就有一个零宽度空格。放到vim中打开后你会发现是以下这种语句:

     System.out.println(Integer.parseInt("<feff>2"));

    Unicode规范中定义,每个文件的最前面分别增加一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZEROWIDTHNO-BREAKSPACE),用FEFF表示。

    这正好是两个字节,并且FF比FE大1。因此以下的语句会输出65279。刚好是FEFF

    System.out.println((int)"2".charAt(0));

    2. 类静态成员初始化

    以下的程序能编译通过么?假设通过,说结果并解释,不能编译,说错误原因。

    class A
    {
        public static int X;
        static { X = B.Y + 1;}
    }
    public class B
    {
        public static int Y = A.X + 1;
        static {}
        public static void main(String[] args) {
            System.out.println("X = "+A.X+", Y = "+B.Y);
        }
    }

    解析:这个程序能正确执行,类的执行步骤例如以下:

    首先载入主类B,初始化静态成员Y。发现须要类A的信息,于是载入类A。初始化静态成员X,也用到B类信息,因为此时B类的Y还未成功载入因此这里是默认值0。从而得到A类的X为1,然后返回到B类,得到Y为2。

    3. 装箱拆箱的实际过程

    关于自己主动装箱,相信大部分人都明确是怎么一回事,但真的全然明确了嘛?
    先看以下的代码:

    Short s1 = 1;
    Short s2 = s1;
    System.out.println(s1 == s2);

    谁都知道当然打印true了。如今加一句试试:

    Short s1 = 1;
    Short s2 = s1;
    s1++;
    System.out.println(s1 == s2);

    还是true吗?No。这次输出成了false。

    WHY?难道s1和s2引用的不是同一个对象吗?有这些疑问的说明你对自己主动装箱拆箱的过程还不是非常清楚。实际上上面的代码能够翻译为以下的代码(实际执行过程,要掌握):

    Short s1 = new Short((short)1);
    Short s2 = s1;
    short tempS1 = s1.shortValue();
    tempS1++;
    s1 = new Short(tempS1);
    System.out.println(s1 == s2);

    哦,原来如此,这下明确了。因此我们在使用自己主动装箱的时候小心点为妙。

    4. 你自以为是的异常

    先来两句代码:

    NullTest myNullTest = null;
    System.out.println(myNullTest.getInt());

    相信非常多人看到这段代码时。都会自以为是的说:NullPointerException。果真如此吗?你还没看到NullTest 这个类是怎样定义的呢。

    如今看看这个类的定义:

    class NullTest {
         public static int getInt() {
             return 1;
         }
    }

    因为getInt()是静态方法,他只和类相关,和详细的对象无关,类完毕载入时,就可以通过类名.getInt()进行调用。因此这里就算对象实例为NULL也会正常输出1.
    记住:类变量和类方法的使用,只依赖引用的类型。即使引用为null,仍然能够调用。从良好实践的角度来看,明智的做法是使用NullTest.getInt()来取代myNullTest.getInt(),但谁不不能保证不会碰到这种代码。因此还是小心为妙。

    5. 变长參数和数组,怎样变通?

    变长參数特性带来了一个强大的概念,能够帮助开发人员简化代码。

    只是变长參数的背后是什么呢?Basically,就是一个数组。

    public void calc(int... myInts) {} 
    calc(1, 2, 3);

    编译器会将前面的代码翻译成相似这样:

    int[] ints = {1, 2, 3};
    calc(ints);

    只是这里有两点须要注意:

    • 当心空调用语句,这相当于传递了一个null作为參数。
      calc();
      等价于
      int[] ints = null;
      calc(ints);
    • 当然,以下的代码会导致编译错误,因为两条语句是等价的:
      public void m1(int[] myInts) { ... }
      public void m1(int... myInts) { ... }

    參考资料

  • 相关阅读:
    struct xxx enum(在class下,在static void Main上)
    集合( Stack / Queue / Hashtable 都没有索引)
    集合(ArrayList)
    数组(for 循环+等量代换)
    类型(Math 、Datetime 、random )
    语句(语句分类及if语句)
    运算符分类、优先级
    基本类型转换及练习
    语言基础(项目结构、数据类型、变量、常量)
    进制转换(二进制、八进制、十进制与十六进制之间的相互转换)
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7238393.html
Copyright © 2011-2022 走看看