运算符

2021/8/25 6:06:07

本文主要是介绍运算符,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

运算符

运算符用于连接值。

算术运算符

四则运算

在Java中,使用算术运算符+、一、*、/表示加、减、乘、除运算。当参与/运算的两个操作数都是整数时,表示整数除法;否则,表示浮点除法。整数的求余操作(有时称为取模)用%表示。例如,15/2等于7,15%2等于1,15.0/2等于7.5。需要注意,整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或NaN结果。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
		System.out.println(15/2);
		System.out.println(15%2);
		System.out.println(15.0/2);
   }
}

运行结果

7
1
7.5

整数除0

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
		System.out.println(1/0);
   }
}

运行结果

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at HuangZiHanTest.main(HuangZiHanTest.java:8)

浮点数被0除

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
		System.out.println(1.0/0);
   }
}

运行结果

Infinity

注释

可移植性是Java语言的设计目标之一。无论在哪个虚拟机上运行,同一运算应该得到同样的结果。对于浮点数的算术运算,实现这样的可移植性是相当困难的。double类型使用64位存储一个数值,而有些处理器则使用80位浮点寄存器。这些寄存器增加了中间过程的计算精度。例如,以下运算:

double w=x*y/z;

很多Intel处理器计算x
×y,并且将结果存储在80位的寄存器中,再除以z并将结果截断为64位。这样可以得到一个更加精确的计算结果,并且还能够避免产生指数溢出。但是,这个结果可能与始终使用64位计算的结果不一样。因此,Java虚拟机的最初规范规定所有的中间计算都必须进行截断。这种做法遭到了数字社区的反对。截断计算不仅可能导致溢出,而且由于截断操作需要消耗时间,所以在计算速度上实际上要比精确计算慢。为此,Java程序设计语言承认了最优性能与理想的可再生性之间存在的冲突,并给予了改进。在默认情况下,现在虚拟机设计者允许对中间计算结果采用扩展的精度。但是,对于使用strictfp关键字标记的方法必须使用严格的浮点计算来生成可再生的结果。

例如,可以把main方法标记为

public static **strictfp** void main(String[] args)

那么,main方法中的所有指令都将使用严格的浮点计算。如果将一个类标记为strictfp,这个类中的所有方法都要使用严格的浮点计算。

具体的计算细节取决于Intel处理器的行为。在默认情况下,中间结果允许使用扩展的指数,但不允许使用扩展的尾数(Intel芯片支持截断尾数时并不损失性能)。因此,这两种方式的区别仅仅是采用默认方式不会产生溢出,而采用严格的计算有可能产生溢出。

数学函数与常量

在Math类中,包含了各种各样的数学函数。在编写不同类别的程序时,可能需要的函数也不同。

sqrt方法

要想计算一个数值的平方根,可以使用sqrt方法:

double x=4;
double y=Math.sqrt(x);
System.out.println(y);   //prints 2.0

程序示例

public class HuangZiHanTest
{  
	public static void main(String[] args)
   {
		double huangzihan_x=4;
		double huangzihan_y=Math.sqrt(huangzihan_x);
		System.out.println(huangzihan_y);   //prints 2.0
   }
}

运行结果

2.0

注释

静态方法

println方法和sqrt方法存在微小的差异。println方法处理System.out对象。但是,Math类中的sqrt方法并不处理任何对象,这样的方法被称为静态方法。

幂运算

在Java中,没有幂运算,因此需要借助于Math类的pow方法。以下语句:

double y=Math.pow(x,a);

将y的值设置为x的a次幂(xe)。pow方法有两个double类型的参数,其返回结果也为double类型。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
		double huangzihan_x=2.0;
		double huangzihan_a=3.0;
		double huangzihan_y=Math.pow(huangzihan_x,huangzihan_a);
		System.out.println(huangzihan_y);   
   }
}

运行结果

8.0

floorMod方法

floorMod方法的目的是解决一个长期存在的有关整数余数的问题。考虑表达式n%2。所有人都知道,如果n是偶数,这个表达式为0;如果n是奇数,表达式则为1。当然,除非n是负数。如果n为负,这个表达式则为-1。为什么呢?设计最早的计算机时,必须有人制定规则,明确整数除法和求余对负数操作数该如何处理。数学家们几百年来都知道这样一个最优(或称“欧几里得”)规则:余数总是要≥0。不过,最早制定规则的人并没有翻开数学书好好研究,而是提出了一些看似合理但实际上很不方便的规则。

下面考虑这样一个问题:计算一个时钟时针的位置。这里要做一个时间调整,而且要归一化为一个0 ~ 11之间的数。这很简单:(position + adjustment)%12。不过,如果这个调整为负会怎么样呢?你可能会得到一个负数。所以要引入一个分支,或者使用((position +adjustment)%12+12)%12。不管怎样都很麻烦。

floorMod方法就让这个问题变得容易了:floorMod(position+adjustment,12)总会得到一个0 ~ 11之间的数。(遗憾的是,对于负除数,floorMod会得到负数结果,不过这种情况在实际中很少出现。)

Math类

Math类提供了一些常用的三角函数:

  • Math.sin
  • Math.cos
  • Math.tan
  • Math.atan
  • Math.atan2

还有指数函数以及它的反函数——自然对数以及以10为底的对数:

  • Math.exp
  • Math.log
  • Math.log10

最后,Java还提供了两个用于表示π和e常量的最接近的近似值:

  • Math.PI
  • Math.E

提示

不必在数学方法名和常量名前添加前缀“Math”,只要在源文件的顶部加上下面这行代码就可以了。

import static java.lang.Math.*;

例如:

System.out.println("The square root of\u03c0 is"+sqrt(PI));

程序示例

import static java.lang.Math.*;

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   System.out.println("平方根\u03c0为:"+sqrt(PI));  
   }
}

运行结果

平方根π为:1.7724538509055159

注释

在Math类中,为了达到最佳的性能,所有的方法都使用计算机浮点单元中的例程。如果得到一个完全可预测的结果比运行速度更重要的话,那么就应该使用StrictMath类。它实现了“可自由分发的数学库(Freely Distributable Math Library,FDLIBM)”的算法(www.netlib.org/fdlibm),确保在所有平台上得到相同的结果。

注释

Math类提供了一些方法使整数有更好的运算安全性。如果一个计算溢出,数学运算符只是悄悄地返回错误的结果而不做任何提醒。例如,10亿乘以3(1000000000*3)的计算结果将是-1294967296,因为最大的int值也只是刚刚超过20亿。不过,如果调用Math.multiplyExact(1000000000,3),就会生成一个异常。你可以捕获这个异常或者让程序终止,而不是允许它给出一个错误的结果然后悄无声息地继续运行。另外还有一些方法(addExact、subtractExact、incrementExact、decrementExact和negateExact)也可以正确地处理int和long参数。

数值类型之间的转换

数值类型之间的合法转换

我们经常需要将一种数值类型转换为另一种数值类型。图(数值类型之间的合法转换)给出了数值类型之间的合法转换。

image

在图(数值类型之间的合法转换)中有6个实线箭头,表示无信息丢失的转换;另外有3个虚线箭头,表示可能有精度损失的转换。例如,123456789是一个大整数,它所包含的位数比float类型所能够表示的位数多。当将这个整数转换为float类型时,将会得到正确的大小,但是会损失一些精度。

int n=123456789;
float f=n;   //f is 1.23456792E8

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_n=123456789;
	   float huangzihan_f=huangzihan_n;   //f is 1.23456792E8
	   System.out.println(huangzihan_f);  
   }
}

运行结果

1.23456792E8

二元运算符连接两个值

当用一个二元运算符连接两个值时(例如n+f,n是整数,f是浮点数),先要将两个操作数转换为同一种类型,然后再进行计算。

  • 如果两个操作数中有一个是double类型,另一个操作数就会转换为double类型。
  • 否则,如果其中一个操作数是float类型,另一个操作数将会转换为float类型。
  • 否则,如果其中一个操作数是long类型,另一个操作数将会转换为long类型。
  • 否则,两个操作数都将被转换为int类型。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_i=123;
	   float huangzihan_f=12;   
	   double huangzihan_d=12.34;
	   long huangzihan_l=1234;
	   System.out.println(huangzihan_i+huangzihan_d);  
	   System.out.println(huangzihan_i+huangzihan_f);
	   System.out.println(huangzihan_i+huangzihan_l);
	   System.out.println(huangzihan_i+huangzihan_i);
   }
}

运行结果

135.34
135.0
1357
246

强制类型转换

强制类型转换的例子

int类型的值将会自动地转换为double类型。但另一方面,有时也需要将double转换成int。在Java中,允许进行这种数值之间的类型转换,当然,有可能会丢失一些信息。这种可能损失信息的转换要通过强制类型转换(cast)来完成。强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。例如:

double x=9.997;
int nx=(int) x;

这样,变量nx的值为9,因为强制类型转换通过截断小数部分将浮点值转换为整型。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   double huangzihan_x=9.997;
	   int huangzihan_y=(int) huangzihan_x;
	   System.out.println(huangzihan_y);  
   }
}

运行结果

9

浮点数舍入运算

如果想对浮点数进行舍入运算,以便得到最接近的整数(在很多情况下,这种操作更有用),那就需要使用Math.round方法:

double x=9.997;
int nx=(int) Math.round(x);

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   double huangzihan_z=9.997;
	   int huangzihan_x=(int) Math.round(huangzihan_z);
	   long huangzihan_y=Math.round(huangzihan_z);
	   System.out.println(huangzihan_x);  
	   System.out.println(huangzihan_y);
   }
}

运行结果

10

现在,变量nx的值为10。当调用round的时候,仍然需要使用强制类型转换(int)。其原因是round方法返回的结果为long类型,由于存在信息丢失的可能性,所以只有使用显式的强制类型转换才能够将long类型转换成int类型。

警告

如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不同的值。例如,(byte)300的实际值为44。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan=(byte)300;
	   System.out.println(huangzihan);  
   }
}

运行结果

44

结合赋值和运算符

可以在赋值中使用二元运算符,这是一种很方便的简写形式。例如,

x += 4;

等价于:

x = x + 4;

(一般来说,要把运算符放在=号左边,如*=或%=)。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_x=4;
	   huangzihan_x+=4;
	   System.out.println(huangzihan_x);  
	   
	   int huangzihan_y=4;
	   huangzihan_y=huangzihan_y+4;
	   System.out.println(huangzihan_y);
   }
}

运行结果

8
8

注释

如果运算符得到一个值,其类型与左侧操作数的类型不同,就会发生强制类型转换。例如,如果x是一个int,则以下语句

x += 3.5;

是合法的,将把x设置为(int)(x+3.5)。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_x=4;
	   huangzihan_x += 3.5;
	   System.out.println(huangzihan_x);  
	   
	   int huangzihan_y=4;
	   huangzihan_y += 3.5;
	   System.out.println(huangzihan_y);
   }
}

运行结果

7
7

自增与自减运算符

当然,程序员都知道加1、减1是数值变量最常见的操作。在Java中,借鉴了C和C++中的做法,也提供了自增、自减运算符:n++将变量n的当前值加1,n--则将n的值减1。例如,以下代码:

int n=12;
n++;

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_n=12;
	   huangzihan_n++;
	   System.out.println(huangzihan_n);  
   }
}

运行结果

13

将n的值改为13。由于这些运算符改变的是变量的值,所以它们不能应用于数值本身。例如,4++就不是一个合法的语句。

前后缀形式

实际上,这些运算符有两种形式;上面介绍的是运算符放在操作数后面的“后缀”形式。还有一种“前缀”形式:++n。后缀和前缀形式都会使变量值加1或减1。但用在表达式中时,二者就有区别了。前缀形式会先完成加1;而后缀形式会使用变量原来的值。

int m=7;
int n=7;
int a=2 * ++m;  //now a is 16,m is 8
int b=2 * n++;  //now b is 14,n is 8

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_m=7;
	   int huangzihan_n=7;
	   int huangzihan_a=2 * ++huangzihan_m;  //now huangzihan_a is 16,huangzihan_m is 8
	   int huangzihan_b=2 * huangzihan_n++;  //now huangzihan_b is 14,huangzihan_n is 8
	   System.out.println(huangzihan_a);  
	   System.out.println(huangzihan_b);
   }
}

运行结果

16
14

建议不要在表达式中使用++,因为这样的代码很容易让人困惑,而且会带来烦人的bug。

关系和boolean运算符

检测相等性

Java包含丰富的关系运算符。要检测相等性,可以使用两个等号==。例如,

3==7

的值为false。

另外可以使用!=检测不相等。例如,

3!=7

的值为true。

最后,还有经常使用的<(小于)、>(大于)、<=(小于等于)和>=(大于等于)运算符。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   System.out.println(3==7);  
	   System.out.println(3!=7);
   }
}

运行结果

false
true

&&运算符

Java沿用了C++的做法,使用&&表示逻辑“与”运算符,使用||表示逻辑“或”运算符。从!=运算符可以想到,感叹号!就是逻辑非运算符。&&和||运算符是按照“短路”方式来求值的:如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。如果用&&运算符合并两个表达式,

expression1 && expression2

而且已经计算得到第一个表达式的真值为false,那么结果就不可能为true。因此,第二个表达式就不必计算了。可以利用这一点来避免错误。例如,在下面的表达式中:

x != 0 && 1/x > x+y //no division by 0

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_x=1;
	   int huangzihan_y=2;
	   boolean huangzihan_z;
	   huangzihan_z=huangzihan_x != 0 && 1/huangzihan_x > huangzihan_x+huangzihan_y;  //no division by 0
	   System.out.println(huangzihan_z);
   }
}

运行结果

false

如果x等于0,那么第二部分就不会计算。因此,如果x为0,也就不会计算1/x,除以0的错误就不会出现。

类似地,如果第一个表达式为trueexpression1||expression2的值就自动为true,而无须计算第二个表达式。

三元操作符?:

最后一点,Java支持三元操作符?:,这个操作符有时很有用。如果条件为true,下面的表达式

condition?expression1:expression2

就为第一个表达式的值,否则计算为第二个表达式的值。例如,

image

会返回x和y中较小的一个。

程序示例

image

运行结果

1

位运算符

掩码技术

处理整型类型时,可以直接对组成整数的各个位完成操作。这意味着可以使用掩码技术得到整数中的各个位。位运算符包括:

image

这些运算符按位模式处理。例如,如果n是一个整数变量,而且用二进制表示的n从右边数第4位为1,则

int fourthBitFromRight=(n&0b1000)/0b1000;

会返回1,否则返回0。利用&并结合使用适当的2的幂,可以把其他位掩掉,而只留下其中的某一位。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_n=1;
	   System.out.println(huangzihan_n&0b1000);
	   int fourthBitFromRight=(huangzihan_n&0b1000)/0b1000;
	   System.out.println(fourthBitFromRight);
   }
}

运行结果

0
0

注释

应用在布尔值上时,&|运算符也会得到一个布尔值。这些运算符&&与和||运算符很类似,不过&|运算符不采用“短路”方式来求值,也就是说,得到计算结果之前两个操作数都需要计算。

左移右移运算符

另外,还有>><<运算符可以将位模式左移或右移。需要建立位模式来完成位掩码时,这两个运算符会很方便:

image

程序示例

image

运行结果
0
0

最后,>>>运算符会用0填充高位,这与>>不同,它会用符号位填充高位。不存在<<<运算符。

警告

image

程序示例

image

运行结果

8
8

括号与运算符级别

表(运算符优先级)给出了运算符的优先级。如果不使用圆括号,就按照给出的运算符优先级次序进行计算。同一个级别的运算符按照从左到右的次序进行计算(但右结合运算符除外,如表中所示)。例如,由于&&的优先级比||的优先级高,所以表达式

a && b || c

等价于

(a && b) || c

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   boolean huangzihan_a=true;
	   boolean huangzihan_b=false;
	   boolean huangzihan_c=true;
	   System.out.println(huangzihan_a && huangzihan_b || huangzihan_c);
	   
	   System.out.println();
	   
	   boolean huangzihan_d=true;
	   boolean huangzihan_e=false;
	   boolean huangzihan_f=true;
	   System.out.println((huangzihan_d && huangzihan_e) || huangzihan_f);
   }
}

运行结果

false
false

true
true

又因为+=是右结合运算符,所以表达式

a += b += c

等价于

a += (b += c)

也就是将b += c的结果(加上c之后的b)加到a上。

程序示例

public class HuangZiHanTest
{  
   public static void main(String[] args)
   {
	   int huangzihan_a=1;
	   int huangzihan_b=2;
	   int huangzihan_c=3;
	   System.out.println(huangzihan_a += huangzihan_b += huangzihan_c);
	   
	   System.out.println();
	   
	   int huangzihan_d=1;
	   int huangzihan_e=2;
	   int huangzihan_f=3;
	   System.out.println(huangzihan_d += (huangzihan_e += huangzihan_f));
   }
}

运行结果

6

6

运算符优先级

image



这篇关于运算符的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程