使用代码分别运出结果?

点评:下面的程序对实际开发并没有什么意义,但却是CPython中的一个大坑,这道题旨在考察面试者对官方的Python解释器到底了解到什么程度。

d的结果是False,这一点的确让人费解。CPython解释器出于性能优化的考虑,把频繁使用的整数对象用一个叫small_ints的对象池缓存起来造成的。small_ints缓存的整数值被设定为[-5, 256]这个区间,也就是说,在任何引用这些整数的地方,都不需要重新创建int对象,而是直接引用缓存池中的对象。如果整数不在该范围内,那么即便两个整数的值相同,它们也是不同的对象。

CPython底层为了进一步提升性能还做了另一个设定,对于同一个代码块中值不在small_ints缓存范围内的整数,如果同一个代码块中已经存在一个值与其相同的整数对象,那么就直接引用该对象,否则创建新的int对象。需要大家注意的是,这条规则对数值型适用,但对字符串则需要考虑字符串的长度,这一点大家可以自行证明。

扩展:如果你用PyPy(另一种Python解释器实现,支持JIT,对CPython的缺点进行了改良,在性能上优于CPython,但对三方库的支持略差)来运行上面的代码,你会发现所有的输出都是True。

在Java语言中运算符有算术运算符、逻辑运算符、比较运算符等等,虽然简单,但是在Java语言中是十分重要的。接下来我将详细介绍在Java中运算符的知识。

③自增/自减运算符++ –

2.如何使用算术运算符

3.算术运算符的注意事项

加减乘都不用再说了,首先讲一下除法的两条注意事项;

a)int /int 结果还是int,需要使用double来计算,上面的代码已经展示过了

b)0不能作为除数,如果0作为除数进行运算会报错

接着讲一下取余的运算注意事项:

取余符号不仅仅可以对int求模,也能对double来求模;

最后再说一下自增/自减运算符的两条注意事项;

a)如果不取自增运算的表达式的返回值, 则前置自增和后置自增没有区别.

b)如果取表达式的返回值, 则前置自增是先自增再赋值 后置自增的是先赋值再自增

2.如何使用关系运算符

3.关系运算符的注意事项

关系运算符的表达式返回值都是boolean 类型

三:逻辑运算符(重点)

3.逻辑运算符的注意事项

a)对于 && , 如果左侧表达式值为 false , 则表达式的整体的值一定是 false, 无需计算右侧表达式

b)对于 ||, 如果左侧表达式值为 true, 则表达式的整体的值一定是 true, 无需计算右侧表达式

Java中对数据的操作的最小单位不是字节,而是二进制位;

位运算符包括 按位与& 按位或| 按位取反~ 按位异或^

按位与&:如果两个二进制位都是1,则结果为1,否则结果为0;

按位或|:如果两个二进制位都是0,则结果为0,否则结果为1;

按位取反~:如果该位为0则转为1,如果该位为1,则转为0;

按位异或^:如果两个数字的二进制位相同,则结果为0,相异则结果为1;

3.位运算符的注意事项

2.如何使用移位运算符

左移<<:最左侧位不要了,最右侧补0;

右移>>:最右侧位不要了,最左侧补符号位(正数补0,负数补1);

无符号右移>>>:最右侧位不要了,最左侧补0;

3.移位运算符的注意事项

a)左移1位,相当于原数字2,左移N位,相当于原数字2的N次方;

b)右移1位,相当于原数字/2,右移N位,相当于原数字/2的N次方;

c)由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替;

d)移动负数位或者移位位数过大都没有意义

条件运算符只有一个:表达式1?表达式2:表达式3;

2.如何使用条件运算符

3.条件运算符的注意事项

当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值; 当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值

运算符按照优先级别的高低排序分别是:自加/减运算符、 算术运算符、比较运算符、逻辑运算符、赋值运算符。具体请参考下表:

一元运算符,如 -、++、- -和 !

算术运算符,如 *、/、%、+ 和 -

条件运算符和赋值运算符,如 ? :、=、*=、/=、+= 和 -=

以上即使Java运算符知识以及相应实例代码的全部内容,想要了解更多相关Java基础知识的其他内容请搜索以前的文章或继续浏览下面的相关文章,希望大家以后多多支持!

对于这道题,考察的是对String类型的认识以及编译器优化。JavaString不是基本类型,但是有些时候和基本类型差不多,如String b =  "tao" 可以对变量直接赋值,而不用 new 一个对象(当然也可以用 new)。所以String这个类型值得好好研究下。

Java中的变量和基本类型的值存放于栈内存,而new出来的对象本身存放于堆内存,指向对象的引用还是存放在栈内存。例如如下的代码:

变量is以及1存放在栈内存,而s指向的对象”Hello World”存放于堆内存。

栈内存的一个特点是数据共享,这样设计是为了减小内存消耗,前面定义了i=1i1都在栈内存内,如果再定义一个j=1,此时将j放入栈内存,然后查找栈内存中是否有1,如果有则j指向1。如果再给j赋值2,则在栈内存中查找是否有2,如果没有就在栈内存中放一个2,然后j指向2。也就是如果常量在栈内存中,就将变量指向该常量,如果没有就在该栈内存增加一个该常量,并将变量指向该常量。

如果j++,这时指向的变量并不会改变,而是在栈内寻找新的常量(比原来的常量大1),如果栈内存有则指向它,如果没有就在栈内存中加入此常量并将j指向它。这种基本类型之间比较大小和我们逻辑上判断大小是一致的。如定义ij是都赋值1,则i==j结果为true==用于判断两个变量指向的地址是否一样。i==j就是判断i指向的1j指向的1是同一个吗?当然是了。对于直接赋值的字符串常量(如String

);,则会在堆内存创建一个新的String对象,变量w存放在栈内存,w指向这个新的String对象。堆内存中不同对象(指同一类型的不同对象)的比较如果用==则结果肯定都是false,比如s==w?当然不等,sw指向堆内存中不同的String对象。如果判断两个String对象相等呢?用equals方法。

说了这么多只是说了这道题的铺垫知识,还没进入主题,下面分析这道题。 MESSAGE 成员变量及其指向的字符串常量肯定都是在栈内存里的,变量 a 运算完也是指向一个字符串“ taobao ”啊?是不是同一个呢?这涉及到编译器优化问题。对于字符串常量的相加,在编译时直接将字符串合并,而不是等到运行时再合并。也就是说

;编译出的字节码是一样的。所以等到运行时,根据上面说的栈内存是数据共享原则,aMESSAGE指向的是同一个字符串。而对于后面的(b+c)又是什么情况呢?b+c只能等到运行时才能判定是什么字符串,编译器不会优化,想想这也是有道理的,编译器怕你对b的值改变,所以编译器不会优化。运行时b+c计算出来的"taobao"和栈内存里已经有的"taobao"是一个吗?不是。b+c计算出来的"taobao"应该是放在堆内存中的String对象。这可以通过System. );的结果为false来证明这一点。如果计算出来的b+c也是在栈内存,那结果应该是trueJavaString的相加是通过StringBuffer实现的,先构造一个StringBuffer里面存放”tao”,然后调用append()方法追加”bao”,然后将值为”taobao”StringBuffer转化成String对象。StringBuffer对象在堆内存中,那转换成的String对象理所应当的也是在堆内存中。下面改造一下这个语句System. ) 中是否存在相同的字符串常量,如果有就返回。所以 intern()返回的就是MESSAGE指向的"taobao"。再把变量bc的定义改一下,

现在bc不可能再次赋值了,所以编译器将b+c编译成了”taobao”。因此,这时的结果是true

在字符串相加中,只要有一个是非final类型的变量,编译器就不会优化,因为这样的变量可能发生改变,所以编译器不可能将这样的变量替换成常量。例如将变量bfinal去掉,结果又变成了false。这也就意味着会用到StringBuffer对象,计算的结果在堆内存中。

    如果对指向堆内存中的对象的String变量调用intern()会怎么样呢?实际上这个问题已经说过了,(b+c).intern()b+c的结果就是在堆内存中。对于指向栈内存中字符串常量的变量调用intern()返回的还是它自己,没有多大意义。它会根据堆内存中对象的值,去查找String池中是否有相同的字符串,如果有就将变量指向这个string池中的变量。

我要回帖

更多关于 运价代码 的文章

 

随机推荐