内容简介:看一下下面的代码,最终将打印什么呢?代码很简单,就是累加这几个大整数,那么这个程序最终会打印很显然,就这个例子而言,所有这些加法对total没有产生什么影响。原因就是:
问题一:BigInteger你了解不?
看一下下面的代码,最终将打印什么呢?
public static void main(String[] args) { BigInteger fiveThousand = new BigInteger("5000"); BigInteger fiftyThousand = new BigInteger("50000"); BigInteger fiveHundredThousand = new BigInteger("500000"); BigInteger total = BigInteger.ZERO; total.add(fiveThousand); total.add(fiftyThousand); total.add(fiveHundredThousand); System.out.println(total); }
代码很简单,就是累加这几个大整数,那么这个程序最终会打印 555000
么,如果你觉得会的话,那么说明你对 BigInteger
掌握的还是不够好哟。运行这段代码,可以发现最终打印的是0。
解惑1:
很显然,就这个例子而言,所有这些加法对total没有产生什么影响。原因就是:
BigInteger实例是不可改变的。
String
, BigDecimal
,以及包装类类型: Integer
, Long
, Double
等都是如此,我们不能修改现有实例的值,对这些类型的修改将返回新的实例。所以针对该例子,我们只需要将最终计算的结果赋值到新的实例上就可以:
public static void main(String[] args) { BigInteger fiveThousand = new BigInteger("5000"); BigInteger fiftyThousand = new BigInteger("50000"); BigInteger fiveHundredThousand = new BigInteger("500000"); BigInteger total = BigInteger.ZERO; total = total.add(fiveThousand); total = total.add(fiftyThousand); total = total.add(fiveHundredThousand); System.out.println(total); }
问题二:八进制的问题
来看下下面的代码,最终会打印什么?
public static void main(String[] args) { int[] vals = {5, 6, 7, 8, 9, 010, 011, 012}; int[] valTemps = new int[vals.length]; for (int i = 0; i < vals.length; i++) { valTemps[i] = vals[i] - 5; } System.out.println(Arrays.toString(valTemps)); }
方法很简单,我们将一个整数数组中的值减去固定值之后,赋值给新的数组,那么程序会打印什么呢?如果你认为会打印 [0, 1, 2, 3, 4, 5, 6, 7]
,那你可能就需要接着往下看了。
解惑2:
很遗憾,运行程序后,程序的结果是: [0, 1, 2, 3, 4, 3, 4, 5]
,和我们预期不同的是数组后面三个值,那么为什么会这样呢?也许聪明的你很快就看出问题所在了。没错,就是原数组中后面三个值都是 0
开头的。
Java中以0开头的整型字面值常量将按照八进制数值来计算。
也就是说,这里出现的三个 0
开头的值,其实是八进制的值,那么计算的时候首先要转换为十进制,那么 010
的十进制就是 8
, 011
的十进制是 9
,012的十进制是 10
,然后进行计算,最终结果就是我们看到的这样了。
除了八进制是以 0
开头外,二进制是以 0b
开头,而16进制则是以 0x
开头。
所以我们写代码的时候,千万不要没事在整型变量前面给加一个 0
。
问题三:绝对值的问题
看下下面这个问题,先简单说下, Math.abs()
是用于求一个数值的绝对值,最终会有打印结果么?
public static void main(String[] args) { for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { if (Math.abs(i) < 0) { System.out.println("this value is:" + i); } } }
解惑3:
问题很简单,就是判断 int类型 整数范围内,有没有绝对值小于0的数值存在。一般情况下,对于绝对值,我们都知道:
正数的绝对值是它本身;负数的绝对值是对该值取反;0的绝对值是0;
正常来看,是不会有打印结果的,不过结合我们前面学习到的,想必你应该知道,int类型整数范围内,还真有一个值可以满足,那就是 Integer.MIN_VALUE
:
Integer.MIN_VALUE,该值比较特殊,对该值取反还是它本身;对该值取绝对值仍然是它本身。
所以,int类型范围内绝对值小于0的有就仅有一个,就是 Integer.MIN_VALUE
,同样对于Long类型范围内的数值,绝对值小于0的也是有一个,就是 Long.MIN_VALUE
。
所以说,如果你哪天遇到别人问你: 整数范围内有没有绝对值小于0的? ,就可以很明白的回答了。
问题四:传递性的问题
在数学运算中,我们学习过, 等于(=)
定义了一种数与数之间的等价关系,这种关系当且仅当它是 自反的
, 传递的
, 对称的
,我们这里只说狭义的与等于相关的传递性:
传递性,如果 x==y
,并且 y==z
,那么 a==z
;
那么接下来,需要你出出手了,你能写一段违反传递性的代码么?
解惑4:
其实,我们前面已经学习过原生类型的转换中,涉及到窄化与拓展的时候,有可能精度丢失,这时候就可以借助这块的内容来写出违反传递性的代码,比如说:
public static void main(String[] args) { long x = Long.MAX_VALUE; double y = (double) Long.MAX_VALUE; long z = Long.MAX_VALUE - 1; System.out.println(x == y); System.out.println(y == z); System.out.println(x == z); }
这里就会打印 true true false
,这里涉及到了类型拓展时精度丢失的问题,并且涉及到了double类型在数值特别大的时候,会出现 double == (double+1)
的情况,也就是两个double类型之间的差大于1的时候,前面已经介绍过,这里就不多说了。
问题五:静态方法的问题
看下下面的这个程序,最终程序会通过编译并运行成功么?
public static void main(String[] args) { Main main = null; main.print(); } public static void print() { System.out.println("hello world"); }
也就是我们在一个 null
对象上调用了一个方法,那么这个程序会抛出空指针异常么?
解惑5:
很遗憾,这个程序可以正常运行,并且会打印 hello world
,为什么会这样呢?我们学习 Java 的时候学习过,在 null
对象上调用方法将会抛出 NullPointException
的,但这里为什么可以正常运行呢?原因就在于 print
是一个静态方法。
静态方法调用的表达式对象是被忽略的,没有任何要求其对象值为非空的限制。
也就是在静态方法上通过对象而不是类进行调用时,该对象可以是空值,无论该值是不是空值,该值在运行的时候是会被忽略的。
另外,这里再多说一点,我们学习静态方法的时候还了解到:
对静态方法的调用是不存在动态调用这一说的,静态方法的调用对象是编译时就被选定的。
比如说下面的代码:
public class Main { public static void main(String[] args) { Dog dog = new Dog(); dog.brak(); Dog nipper = new Basenji(); nipper.brak(); } } class Dog { public static void brak() { System.out.println("Dog"); } } class Basenji extends Dog { public static void brak() { System.out.println("Basenji"); } }
最终打印的结果是 Dog Dog
,所以这一点也需要注意下。
总之,我们在这个例子中学到的就是:
不要用一个表达式对象来调用静态方法,最好使用类来进行调用。
问题六:循环变量问题
来看下下面的代码,最终程序会怎么执行呢?会打印什么呢?
public class Main { public static void main(String[] args) { for (int i = 0; i < 10; i++) Dog dog = new Dog(); } } class Dog { Dog() { System.out.println("hello world"); } }
看上去程序会循环10次,创建10个对象,然后打印十次 hello world
,可事实上真的是这样么?
这里备注下:我以前面试的时候,有次笔试就出现过这个小问题,当时我左看右看没看出来这里有什么问题,可能当时比较年轻吧。
很遗憾,这里什么都不会打印,连编译都不会通过。
解惑6:
这里的解答也比较简单,因为Java语言规范有说明【JLS14.12-14】:
-
Java中不允许一个本地变量声明作为一条语句出现在for、while或do循环中重复执行;
-
一个本地变量声明作为一条语句只能直接出现在一个语句块中(一个语句块是由一对花括号以及包含在这对花括号中的语句和声明构成的)。
也就是,这里创建对象的这行代码,不能直接出现在for循环中,需要将该对象声明放置于一个语句块中:
public static void main(String[] args) { for (int i = 0; i < 10; i++) { Dog dog = new Dog(); } }
所以说,这里的小问题可能需要我们注意下。
以上所述就是小编给大家介绍的《Java 解惑系列(五):绝对值小于 0 的整数存在么》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Java 解惑系列(五):绝对值小于 0 的整数存在么
- Unity C# Mathf.Abs()取绝对值性能测试
- 答疑解惑之nginx
- 移动端H5解惑-页面适配(二)
- 移动端H5解惑-概念术语(一)
- 解惑3:时间频度,算法时间复杂度
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Grails权威指南
瑞切 / 张若飞 / 电子工业 / 2007-11 / 49.80元
《Grails权威指南》译自由Grails项目负责人Graeme Keith Rocher编写的《The Definitive Guide to Grails》,着重介绍了如何在Grails框架下使用Groovy语言进行敏捷的Web开发。本书详细讲解Grails开发的全部过程,包括项目构架、控制器与视图、与关系数据库之间的ORM映射,以及与Ajax和Java平台的无缝集成。同时该书也揭示了Grai......一起来看看 《Grails权威指南》 这本书的介绍吧!