Java中移位操作运算符的理解
java中的移位运算符有三种:
1、 <<: 左移
2、 >>: 右移
3、 >>>: 无符号右移
使用方法:左移就是将左边的操作数在内存中的二进制数据左移指定的位数,左边移空的部分补零,右移:如果最高位是0,空位就填0,如果最高位是1,空位就填1。无符号右移无论最高位是什么,空位都补零。
数据在内存中以补码的形式存储
左移和右移的数学意义:
对于左移,对于整型a, a<<n=a*2^n(前提是结果在整型的范围之内),对于右移 正的整型a, a>>n=a/2^n,对于负的整型a,a>>n=-(|a|/2^n+1);
为什么对于右移,正数和负数的结果不一样呢?
我们可以看一个例子:
运行结果为:
对于123,其二进制数为0 1111011,右移两位相当于把0 111000右移两位,而0 111000的十进制为120,所以结果为120/4=30;
对于-123,其二进制数为1 0000101,右移两位相当于把1 0000100右移两位,而1 0000100的十进制为-124,所以结果为-124/4=-31。
「Java」位运算符
1、Java中的位运算符(操作符)
1.1 .与运算符
与运算符用符号“&”表示,其使用规律如下:
只有对应的两个二进制位均为1时,结果才为1。例如,9&5,即00001001&00000101=00000001
- 运行结果:
- a 和b 与的结果是:128
- 下面分析这个程序:
- “a”的值是131,转换成二进制就是10000011,而“b”的值是128,转换成二进制就是10000000。根据与运算符的运算规律,只有两个位都是1,结果才是1,可以知道结果就是10000000,即2的7次方,为128。
1.2.或运算符
或运算符用符号“|”表示,其运算规律如下:
只要对应的两个二进制位有一个为1,结果就为1,否则就为0,例如9|5,即00001001|00000101=00001101。
- 运行结果:
- a 和b 或的结果是:129
- 下面分析这个程序段:
- a 的值是129,转换成二进制就是10000001,而b 的值是128,转换成二进制就是10000000,根据或运算符的运算规律,只有两个位有一个是1,结果才是1,可以知道结果就是10000001,即129。
1.3.非运算符
非运算符用符号“~”表示,其运算规律如下:
如果位为0,结果是1,如果位为1,结果是0。
- 运行结果:
- ~a 结果是:1
- 下面分析这个程序段:
- a 的值是2,转换成二进制就是10,非运算符的运算规律,如果位为0,结果是1,如果位为1,结果是0,可以知道结果就是01,即1。
1.4.异或运算符
异或运算符是用符号“^”表示的,其运算规律是:
两个操作数的位中,位相同则结果为0,不同则结果为1。
- 运行结果: a 与 b 异或的结果是:13 分析上面的程序段:a 的值是15,转换成二进制为1111,而b 的值是2,转换成二进制为0010,根据异或的运算规律,可以得出其结果为1101 即13。
2.Java中的运算符(操作符)
程序的基本功能是处理数据,任何编程语言都有自己的运算符。因为有了运算符,程序员才写出表达式,实现各种运算操作,实现各种逻辑要求。
为实现逻辑和运算要求,编程语言设置了各种不同的运算符,且有优先级顺序,所以有的初学者使用复杂表达式的时候搞不清楚。这里详细介绍一下Java中的运算符。
Java运算符很多,下面按优先顺序列出了各种运算符。
2.1 . 一元运算符
因操作数是一个,故称为一元运算符。
++x 因为++在前,所以x的值先加1后用。
x++ 因为++在后,所以x的值先用后加1。
注意:a+ ++b和a+++b是不一样的(因为有一个空格)。
运行结果是: a=10,b=11,sum=21
运行结果是:a=11,b=10,sum=20
2.2.算术运算符
所谓算术运算符,就是数学中的加、减、乘、除等运算。因算术运算符是运算两个操作符,故又称为二元运算符。
这些操作可以对不同类型的数字进行混合运算,为了保证操作的精度,系统在运算过程中会做相应的转化。数字精度的问题,我们在这里不再讨论。下图中展示了运算过程中,数据自动向上造型的原则。
注:
1、实线箭头表示没有信息丢失的转换,也就是安全性的转换,虚线的箭头表示有精度损失的转化,也就是不安全的。
2、当两个操作数类型不相同时,操作数在运算前会子松向上造型成相同的类型,再进行运算。
示例如下:
运行结果如下:
3、移位运算符
移位运算符操作的对象就是二进制的位,可以单独用移位运算符来处理int型整数。
以int类型的6297为例,代码如下:
运行结果:
注:
x<>y相当于x/2y,从计算速度上讲,移位运算要比算术运算快。如果x是负数,那么x>>>3没有什么算术意义,只有逻辑意义。
4、关系运算符
Java具有完备的关系运算符,这些关系运算符同数学中的关系运算符是一致的。具体说明如下:
5、逻辑运算符
逻辑非关系值表
逻辑与关系值表
逻辑或关系值表
在运用逻辑运算符进行相关的操作,就不得不说“短路”现象。代码如下:
逻辑或也存在“短路”现象,当执行到有一个表达式的值为true时,整个表达式的值就为true,后面的代码就不执行了。
“短路”现象在多重判断和逻辑处理中非常有用。我们经常这样使用:
如果str为null,那么执行str.trim().length()就会报错,短路现象保证了我们的代码能够正确执行。
在书写布尔表达式时,首先处理主要条件,如果主要条件已经不满足,其他条件也就失去了处理的意义。也提高了代码的执行效率。
位运算是对整数的二进制位进行相关操作,详细运算如下:
非位运算值表
与位运算值表
或位运算值表
异或位运算值表
运算结果如下:
程序分析:
按位运算属于计算机低级的运算,现在我们也不频繁的进行这样的低级运算了。
6、三目运算符
三目运算符是一个特殊的运算符,它的语法形式如下:
布尔表达式?表达式1:表达式2
运算过程:如果布尔表达式的值为true,就返回表达式1的值,否则返回表达式2的值,例如:
等价于下列代码:
三目运算符和if…else语句相比,前者使程序代码更加简洁。
7、赋值运算符
赋值运算符是程序中最常用的运算符了,示例如下:
补充:
- 字符串运算符: + 可以连接不同的字符串。
- 转型运算符: () 可以将一种类型的数据或对象,强制转变成另一种类型。如果类型不相容,会报异常出来。
需要更多学习笔记干货的小伙伴、欢迎关注公众号【老堂】(づ ̄3 ̄)づ╭❤~
Java常用运算符的使用
在Java编程体系中,运算符有着举足轻重的地位,它们宛如一个个精巧的工具,是处理数据和变量、构建逻辑以及执行各类计算的基础所在。通过运算符对数据进行操作,程序员能够实现复杂多样的逻辑与计算任务,进而编写出功能强大的程序代码。
Java中的运算符种类繁多,功能各异。从操作数数量的角度来看,可划分为一元运算符、二元运算符以及三元运算符。一元运算符如“-”(表示取负数)、“++”(自增1)、“–”(自减1)等,仅需一个操作数就能发挥其作用;二元运算符则需要两个操作数参与运算,像常见的算术运算符“+”(加法)、“-”(减法)、“*”(乘法)、“/”(除法)、“%”(取余),以及关系运算符“==”(等于)、“!=”(不等于)、“>”(大于)、“<”(小于)、“>=”(大于等于)、“<=”(小于等于),还有逻辑运算符“&&”(逻辑与)、“||”(逻辑或)、“&”(按位与)、“|”(按位或)、“^”(按位异或)等都属于此类;三元运算符较为特殊,只有“? :”这一种,需要三个操作数,常用于根据特定条件选择性地执行两个表达式之一,可在一定程度上简化代码逻辑,取代部分if-then-else语句结构。
同时,不同类型的运算符在功能侧重点上也各有不同。例如算术运算符主要用于执行基本的数学运算,关系运算符着重于比较操作数之间的关系并返回布尔值,逻辑运算符则擅长组合多个布尔表达式来判断更为复杂的条件逻辑,位运算符可对整数的二进制位展开相应操作,赋值运算符负责将运算结果准确地赋值给变量。
鉴于Java常用运算符的多样性及其在编程过程中的关键作用,对各类运算符展开详细的探讨与分析就显得十分必要,这将有助于开发者更好地理解并熟练运用它们,从而提高编程效率、编写出高质量的Java程序代码。
在Java编程中,基本四则运算符(加法“+”、减法“-”、乘法“*”、除法“/”、取余“%”)有着广泛的应用场景,以下为大家详细介绍其在具体数字计算场景中的应用以及相关运算规则和类型转换情况。
例如在计算商品总价的场景中,如果已知某商品单价为10元,购买数量为5件,我们可以使用加法来计算多次购买该商品的总价,代码示例如下:
在上述代码中,通过循环不断使用加法运算符累加每次的商品价格,最终得到总价。此外,“+”运算符还可用于字符串的拼接,比如:
这里展示了“+”运算符在不同数据类型上的不同作用,当操作数为字符串时,它执行拼接操作。
假设我们要分配资源数量,有总资源量100个,已经分配出去30个,想知道剩余资源量,就可以利用减法运算符来计算,代码如下:
减法运算符按照常规数学运算规则,从第一个操作数中减去第二个操作数得到差值。
比如计算矩形的面积,已知长为8,宽为5,使用乘法运算符来求面积的代码如下:
乘法运算符将两个操作数相乘,得到相应的乘积结果,其运算规则与数学中的乘法一致。
在Java中,整数除法有着特殊的规则。当进行整数除法运算时(即两个操作数都是整数类型),结果会向下取整,舍弃小数部分,只保留整数部分。例如:
上述代码中,10 / 3的实际数学结果是 3.333…,但在Java的整数除法运算里,结果为 3。如果想要得到精确的浮点数结果,可以将操作数转换为浮点数类型,如:
此时得到的结果 resultDouble 就是包含小数部分的精确值了。
另外,需要特别注意的是,除数不能为0,若在代码中进行除法运算时除数为0,Java会抛出 ArithmeticException 异常,所以在实际编写代码时,建议先进行除数是否为0的判断,例如:
取余运算符常用于判断两个数之间的整除关系或者获取周期性数据等场景。比如要判断一个数是否为偶数,就可以用该数对2取余,如果余数为0,则这个数是偶数,代码示例如下:
取余运算符不仅可以对整数求模,也能对浮点数求模,例如:
输出结果为 1.5,按照数学上取余的概念进行相应的运算。
在四则运算的过程中,还涉及类型转换的情况。当不同类型的数据进行运算时,Java会遵循一定的类型转换规则。比如存在相互兼容的数据类型在运算时,小转大即为自动类型转换(如 int 类型与 double 类型运算,int 会自动转换为 double 类型参与运算),而大转小则需要进行强制类型转换(例如将 double 类型的值赋给 int 类型变量时,要使用强制类型转换),示例代码如下:
总之,掌握基本四则运算符的应用案例、运算规则以及类型转换情况,对于编写正确且高效的Java程序代码至关重要。
自增(++)和自减(–)运算符在Java编程中是常用的一元运算符,它们能够便捷地对变量的值进行加1或减1操作,在很多场景中都发挥着重要作用。以下通过具体案例来详细展示它们的使用方式以及前置和后置形式在运算顺序、返回值等方面的差异。
在Java的循环结构中,自增和自减运算符经常被用于控制循环的次数或者更新循环变量的值。例如常见的 for 循环:
在上述代码中,i++ 就是后置自增运算符的应用。其运算顺序是先使用 i 的当前值参与循环条件的判断以及循环体内部的操作(这里是输出 i 的值),然后在本次循环结束后,再将 i 的值加1。所以,在第一次循环时,i 的初始值为0,先输出0,然后 i 变为1;第二次循环时,i 的值为1,输出1后 i 变为2,以此类推,直到 i 的值达到10,不满足循环条件 i < 10 时,循环结束。
如果将代码修改为使用前置自增运算符:
此时的运算顺序有所不同,++i 会先将 i 的值加1,然后再使用更新后的 i 值参与循环条件判断和循环体操作。比如在第一次进入循环前,i 会先从0变为1,然后判断 1 < 10 成立,进入循环体输出1,接着继续下一次循环时,i 再变为2,依此类推。从最终的循环次数和输出结果来看,与后置自增的情况是一样的,但运算顺序的差异在更复杂的代码逻辑中会产生不同的影响。
再来看一个 while 循环的案例:
这里同样是后置自增,先输出 j 的当前值,然后 j 自增。当 j 从0开始逐步自增到5时,不再满足循环条件 j < 5,循环结束。
在遍历数组时,自增运算符可以方便地用于更新数组的索引值。例如:
上述代码通过 index++ 来不断更新数组的索引,使得每次循环都能访问到数组中的下一个元素,先是输出 array[0],然后 index 自增为1,接着输出 array[1],以此类推,直到遍历完整个数组。
如果想要从数组的末尾往前遍历,可以使用自减运算符,如下所示:
这里的 k– 就是后置自减,先使用 k 的当前值作为数组的索引去获取元素并输出,然后再将 k 的值减1,从而实现从后往前遍历数组的效果。
- 运算顺序差异:前置形式(如 ++a、–a)是先对变量进行自增或自减操作,然后再使用变量的值参与其他运算;后置形式(如 a++、a–)则是先使用变量的当前值参与运算,之后再对变量进行自增或自减操作。例如:
在上述代码中,执行 int n = ++m; 时,先将 m 的值自增为6,然后把6赋值给 n,所以 n 和 m 的值都为6;而执行 int q = p++; 时,先将 p 的当前值5赋值给 q,然后 p 再自增为6,所以 q 的值为5,p 的值为6。
- 返回值差异:前置自增或自减运算符返回的是变量自增或自减后的值,而后置自增或自减运算符返回的是变量自增或自减前的原始值。这一点在参与更复杂的表达式运算时体现得更为明显,例如:
在 int result1 = ++x + y; 中,++x 先将 x 变为4,然后与 y 的值4相加,得到 result1 的值为8;而在 int result2 = a++ + b; 中,a++ 先使用 a 的原始值3与 b 的值4相加,得到7赋值给 result2,然后 a 再自增为4。
在简单的计数场景中,自增和自减运算符能清晰地实现对变量值按步长1进行增减操作,使代码简洁明了。比如统计某个事件发生的次数等情况,通过不断自增变量就能轻松实现。
在复杂的表达式和逻辑判断中,前置和后置形式的选择需要根据具体需求来决定。如果希望先更新变量的值再参与计算,就使用前置形式;如果需要先基于变量的当前值进行运算,后续再更新变量,那就选择后置形式。例如在一个根据条件判断来动态调整某个计数器变量的场景中:
这里根据 condition 的真假来决定是对 count 进行自增还是自减操作,从而影响 count 的最终值。
总之,自增和自减运算符虽然简单,但正确理解其前置和后置的差异以及在不同场景下的应用方式,对于编写准确、高效的Java代码有着重要意义,开发者需要根据具体的代码逻辑需求合理地运用它们,以实现期望的程序功能和变量值变化效果。
在Java编程中,关系运算符常用于比较两个值之间的关系,并返回一个布尔值(true或false),这在许多实际场景中都有着重要作用,以下为大家展示一些具体案例。
在学校的成绩管理系统中,常常需要根据学生的成绩来判断其是否及格、优秀等不同等级情况,这时就会用到关系运算符。例如,我们设定60分及以上为及格,代码示例如下:
在上述代码中,使用了大于等于(>=)关系运算符来比较变量score代表的学生成绩和60这个分数界限,运算结果为true,就表明该学生成绩及格了。
再比如,要判断学生成绩是否达到优秀水平(假设90分及以上为优秀),可以这样写代码:
这里同样是利用大于等于关系运算符,根据比较结果输出相应的布尔值,直观地反映出成绩的等级情况。而且还可以通过多个关系运算符组合在条件判断语句中来划分更多的成绩区间等级,像下面这样:
在这个复杂一点的示例中,不仅用到了大于等于(>=)、小于(<)关系运算符,还结合了逻辑运算符(&&)用于构建多条件判断逻辑,根据学生成绩所在不同区间输出对应的等级评价,关系运算符在此处起到了关键的比较判断作用,是整个逻辑实现的基础。
在电商平台或者零售系统中,比较商品价格大小是极为常见的操作。比如,有两款商品,分别为商品A价格为100元,商品B价格为80元,想要判断商品A价格是否高于商品B价格,代码如下:
通过大于(>)关系运算符进行比较,得到true的结果,表示商品A价格确实高于商品B价格。
又比如,要筛选出价格小于等于100元的商品进行推荐,代码示例可以写成:
在这个循环遍历商品价格数组的过程中,使用小于等于(<=)关系运算符来逐一判断每个商品价格是否满足条件,进而筛选出符合要求的商品进行相应操作,关系运算符在这种批量数据比较场景下发挥了重要作用。
从上述这些案例可以看出,等于(==)、不等于(!=)、大于(>)、小于(<)、大于等于(>=)和小于等于(<=)这些关系运算符的运算结果都是布尔值,它们能够方便地帮助我们在程序中构建各种条件判断逻辑,在不同的业务场景中根据具体的数值比较需求来决定程序的执行路径或者筛选出满足特定条件的数据,是Java编程实现逻辑控制和数据筛选等功能不可或缺的工具。
在实际编程中,往往需要依据多个条件来决定程序的执行路径,关系运算符在构建复杂条件判断逻辑时起着关键作用。例如,在一个员工管理系统中,要筛选出满足特定条件的员工信息进行相应操作。假设我们有员工类,其中包含员工年龄(age)、薪资(salary)、职位级别(level)等属性,现在要找出年龄在30岁到40岁之间,且薪资高于8000元,职位级别为中级(假设用数字2表示中级)的员工,代码可以这样写:
在上述代码的 isTargetEmployee 方法中,通过使用大于等于(>=)、小于等于(<=)、大于(>)、等于(==)这些关系运算符组合成复杂的逻辑表达式,来判断员工是否符合目标筛选条件。如果符合条件,该方法返回 true,否则返回 false。当需要批量处理员工数据时,就可以遍历员工列表,依据这个方法的返回结果来执行不同的业务逻辑,比如对符合条件的员工进行奖金发放等操作。
再比如,在一个电商系统中,要判断用户是否满足某种优惠活动的参与条件。假设优惠活动要求用户的历史消费金额(totalConsumption)大于1000元,且当前购买商品数量(quantity)不少于3件,代码示例如下:
这里利用关系运算符构建的条件判断,决定了后续程序是否给予用户相应的优惠,从而控制程序的执行走向。
关系运算符常被用于循环语句的控制条件设定,以精准控制循环的执行次数和结束时机。比如常见的 for 循环,在遍历数组元素时,通过比较当前索引与数组长度的关系来确定是否继续循环。以下是一个简单的示例,对一个整型数组中的元素进行求和操作:
在上述 for 循环中,关系运算符 i < numbers.length 作为循环的控制条件,每一次循环迭代都会判断当前索引 i 是否小于数组 numbers 的长度,如果满足条件则继续执行循环体,进行元素累加操作;当 i 不小于数组长度时,循环结束。
同样,在 while 循环中关系运算符也有类似应用。例如,要实现一个简单的计数器,从1累加到100,代码可以这样写:
这里利用 count <= 100 这个条件,借助关系运算符控制 while 循环的执行次数,使得计数器能按预期从1逐步累加到100,当 count 的值超过100时,循环结束。
在各种排序算法里,关系运算符是实现元素大小比较以及交换位置等操作的基础工具。以冒泡排序算法为例,它的基本思想是通过反复比较相邻的两个元素,如果顺序不对则进行交换,并不断重复这个过程,直到整个序列有序。以下是用Java实现冒泡排序的简单代码示例,对一个整型数组进行升序排序:
在上述冒泡排序的代码中,内层循环里通过 arrayToSort[j] > arrayToSort[j + 1] 这个条件判断,使用大于关系运算符比较相邻元素的大小关系。如果前一个元素大于后一个元素,就交换它们的位置,经过多次循环迭代,最终实现整个数组元素按照升序排列。
类似地,像选择排序、插入排序等其他排序算法中,关系运算符同样用于比较元素大小,以此来决定元素的移动或者交换顺序,从而达到对数据进行排序的目的。
在使用关系运算符时,需要特别留意数据类型的匹配情况,因为不同数据类型之间的比较可能会出现不符合预期的结果。
对于基本数据类型而言,像整数类型(int、long 等)、浮点类型(float、double)、字符类型(char)等,它们之间进行比较时通常遵循常规的数学或字符编码顺序的比较规则。例如,比较两个整数的大小:
但当涉及不同类型的基本数据类型进行比较时,Java会进行自动类型转换,可能导致一些细微的问题。比如 int 类型和 double 类型比较时,int 会自动转换为 double 类型再进行比较:
然而,如果是浮点数之间进行相等比较(使用 == 运算符),由于浮点数在计算机内部存储表示的精度问题,可能会出现意外情况,比如:
所以在比较浮点数是否相等时,更推荐通过判断它们差值的绝对值是否小于一个极小值(比如 1e-9)来间接判断是否相等,示例代码如下:
对于引用数据类型,如字符串(String),使用关系运算符(像 ==)比较时,比较的是它们的引用地址而不是实际的字符串内容。例如:
若要比较字符串的实际内容是否相等,应该使用 equals 方法,像这样:
总之,在使用关系运算符时,充分了解数据类型的特点以及比较规则,谨慎处理不同类型间的比较操作,能有效避免因数据类型不匹配而导致的错误,确保程序逻辑的正确性。
- “&&”短路与案例(用户登录验证):
在用户登录系统中,通常需要同时验证用户名和密码是否正确才能允许用户登录。假设我们有如下的代码来模拟这个验证过程:
在上述代码中,使用了“&&”短路与运算符。当判断 correctUsername && correctPassword 时,它会先检查 correctUsername 的值,如果这个值为 false(也就是用户名不正确),那么就不会再去检查 correctPassword 的值了,因为只要有一个条件为 false,整个逻辑与的结果就为 false,此时直接判定登录失败。只有当 correctUsername 为 true 时,才会继续去检查 correctPassword 的值,只有两个条件都为 true,才会输出“登录成功”。这种短路特性可以提高程序的执行效率,避免不必要的运算。比如,如果用户名验证不通过,就没必要再去验证密码了,节省了验证密码这一步骤的开销。
- “&”逻辑与案例(权限判断示例):
考虑一个系统中用户具有多种权限,比如有查看文档权限(hasReadPermission)、编辑文档权限(hasEditPermission)、删除文档权限(hasDeletePermission)等,现在要判断用户是否同时具有查看和编辑权限,代码示例如下:
这里使用了“&”逻辑与运算符,不管 hasReadPermission 的值是 true 还是 false,都会继续去判断 hasEditPermission 的值,然后对两个布尔值进行按位与运算(虽然这里是逻辑运算,但“&”本身也可用于位运算,在逻辑运算场景下规则就是都为 true 结果才为 true),最终得到 hasBothPermissions 的值。在这个例子中,因为 hasEditPermission 为 false,所以最终结果为 false。不过对比“&&”短路与,“&”逻辑与在第一个条件已经能确定结果的情况下,依然会执行后续的判断,效率相对较低,但在某些特定场景下,如果希望无论如何都要执行两边的表达式,就可以使用它。
- “||”短路或案例(权限判断):
假设在一个系统中,用户只要具有管理员权限(isAdmin)或者超级用户权限(isSuperUser)中的任意一个,就可以访问某个特定的功能模块。代码可以这样写:
在判断 isAdmin || isSuperUser 时,“||”短路或运算符会先检查 isAdmin 的值,如果这个值为 true(也就是用户是管理员),那么就不会再去检查 isSuperUser 的值了,因为只要有一个条件为 true,整个逻辑或的结果就为 true,此时直接判定用户有权访问该功能模块。只有当 isAdmin 为 false 时,才会继续去检查 isSuperUser 的值,只要两个条件中有一个为 true,就会输出用户有权访问该功能模块。这种短路特性同样提高了执行效率,避免了不必要的运算,比如用户已经是管理员满足条件了,就没必要再去判断是否是超级用户了。
- “|”逻辑或案例(复杂条件判断):
比如在一个资源分配系统中,要判断资源是否可以分配给某个用户,条件是用户的信用等级(creditLevel)达到一定标准(假设大于等于 3 级)或者用户有足够的押金(hasEnoughDeposit),代码示例如下:
这里使用“|”逻辑或运算符,不管 creditLevel >= 3 这个条件的结果是 true 还是 false,都会继续去判断 hasEnoughDeposit 的值,然后根据两个布尔值进行或运算(只要有一个为 true 结果就为 true),得到 canAllocateResource 的值。在这个例子中,因为 hasEnoughDeposit 为 true,所以最终结果为 true,表示可以分配资源给该用户。不过和“||”短路或相比,“|”逻辑或在第一个条件已经能确定结果的情况下,依然执行两边的判断,效率稍低,通常在需要确保两边表达式都执行的场景下使用,例如两边的表达式都有一些附带的操作需要执行时。
- 基本使用案例(条件取反):
在一个投票系统中,假设有一个变量 isVoted 表示用户是否已经投票(true 表示已投票,false 表示未投票),现在要判断用户是否还未投票,就可以使用逻辑非运算符“!”,代码如下:
这里“!”将 isVoted 的布尔值取反,原本 isVoted 为 true,取反后 hasNotVoted 就为 false,直观地实现了条件的反转判断。
- 在复杂逻辑中的应用案例(排除特定情况):
假设在一个员工绩效评估系统中,有一个变量 isUnderperform 表示员工是否绩效不佳(true 表示绩效不佳,false 表示绩效良好),现在要筛选出绩效良好的员工进行奖励,就可以这样写判断条件:
通过“!”对 isUnderperform 取反,将原本表示负面情况的变量转化为可以用于筛选出正面情况(绩效良好)的条件,从而方便地实现了在复杂逻辑中根据需求排除特定情况的目的,帮助构建准确的筛选和判断逻辑。
综上所述,逻辑与、或、非运算符在不同的条件组合下有着各自明确的运算规则和特点,短路特性的“&&”和“||”在合适的场景中能有效提高程序执行效率,而“&”和“|”则在需要确保两边表达式都执行的特定情况下发挥作用,“!”用于简单的取反以及在复杂逻辑中对条件进行反向判断,开发者需要根据实际的业务逻辑和编程需求来合理选择使用这些逻辑运算符。
在Java编程中,逻辑运算符常常会在一些较为复杂的场景下发挥关键作用,以下是对其在多层嵌套条件判断、逻辑表达式构建等复杂逻辑场景应用的详细阐述。
多层嵌套条件判断在实际业务逻辑处理中较为常见,例如在一个完整的表单验证场景里,往往需要对多个字段进行合法性验证,并且这些验证条件之间存在复杂的逻辑关系,这时逻辑运算符就能帮助我们准确地表达这些关系。
假设我们有一个用户注册表单,包含用户名(username)、密码(password)、确认密码(confirmPassword)、电子邮箱(email)以及年龄(age)等字段。验证规则如下:用户名不能为空且长度在6到16位之间;密码不能为空且长度至少8位,同时要和确认密码一致;电子邮箱格式要正确;年龄需大于等于18岁。使用逻辑运算符来实现这个表单验证的代码示例如下:
在上述代码中,通过多个&&(短路与)运算符将各个字段的验证条件组合起来,形成一个总的验证条件表达式。短路特性在这里体现出了优势,比如在判断usernameValid && passwordValid && emailValid && ageValid时,如果usernameValid为false(即用户名不符合要求),那么后续的passwordValid、emailValid和ageValid就不会再进行判断了,因为只要有一个条件为false,整个逻辑与的结果就为false,直接可以确定表单验证不通过,从而避免了不必要的运算,提高了程序的执行效率。
再比如,在一个员工请假审批系统中,不同职位级别、请假天数以及部门的员工有着不同的审批流程,可能会出现多层嵌套的条件判断情况。假设有普通员工、主管和经理三个职位级别,普通员工请假天数小于等于3天由主管审批,大于3天由经理审批;主管请假不论天数都由经理审批;经理请假需经过更高层领导审批(此处暂不细化更高层审批逻辑)。代码示例如下:
上述代码可以通过逻辑运算符进一步优化,利用短路或(||)和短路与(&&)运算符改写为:
在优化后的代码中,运用逻辑运算符清晰地梳理了复杂的条件判断逻辑,同样利用了短路特性,减少不必要的判断步骤,提升代码执行效率。
在构建复杂的逻辑表达式时,逻辑运算符也是不可或缺的工具。比如在一个电商促销系统中,要制定商品的折扣规则,条件可能是:商品为热门商品(isPopular)且库存(stock)大于100件,或者商品处于新品上架期(isNew)且有用户好评(hasPositiveReview),满足这些条件的商品给予8折优惠。代码示例如下:
在这个逻辑表达式(isPopular && stock > 100) || (isNew && hasPositiveReview)中,通过合理运用逻辑与(&&)和逻辑或(||)运算符,准确地描述了商品享受折扣优惠的复杂业务逻辑。而且在判断这个表达式时,短路特性也在发挥作用,例如在判断(isPopular && stock > 100)时,如果isPopular为false,就不会再去判断stock > 100了,接着判断(isNew && hasPositiveReview)部分;同样,在判断(isNew && hasPositiveReview)时,如果isNew为false,也就不会再判断hasPositiveReview了,直到确定整个逻辑表达式的最终结果是true还是false,以此来决定商品是否能享受优惠。
再比如,在一个在线考试系统中,要判断学生的考试成绩是否合格以及是否有资格获得奖励。假设规定总分(totalScore)大于等于60分为合格,并且如果总分大于等于85分且主观题平均分(subjectiveAverage)大于等于40分,则有资格获得奖励。代码示例如下:
这里通过构建包含逻辑运算符的逻辑表达式,清晰地划分出了不同成绩情况对应的业务逻辑,方便后续根据结果进行相应的处理操作。
总之,在面对各种复杂的逻辑场景时,合理运用逻辑运算符能够简洁、准确地表达业务逻辑,而其短路特性更是能帮助避免不必要的运算,有效提升程序的性能,是Java编程中实现复杂功能和逻辑控制的重要手段。
在Java编程中,赋值运算符起着将值赋予变量的关键作用,可分为简单赋值运算符(=)和复合赋值运算符(+=、-=、*=、/=、%=)。
简单赋值运算符(=)是最基本的形式,它遵循将运算符右边的操作数的值存储在运算符左边操作数指定的变量中的规则,运算符左边的操作数为被赋值的变量,右边的操作数可以是常量、变量或表达式等。例如在声明变量并初始化时,像 int num = 10; 就是通过简单赋值运算符将常量 10 赋值给整型变量 num。再比如在程序中后续改变变量的值,num = 20; 也是使用简单赋值运算符将新的值 20 赋给已经声明过的 num 变量。
复合赋值运算符则结合了其他运算与赋值操作,具有独特的便利性和优势。以 += 为例,它的作用是把左边和右边做加法,然后赋值给左边。例如:
这里相当于执行了 x = x + 20 的操作,先计算 x 原来的值 10 与 20 的和,再将结果 30 赋值给 x。
同样的道理,-= 是把左边和右边做减法,然后赋值给左边,比如:
这等同于 y = y – 10 的运算过程。
*= 运算符是把左边和右边做乘法,然后赋值给左边,示例如下:
也就是执行了 z = z * 3 的操作。
/= 运算符是把左边和右边做除法,然后赋值给左边,像:
相当于 a = a / 20 的计算逻辑。
%= 运算符是把左边和右边做除法取余数,然后赋值给左边,例如:
等同于 b = b % 5,即获取 17 除以 5 的余数并赋值给 b。
复合赋值运算符的一个重要优势在于其在简化代码方面表现突出,相较于普通赋值运算结合算术运算的写法,复合赋值运算符能让代码更为简洁易读。比如,如果想让一个变量不断累加某个值,使用复合赋值运算符可以写成 count += 5;,要是用普通赋值与算术运算结合的方式就需要写成 count = count + 5;,当代码中存在大量类似操作时,前者的简洁性就体现得更为明显了。
此外,复合赋值运算符在自动进行类型转换(在符合规则情况下)方面也有着独特的作用。例如:
输出结果为 2,这个操作成功的原因是扩展的赋值运算符其实蕴含了一个强制类型转换,在这里 short 类型数据在运算时本应转成 int 类型,可能会出现因精度问题报错的情况,但复合赋值运算符帮我们自动处理好了类型转换,将最终结果正确地转换回 short 类型并赋值给变量 s。而如果写成 s = s + 1; 就会因与失精度报错,因为 short 类型数据在运算时会转成 int 类型,右侧表达式结果是 int 类型,直接赋值给 short 类型的 s 不符合类型要求,就需要进行强制类型转换,像 s = (short)(s + 1); 这样才能避免报错。
总之,简单赋值运算符和复合赋值运算符在Java编程中都有着广泛且重要的应用场景,熟练掌握它们的使用方法以及理解其特性,有助于我们更加高效、准确地编写代码。
在Java编程中,使用赋值运算符时,类型转换是一个需要重点关注的方面,尤其是在不同数据类型变量之间进行赋值操作时,很可能出现数据精度损失等情况。
当把较大类型的值赋给较小类型变量时,通常需要进行强制类型转换。例如,将 int 类型的值赋给 byte 类型变量,由于 int 类型的取值范围大于 byte 类型,直接赋值会存在潜在的数据溢出风险,所以必须显式地使用强制类型转换,像这样的代码:
在上述代码中,128 这个 int 类型的值超出了 byte 类型所能表示的范围(byte 的取值范围是 -128 到 127),经过强制类型转换后,得到的 numByte 值会出现溢出,实际输出的结果并不是期望的 128,而是 -128,这体现了大类型转小类型时不进行强制转换可能导致的问题。
而对于复合赋值运算符在涉及类型转换时,有着特殊的处理机制。以 byte 类型变量进行复合赋值运算为例,比如:
这里输出结果为 2,操作能够成功的原因是扩展的赋值运算符(如 +=)其实蕴含了一个强制类型转换。在这个例子中,byte 类型数据在运算时本应转成 int 类型(因为在Java中,byte、short、char 类型参与算术运算时会自动提升为 int 类型),如果写成 s = s + 1; 就会因精度问题报错,因为右侧表达式 s + 1 的结果是 int 类型,直接赋值给 byte 类型的 s 不符合类型要求,需要进行强制类型转换,像 s = (byte)(s + 1); 这样才能避免报错。但使用复合赋值运算符 += 时,它自动帮我们处理好了类型转换,将最终结果正确地转换回 byte 类型并赋值给变量 s。
再比如,有如下代码:
同样,这里的 t += 10 相当于 t = (short)(t + 10),即使 short 类型在运算过程中会先提升为 int 类型进行计算,复合赋值运算符也能确保最终结果能正确转换回 short 类型赋值给变量 t,输出为 20。
总之,在使用赋值运算符时,要充分了解不同情况下类型转换的规则,特别是在不同数据类型相互赋值以及使用复合赋值运算符时,谨慎处理类型转换问题,才能避免出现数据错误以及程序运行异常等情况,保证程序的正确性和稳定性。
以下是按位与(&)、按位或(|)、按位异或(^)、左移(<<)、右移(>>、>>>)等位运算符的相关操作案例及应用场景介绍:
按位与运算符(&)参加运算的两个数据,按二进制位进行“与”运算。运算规则为:相对应的位,两个都为1,结果才为1,否则为0。例如:
输出结果为 1。
再比如,利用按位与进行清零操作,如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。例如:
还有取一个数中指定位的方法,找一个数,对应要取的位,该数的对应位为1,其余位为零,此数与目标数进行“与运算”即可。例如要获取一个字节数据(8位)的低4位:
按位或运算符(|)参加运算的两个对象,按二进制位进行“或”运算。运算规则是:相对应的位,两个中有一个为1,结果为1,否则为0。例如:
输出结果为 7。
在权限管理场景中常常用到按位或操作,比如用二进制的方式来表示不同的权限:
按位异或运算符(^)参加运算的两个数据,按二进制位进行“异或”运算,运算规则为:相对应的位,两个不一样,结果为1,否则为0。例如:
输出结果为 6。
它有个有趣的应用是可以实现两个值的交换,而不使用临时变量。例如交换两个整数 a、b 的值可通过下列语句实现:
左移运算符(<<)是将一个数的二进制表示向左移动指定的位数,左边超出的位数舍弃,右边不足的位补0。例如:
输出结果为 20。左移操作常用于快速实现乘法运算,将一个数左移 n 位,相当于这个数乘以 2 的 n 次方,在一些底层优化算法中,若涉及到乘以2的幂次的计算,使用左移运算效率会更高。
右移运算符(>>)是算术右移,将一个数的二进制表示向右移动指定的位数,对于正数,左边不足的位补0;对于负数,左边补1。例如:
无符号右移运算符(>>>)则无论正负数,左边不足的位都补0。例如:
右移操作常用于快速实现除法运算,将一个数右移 n 位,相当于这个数除以 2 的 n 次方(对于整数部分而言),在一些对内存数据处理、优化循环等场景中会使用到右移操作来快速改变数据所代表的量级等。
总之,位运算符在处理二进制数据、进行位掩码操作、底层数据处理以及优化算法等方面有着重要的应用场景,能够帮助开发者更高效地操作数据的二进制表示,实现一些特殊功能和性能优化。
在Java编程中,位运算符在特定场景下相较于其他运算符展现出了显著的性能和应用优势,尤其在对内存利用及运算速度要求较高的情况下,其作用不容小觑。
位运算符直接作用于整数的二进制位,计算机的硬件对二进制位运算有着高效的底层支持。例如,在大量数据处理时,如果需要对数据进行乘2或者除以2的操作,使用左移(<<)和右移(>>)运算符相比于普通的乘法(*)和除法(/)运算符,效率会更高。因为左移一位相当于乘以2,右移一位相当于除以2,且位运算指令在计算机处理器执行时通常只需要更少的时钟周期。像在循环中对一个较大数组元素进行数值调整的场景,若频繁涉及此类运算,采用位运算符能显著加快程序运行速度。以下是一个简单对比示例:
在上述代码中,对大量次(这里设定为1亿次)的相同倍数乘法操作分别用普通乘法和左移位运算来实现,可以发现左移运算的耗时往往明显少于乘法运算,特别是在更复杂、数据量更大的实际项目中,这种性能优势会更加凸显。
位运算符在空间利用方面有着独特优势,可用于对大量数据进行状态标记、压缩存储等场景。例如,在权限管理系统中,如果存在多种权限(如读、写、执行等权限),可以使用一个整数的二进制位来分别表示不同权限的有无。假设有读(0b0001)、写(0b0010)、执行(0b0100)三种权限,使用按位或(|)操作可以合并多个权限到一个变量中,代码如下:
通过这种方式,原本可能需要多个布尔变量或者其他更复杂的数据结构来存储的权限状态,现在仅用一个整数就能表示,大大节省了内存空间。而且后续要检查是否具有某种权限时,通过按位与(&)操作就能快速判断,像判断是否有写权限可以这样写:
再比如,在网络通信中对数据包的处理,某些标志位可以通过位运算进行压缩存储在一个字节或者几个字节中,在接收端再通过相应位运算解析还原出各个标志的状态,有效减少了数据传输和存储时所占用的空间。
在图像处理领域也经常会用到位运算符来优化算法。例如,在图像的灰度处理中,对于图像的每个像素点,其颜色信息通常由RGB(红、绿、蓝)三个通道的值来表示,每个通道的值一般用一个字节(8位二进制)存储。如果要对图像进行一些特效处理或者简单的颜色调整,可以利用位运算来快速操作这些二进制数据。假设要将图像整体亮度降低,可以通过对每个像素点的RGB值进行适当的右移操作(相当于数值变小,亮度降低),代码示例如下(简化示意,实际图像操作更复杂):
在上述代码中,先通过位运算提取出像素点的红色通道值(右移16位并与0xff按位与获取低8位),然后进行右移调整亮度,再通过位运算将调整后的红色通道值写回原像素数据位置,对绿色通道和蓝色通道也可按照类似逻辑处理,利用位运算的高效性可以快速处理整幅图像的像素数据,实现图像亮度调整的效果。
综上所述,位运算符凭借其在性能和空间利用上的优势,在诸多实际开发场景中发挥着重要作用,合理运用它们能够帮助开发者编写出更高效、更节省资源的Java程序代码。
以下通过几个简单案例来展示条件运算符(? : )的基础用法。
根据用户性别显示对应称呼:
假设在一个程序中,我们获取到了用户的性别信息,存储在一个布尔变量 isMale 中(true 表示男性,false 表示女性),现在要根据性别来显示对应的称呼,可以使用条件运算符来实现,代码如下:
在上述代码中,条件表达式为 isMale,当 isMale 的值为 true 时,就会返回表达式1也就是 \”先生\” 这个字符串,赋值给 greeting 变量;当 isMale 的值为 false 时,则返回表达式2 \”女士\”,最终将包含对应称呼的欢迎语句输出。
依据成绩等级输出相应评价:
再比如,根据学生的考试成绩来给出相应的评价等级。设定90分及以上为优秀,60分及以上为及格,60分以下为不及格,代码示例如下:
这里外层的条件运算符中,先判断 score >= 90 这个条件,如果为 true,则直接返回 \”优秀\”;如果为 false,就进入内层的条件运算符继续判断 score >= 60,根据其真假情况返回 \”及格\” 或者 \”不及格\”,从而实现了根据不同成绩区间输出对应评价等级的功能。
从这些案例可以看出,条件运算符(? : )根据布尔表达式的真假来选择执行不同的表达式并返回结果,其语法规则要求必须有三个操作数,即条件表达式、满足条件时执行的表达式1以及不满足条件时执行的表达式2。在实际编程中,对于一些简单的条件判断并赋值的场景,合理运用条件运算符能够使代码更加简洁明了,提高代码的编写效率。
在嵌套条件判断场景中,条件运算符能让代码更为简洁高效。例如,在一个电商系统中,根据用户的会员等级(分为普通会员、银卡会员、金卡会员)以及购买金额来确定折扣力度,代码示例如下:
在上述代码中,外层先通过条件运算符判断会员等级,若是金卡会员,则进入内层的条件运算符根据购买金额进一步判断折扣;若不是金卡会员,再判断是否是银卡会员并根据相应金额确定折扣,以此类推。要是使用if-else语句来实现相同功能,代码结构会更加冗长复杂,如下所示:
对比可以看出,在这种多层嵌套的条件判断场景下,条件运算符使代码更加紧凑,易于阅读(在条件不太复杂的情况下),避免了过多的代码缩进和大段的逻辑判断块。
不过需要注意的是,当嵌套层次过多时,条件运算符的可读性会变差,此时可能就需要考虑使用if-else语句来增强代码的可维护性。
对于一些多分支逻辑,条件运算符可以发挥很好的简化作用。比如根据学生的考试成绩评定等级,设定90分及以上为优秀,80 – 89分为良好,70 – 79分为中等,60 – 69分为及格,60分以下为不及格,使用条件运算符实现的代码如下:
通过连续使用条件运算符,根据不同的成绩区间简洁地返回对应的等级。若采用if-else语句来写,代码会相对繁琐:
显然,条件运算符在这种简单的多分支逻辑场景下,代码量更少,逻辑也能较为清晰地展现出来(只要嵌套不过度复杂)。
在函数中,当返回值需要根据不同条件来生成时,条件运算符很实用。例如,编写一个函数,根据输入的两个整数返回较大的值,代码如下:
调用这个函数:
这里利用条件运算符简洁地实现了比较两个数大小并返回较大值的功能。如果用if-else语句实现同样的函数,代码如下:
可以看出,条件运算符使得函数代码更加紧凑,在这种简单的根据条件生成返回值的场景中优势明显。
但要注意,在函数内使用条件运算符时,如果涉及的条件判断和要执行的表达式较为复杂,例如包含多条语句的逻辑,那么使用if-else语句可能会让代码的可读性和可维护性更好,因为条件运算符更适合简单直接的条件赋值场景。
在Java编程中,运算符是构建程序逻辑、处理数据的关键要素。本文对Java常用运算符进行了详细探讨,以下是各类运算符使用特点及要点的总结回顾。
对于基本四则运算符(加法“+”、减法“-”、乘法“*”、除法“/”、取余“%”),它们能完成常规的数学运算以及特定场景下的数据处理。“+”除用于数字相加外,还能拼接字符串;除法运算在整数相除时会向下取整,要注意除数不能为0,并且不同类型数据运算时存在自动类型转换与强制类型转换规则。掌握四则运算符的应用场景、运算规则以及类型转换情况,对编写正确且高效的代码至关重要。
自增(++)和自减(–)运算符作为一元运算符,能便捷地对变量的值增减1。前置和后置形式在运算顺序和返回值上存在差异,前置是先改变变量值再参与运算,后置则先使用变量当前值参与运算后再改变变量值,开发者需根据具体逻辑需求合理选用,比如在循环计数、迭代数组索引等场景中它们都有着重要作用。
关系运算符(等于“==”、不等于“!=”、大于“>”、小于“<”、大于等于“>=”、小于等于“<=”)用于比较两个值的关系并返回布尔值,广泛应用于条件判断、数据筛选等场景,像判断学生成绩等级、比较商品价格大小等。在复杂条件判断、循环控制条件设定以及数据排序算法中也都发挥关键作用,同时使用时要留意不同数据类型间比较的匹配问题,如浮点数比较相等时需注意精度问题,引用数据类型比较内容要用“equals”方法等。
逻辑运算符(逻辑与“&&”“&”、逻辑或“||”“|”、逻辑非“!”)可组合多个布尔表达式构建复杂条件逻辑。短路特性的“&&”和“||”能提高执行效率,避免不必要运算;“&”和“|”则在需要确保两边表达式都执行的场景下使用,“!”用于简单取反或在复杂逻辑中反向判断条件,在多层嵌套条件判断、逻辑表达式构建等复杂逻辑处理中有着不可或缺的地位。
赋值运算符分为简单赋值(=)和复合赋值(+=、-=、*=、/=、%=)两类。简单赋值用于给变量赋值,复合赋值将运算与赋值结合,简化代码的同时在类型转换方面有独特处理机制,例如在复合赋值运算时能自动处理好一些类型转换情况,避免因精度问题导致的报错,但使用时要注意不同数据类型相互赋值时可能出现的类型转换问题,防止数据溢出或错误赋值。
位运算符(按位与“&”、按位或“|”、按位异或“^”、左移“<<”、右移“>>”“>>>”)直接作用于整数的二进制位,有着性能和空间利用上的优势。在权限管理、图像处理等诸多领域都有重要应用,比如利用位运算可高效实现乘除2的幂次运算、进行状态标记与压缩存储等,合理运用能优化程序性能、节省内存空间。
条件运算符(? : )作为三元运算符,根据布尔表达式的真假选择执行不同表达式并返回结果,在简单的条件判断赋值、嵌套条件判断、简化多分支逻辑以及函数根据条件生成返回值等场景中,能使代码更简洁明了,但嵌套层次过多时会影响可读性,需根据实际情况选择使用。
总之,Java常用运算符各有特点和适用场景,开发者在编程过程中需要深入理解它们的功能、运算规则以及注意事项,根据具体的业务逻辑和功能需求合理选择、正确运用,这样才能编写出高效、准确、易于维护的Java程序代码,充分发挥Java语言在软件开发中的强大功能。
随着技术的不断发展以及编程应用场景日益复杂,对Java常用运算符的深入掌握和灵活运用将变得愈发重要。
在后续更深入的Java编程学习以及实际项目开发中,我们会面临更加复杂且多样化的业务逻辑。比如在大型企业级应用开发里,要处理海量数据的运算、多条件的复杂逻辑判断以及不同模块间数据交互时的精准赋值等情况。那时,这些常用运算符将成为构建高效、稳定程序的关键基石。
我们需要进一步探索如何巧妙结合不同的运算符来解决实际问题。例如,在进行性能优化时,可以充分利用位运算符在处理二进制数据方面的优势,替代一些常规算术运算符执行乘除运算,以此提升运算速度;在构建复杂的条件判断逻辑时,将逻辑运算符与关系运算符精准搭配,更简洁且准确地表达业务规则,同时借助逻辑运算符的短路特性来避免不必要的运算开销,提高程序整体性能。
而且,Java语言自身也在不断更新迭代,新的特性和技术层出不穷。我们要学会把常用运算符的运用与新特性相结合,例如在Java 8引入的Lambda表达式以及Stream API中,合理运用各类运算符来操作流中的数据元素,实现更高效的数据处理和转换。
总之,对于Java常用运算符的学习是一个持续积累和不断实践的过程,期待大家在今后的编程之旅中不断挖掘它们的潜力,编写出更加优质的Java程序代码。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。