在最底层,Java中的数据是通过使用操作符来操作的。
1. 使用Java操作符
操作符作用于操作数,生成一个新值。另外,有些操作符可能会改变操作数自身的值,这被称为“副作用”。那些能改变操作数的操作符,最普遍的用途就是用来产生副作用;但要记住,使用此类操作符生成的值,与使用没有副作用的操作符生成的值,没有什么区别。
几乎所有的操作符都只能操作“基本类型”。例外的操作符是“=”、“==”和“!=”,这些操作符能操作所有的对象,除此之外String类支持“+”和“+=”。
1.1 优先级
当一个表达式中存在多个操作符时,操作符的优先级就决定了各部分的计算顺序。Java对计算顺序做了特别的规定。其中最简单的规则就是先乘除后加减。程序员经常会忘记其他优先级规则,所以应该用括号明确规定计算顺序。
public class Precedence {
public static void main(String[] args) {
int x = 1, y = 2, z = 3;
int a = x + y - 2/2 + z; // (1)
int b = x + (y - 2)/(2 + z); // (2)
System.out.println("a = " + a + " b = " + b);
}
}
/* Output:
a = 5 b = 1
*/
这两个语句看起来大体相同,但是从输出就可以看出他们具有迥然不同的含义,而这正是使用括号的结果。
请注意,System.out.println(“a = ” + a + ” b = ” + b); 该语句中包含“+”操作符。在这种上下文环境中,“+”意味着“字符串连接”,并且如果必要,它还要执行“字符串转换”。当编译器观察到一个String后面紧跟一个“+”,而这个“+”的后面又紧跟一个非String类型的元素时,就会尝试着将这个非String类型的元素转换为String。正如在输出中所看到的,它成功的将a和b从int转换为String。
2. 赋值
赋值操作符“=”。它的意思是“取右边的值(右值),把它复制给左边(即左值)”。右值可以是任何常数、变量或者表达式(只要它能生成一个值就行)。但左值必须是一个明确已命名的变量。
对基本数据类型的赋值是很简单的。基本类型存储了实际的数值,而并非指向一个对象引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方。例如:对基本数据类型使用a=b,那么b的内容就复制给a。若接着又修改了a,而b根本不会受这种修改的影响。
但是在为对象赋值的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是对象的引用。所以倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方复制到另一个地方。这意味着假若对对象使用c=d,那么c和d都指向原本只有d指向的那个对象。
练习: 创建一个包含一个float域的类,并用这个类来展示别名机制。
public class Tank {
float val;
public static void main(String[] args) {
Tank t1 = new Tank();
Tank t2 = new Tank();
t1.val = 4;
t2.val = 6;
System.out.println("1: t1.val: " + t1.val + " t2.val: " + t2.val);
t1 = t2;
System.out.println("2: t1.val: " + t1.val + " t2.val: " + t2.val);
t1.val = 8;
System.out.println("3: t1.val: " + t1.val + " t2.val: " + t2.val);
}
}
/**
* 1: t1.val: 4.0 t2.val: 6.0
* 2: t1.val: 6.0 t2.val: 6.0
* 3: t1.val: 8.0 t2.val: 8.0
*/
Tank类非常简单,它的两个实例(t1和t2)是在main中创建的。对每个Tank类对象的val域都赋予了一个不同的值,然后将t2赋给t1,接着又修改了t1。由于赋值操作的是一个对象的引用,所以修改t1的同时也改变了t2。这是由于t1和t2包含的是相同的引用,它们指向相同的对象。(原本t1包含的对对象的引用是指向一个值为4的对象。在对t1赋值的时候,这个引用被覆盖,也就是丢失了;而那个不再被引用的对象会由“垃圾回收器”自动清理)。这种特殊的现象通常称为“别名现象”,是Java操作对象的一种基本方式。所谓的“别名现象”也就是说有不止一个的引用指向同一个对象,当通过其中的一个引用使得该对象发生改变时,发现用另一个引用获取对象的属性时,也发生了改变。
2.1 方法调用中的别名问题
将一个对象传递给方法时,也会产生别名问题:
import static net.mindview.util.Print.*;
class Letter {
char c;
}
public class PassObject {
static void f(Letter y) {
y.c = 'z';
}
public static void main(String[] args) {
Letter x = new Letter();
x.c = 'a';
print("1: x.c: " + x.c);
f(x);
print("2: x.c: " + x.c);
}
} /* Output:
1: x.c: a
2: x.c: z
*/
3. 算术操作符
java中的基本算术操作符包括了+ 、 - 、 * 、 / 、% 。整数除法会直接去掉结果的小数位,而不是四舍五入。
Java也使用了一种简化符号进行运算与赋值操作。这用操作符后紧跟一个等号来表示,它对于Java中的所有操作符都适用,只要其有实际意义就行。例如,要将x加4,并将结果赋回给x,可以这样写:x+=4。
//show all math operators
public class MathOps {
public static void main(String[] args) {
// create a seeded random number generator
Random rand = new Random(13);
int i, j, k;
// choose value from 1 to 100
j = rand.nextInt(100) + 1;
System.out.println("j: " + j);
k = rand.nextInt(100) + 1;
System.out.println("k: " + k);
i = j + k;
System.out.println("j + k : " + i);
i = j - k;
System.out.println("j - k : " + i);
i = k / j;
System.out.println("k / j : " + i);
i = k * j;
System.out.println("k * j : " + i);
i = k % j;
System.out.println("k % j : " + i);
j %= k;
System.out.println("j %= k : " + j);
}
/**
* j: 7
* k: 69
* j + k : 76
* j - k : -62
* k / j : 9
* k * j : 483
* k % j : 6
* j %= k : 7
*/
}
要生成数字,程序首先会创建一个Random类的对象。如果在创建过程中没有传递任何参数,那么Java就会将当前时间作为随机数生成器的种子,并由此在程序每一次执行时都产生不同的输出。通过在创建Random对象时提供种子(用于随机数生成器的初始化值,随机数生成器对于特定的种子值总是产生相同的随机数序列),就可以在每一次执行程序时都产生相同的随机数。
通过Ramdom类的对象,程序可生成许多不同类型的随机数字。只需要调用方法nextInt()和nextFloat()即可。传递给nextInt()的参数设置了所产生随机数的上限,而其下限为0,但是这个下限并不是我们想要的,因为它会产生除0的可能性,因为我们对结果做了加一操作。
练习:编写一个计算速度的程序,它所使用的距离和时间都是常量。
public class CalculateSpeed {
public static void main(String[] args) {
Random rand_d = new Random(24);
Random rand_t = new Random(81);
float distance = rand_d.nextFloat();
float time = rand_t.nextFloat();
float speed = distance / time;
System.out.println("速度为:" + speed);
}
}
3.1 一元加、减操作符
一元减号(-)和一元加号(+)与二元减号和加号都使用相同的符号。其实就是一元就是表示正负号,二元就是运算符加减;根据表达式的书写形式,编译器会自动判断出使用的是哪一种。例如语句:x = -a;的含义是显然的。编译器能正确识别下述语句:x = a * -b;但读者会被搞糊涂,所以有时更明确地写成:x = a * (-b);一元减号用于转变数据的符号;而一元加号只是为了与一元减号相对应,但是它唯一的作用仅仅是将较小类型的操作数提升为int。
4. 自动递增和递减
递增和递减操作符不仅改变了变量,并且以变量的值作为结果。对于前缀递增和前缀递减(如++a或--
a),会先执行运算,再生成值。而对于后缀递增和后缀递减(如a++或a--
),会先生成值,再执行运算。
举例:
public class AutoInc {
public static void main(String[] args) {
int i = 1;
System.out.println("i: " + i);
System.out.println("++i: " + ++i); //pre-increment
System.out.println("i++: " + i++ ); //post-increment
System.out.println("i: " + i);
System.out.println("--i: " + --i); //pre-increment
System.out.println("i--: " + i--); //post-increment
System.out.println("i: " + i);
}
测试结果为:
/**
* i: 1
* ++i: 2
* i++: 2
* i: 3
* --i: 2
* i--: 2
* i: 1
*/
}
5. 关系操作符
关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系。如果关系是真实的,关系表达式会生成true;如果关系不真实,则生成false。关系操作符包括>、<、 >=、 <=、 ==、 != 等于和不等于适用所有的基本数据类型,而其他比较符不能用于Boolean类型。因为Boolean值只能为true或false,“大于”和“小于”没有实际意义。关系操作符==和!=也适用于所有对象。基本数据类型使用==和!=直接比较它们的值,而引用型数据类型使用==和!=时则比较的是引用的内存地址值。equals()不适用于“基本类型”,在没有覆盖equals()方法的类中使用equals()进行比较时依然比较的是内存地址值。
练习:创建一个名为Dog的类,它包含两个String域:name和says。在main()方法中,创建两个dog对象,一个名为spot(它的叫声为“Ruff !”),另一个名为scruffy(它的叫声为“Wurf!")。然后显示出它们的名字和叫声。
public class Dog {
private String name;
private String says;
public static void main(String[] args) {
Dog spot = new Dog();
Dog scruffy = new Dog();
spot.says = "Ruff! ";
scruffy.says = "Wurf! ";
System.out.println("spot: " + spot.name + " -- " + spot.says);
System.out.println("scruffy: " + scruffy.name + " -- " + scruffy.says);
}
}
/**
* spot: null -- Ruff!
* scruffy: null -- Wurf!
*/
练习:在上个练习的基础上,创建一个新的dog索引,并对其赋值为spot对象。测试用==和equals()方法来比较所有引用的结果。
public class Dog {
private String name;
private String says;
public static void main(String[] args) {
Dog spot = new Dog();
Dog scruffy = new Dog();
Dog new_d = new Dog();
new_d = spot;
spot.says = "Ruff! ";
scruffy.says = "Wurf! ";
System.out.println("spot: " + spot.name + " -- " + spot.says);
System.out.println("scruffy: " + scruffy.name + " -- " + scruffy.says);
System.out.println("new_d: " + new_d.name + " -- " + new_d.says);
System.out.println(spot == new_d);
System.out.println(spot.equals(new_d));
}
/**
* spot: null -- Ruff!
* scruffy: null -- Wurf!
* new_d: null -- Ruff!
* true
* true
*/
6. 逻辑操作符
逻辑操作符“与”(&&)、“或”(||)、“非”(!)能根据参数的逻辑关系,生成一个布尔值(true或false)。与、或、非操作只可应用于布尔值。注意,如果在应该使用String值的地方使用了Boolean,布尔值会自动转换成适当的文本形式。
短路现象:即一旦能明确无误的确定整个表达式的值,就不再计算表达式余下的部分了。因此,整个逻辑表达式靠后的部分有可能不会被运算。例如:表达式1 && 表达式2 && 表达式3 ,假如第一个表达式结果为true,第二个结果为false,由于这意味着整个结果为false,所以没必要计算余下的表达式。
7. 直接常量
一般来说,如果在程序里使用了“直接常量”,编译器可以准确地知道要生成什么样的类型,但有时候却是模棱两可的。如果发生这种情况,必须对编译器加以适当的“指导”,用与直接量相关的某些字符来额外增加一些信息。
举例:
public class Literals {
public static void main(String[] args) {
int i1 = 0x2f;
System.out.println("i1: " + Integer.toBinaryString(i1));
int i2 = 0x2F;
System.out.println("i2: " + Integer.toBinaryString(i2));
int i3 = 0177;
System.out.println("i3: " + Integer.toBinaryString(i3));
char c = 0xffff;
System.out.println("c: " + Integer.toBinaryString(c));
byte b = 0x7f;
System.out.println("b: " + Integer.toBinaryString(b));
short s = 0x7fff;
System.out.println("s: " + Integer.toBinaryString(s));
long n1 = 200L;
long n2 = 200l;
long n3 = 200;
System.out.println("n1:" + n1 + "|| n2: " + n2 + "|| n3: " + n3);
float f1 = 1F;
float f2 = 1f;
float f3 = 1;
System.out.println("f1:" + f1 + "|| f2: " + f2 + "|| f3: " + f3);
double d1 = 1d;
double d2 = 1D;
System.out.println("d1:" + d1 + "|| d2:" + d2);
}
/**
* i1: 101111
* i2: 101111
* i3: 1111111
* c: 1111111111111111
* b: 1111111
* s: 111111111111111
* n1:200|| n2: 200|| n3: 200
* f1:1.0|| f2: 1.0|| f3: 1.0
* d1:1.0|| d2:1.0
*/
}
直接常量后面的后缀字符标志了它的类型。若为大写(或小写)的L,代表long(但是使用小写字符l容易造成混淆,因为它看起来看像数字1)。大写(或小写)字符F,代表Float,大写(或小写)字符D,则代表double。
十六进制数适用于所有整数数据类型,以前缀0X(或0x),后面跟随0~9或小写(或大写)的a~f来表示。
八进制数由前缀0以及后续的0~7的数字来表示。
8. 三元操作符
三元操作符也称为条件操作符,它显得比较特别,因为它有三个操作数;但它确实属于操作符的一种,因为它最终也会生成一个值。表达式为:
boolean-exp ? value0 : value1
如果表达式的结果为true,就计算value0,而且这个计算结果也就是操作符最终产生的值。如果表达式的结果为false,就计算value1,同样,它的结果也就成了操作符最终产生的值。
当然也可以换用普通的if-else语句,但是三元操作符更加简洁。但假如你打算频繁使用它,还是要多做思量,因为它很容易产生可读性差的代码。
9. 字符串操作符+ 和 +=
这个操作符在Java中有一项特殊的用途:连接不同的字符串。字符串操作有一些很有趣的行为。如果表达式以一个字符串开头,那么后续所有操作数必须是字符串型(请记住,编译器会把双引号内的字符序列自动转成字符串)
举例:
public class StringOperator {
public static void main(String[] args) {
int x = 0, y = 1, z = 2;
String s = "x, y, z ";
System.out.println(s + x + y + z);
System.out.println(x + " " + s); //converts x to a String
s += "(summend) = ";
System.out.println(s + (x + y + z));
System.out.println("" + x); //shortand for Integer.toString();
}
/**
* x, y, z 012
* 0 x, y, z
* x, y, z (summend) = 3
* 0
*/
}
请注意第一个打印语句的输出是012而不是3,而3正是将这些整数求和之后应该得到的结果,之所以出现这种结果,是因为Java编译器会将x、y、z转换成它们的字符串形式,然后连接这些字符串,而不是先把它们加到一起。
请注意main()中的最后一个示例:有时会看到这种一个空的String后面跟 + 和一个基本类型变量,以此作为不调用更加麻烦的显式方法(在本例中应该是Interger.toString())而执行字符串转换的方式。
10. 类型转换操作符
在适当的时候,Java会将一种数据类型自动转换为另一种。例如,假设我们为某浮点变量赋以一个整数值,编译器会将int自动转换为float。类型转换运算允许我们显式地进行这种类型的转换,或者在不能自动进行类型转换的时候强制进行类型转换。
要想执行类型转换,需要将希望得到的数据类型置于圆括号内,放在要进行类型转换的值的左边。
示例:
public class Casting {
public static void main(String[] args) {
int i = 200;
long lng = (long)i; //"widening," so cast not really required
lng = i;
long lng2 = 200;
//this is narrowing conversion
i = (int)lng2; //cast required
}
}
正如所看到的,即可以对数值进行类型转换,亦可对变量进行类型转换。请注意,这里可能会引入“多余的”转型,例如,编译器在必要的时候会自动进行int值到long值的提升。但是你仍然可以做这样“多余的”事,以提醒自己需要留意,也可以使代码更清晰。在其他情况下,可能只有先进行类型转换,代码编译才能通过。
在Java中类型转换则是一种比较安全的操作。然而,如果要执行一种名为“窄化转换”的操作(也就是说,将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型),就有可能面临信息丢失的危险。此时,这么做,必须显式的进行类型转换。“扩展转换(widening conversion)”,则不必显式地进行类型转换,因为新类型肯定能容纳原来类型的信息,不会出现任何信息的丢失。
Java允许我们把任何基本数据类型转换成别的基本数据类型,但是Boolean除外,后者根本不允许进行任何类型的转换处理。“类”数据类型不允许进行类型转换。为了将一种类转换成另一种,必须采用特殊的方法(本书后面会说到,对象可以在其所属类型的类族之间进行类型转换,例如“橡树”可转型为“树”。)
总结:1. 基本类型(除布尔)可以相互转换 2. 引用类型不可以相互转换(类族之间可以)
10.1 截尾和舍入
在执行窄化转换时,必须注意截尾和舍入的问题。例如,如果将一个浮点数转换为整型值,Java会如何处理呢?例如,将29.7转换为int,结果是29还是30呢?
示例1:
public class CastingNumbers {
public static void main(String[] args) {
double above = 29.7,below = 29.4;
float fabove = 29.7f, fbelow = 29.4f;
System.out.println("(int)above: " + (int)above);
System.out.println("(int)below: " + (int)below);
System.out.println("(int)fabove: " + (int)fabove);
System.out.println("(int)fbelow: " + (int)fbelow);
}
/**
* (int)above: 29
* (int)below: 29
* (int)fabove: 29
* (int)fbelow: 29
*/
}
示例2:
public class RoundingNumbers {
public static void main(String[] args) {
double above = 29.7,below = 29.4;
float fabove = 29.7f, fbelow = 29.4f;
System.out.println("Math.round(above): " + Math.round(above));
System.out.println("Math.round(below): " + Math.round(below));
System.out.println("Math.round(fabove): " + Math.round(fabove));
System.out.println("Math.round(fbelow): " + Math.round(fbelow) );
}
/**
* Math.round(above): 30
* Math.round(below): 29
* Math.round(fabove): 30
* Math.round(fbelow): 29
*/
}
结论:将float和double转型为整数时,总是对该数字执行截尾。如果想要得到舍入的结果,就需要使用java.lang.,Math中的round()方法。
10.2 提升
如果对基本数据类型执行算术运算或按位运算,大家会发现,只要类型比int小(即char、byte或者short),那么在运算之前,这些值会自动转换为int。这样一来,最终生成的结果就是int类型。如果想把结果赋值给较小的类型,就必须使用类型转换(既然把结果赋给了较小的类型,就有可能出现信息的丢失)。通常,表达式中出现的最大的数据类型决定了表达式最终结果的数据类型。如果将一个float值与一个double值相乘,结果就是double;如果将一个int和一个long值相加,则结果为long。
结语:注意,能够对布尔值进行的运算非常有限。我们只能赋予它true或false,并测试它为真还是为假,而不能将布尔值相加,或对布尔值进行其他任何运算。
在char、byte和short中,我们可看到使用算术操作符中数据类型提升的效果。对这些类型的任何一个进行算术运算,都会获得一个int结果,必须将其显式地转换回原来的类型(窄化转换可能出现信息的丢失),以将值赋给原本的类型。但对于int值则不必进行类型转换,因为所有数据已经属于int类型。但要注意,如果对两个足够大的数值进行相乘操作,结果就会溢出。
11. 操作符小结
展示了哪些数据类型能进行哪些特定的运算。基本是同一个不断重复的程序,但是每次使用了不同的基本数据类型。
//: operators/AllOps.java
// Tests all the operators on all the primitive data types
// to show which ones are accepted by the Java compiler.
public class AllOps {
// To accept the results of a boolean test:
void f(boolean b) {}
void boolTest(boolean x, boolean y) {
// Arithmetic operators:
//! x = x * y;
//! x = x / y;
//! x = x % y;
//! x = x + y;
//! x = x - y;
//! x++;
//! x--;
//! x = +y;
//! x = -y;
// Relational and logical:
//! f(x > y);
//! f(x >= y);
//! f(x < y);
//! f(x <= y);
f(x == y);
f(x != y);
f(!y);
x = x && y;
x = x || y;
// Bitwise operators:
//! x = ~y;
x = x & y;
x = x | y;
x = x ^ y;
//! x = x << 1;
//! x = x >> 1;
//! x = x >>> 1;
// Compound assignment:
//! x += y;
//! x -= y;
//! x *= y;
//! x /= y;
//! x %= y;
//! x <<= 1;
//! x >>= 1;
//! x >>>= 1;
x &= y;
x ^= y;
x |= y;
// Casting:
//! char c = (char)x;
//! byte b = (byte)x;
//! short s = (short)x;
//! int i = (int)x;
//! long l = (long)x;
//! float f = (float)x;
//! double d = (double)x;
}
void charTest(char x, char y) {
// Arithmetic operators:
x = (char)(x * y);
x = (char)(x / y);
x = (char)(x % y);
x = (char)(x + y);
x = (char)(x - y);
x++;
x--;
x = (char)+y;
x = (char)-y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
x= (char)~y;
x = (char)(x & y);
x = (char)(x | y);
x = (char)(x ^ y);
x = (char)(x << 1);
x = (char)(x >> 1);
x = (char)(x >>> 1);
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
x <<= 1;
x >>= 1;
x >>>= 1;
x &= y;
x ^= y;
x |= y;
// Casting:
//! boolean bl = (boolean)x;
byte b = (byte)x;
short s = (short)x;
int i = (int)x;
long l = (long)x;
float f = (float)x;
double d = (double)x;
}
void byteTest(byte x, byte y) {
// Arithmetic operators:
x = (byte)(x* y);
x = (byte)(x / y);
x = (byte)(x % y);
x = (byte)(x + y);
x = (byte)(x - y);
x++;
x--;
x = (byte)+ y;
x = (byte)- y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
x = (byte)~y;
x = (byte)(x & y);
x = (byte)(x | y);
x = (byte)(x ^ y);
x = (byte)(x << 1);
x = (byte)(x >> 1);
x = (byte)(x >>> 1);
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
x <<= 1;
x >>= 1;
x >>>= 1;
x &= y;
x ^= y;
x |= y;
// Casting:
//! boolean bl = (boolean)x;
char c = (char)x;
short s = (short)x;
int i = (int)x;
long l = (long)x;
float f = (float)x;
double d = (double)x;
}
void shortTest(short x, short y) {
// Arithmetic operators:
x = (short)(x * y);
x = (short)(x / y);
x = (short)(x % y);
x = (short)(x + y);
x = (short)(x - y);
x++;
x--;
x = (short)+y;
x = (short)-y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
x = (short)~y;
x = (short)(x & y);
x = (short)(x | y);
x = (short)(x ^ y);
x = (short)(x << 1);
x = (short)(x >> 1);
x = (short)(x >>> 1);
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
x <<= 1;
x >>= 1;
x >>>= 1;
x &= y;
x ^= y;
x |= y;
// Casting:
//! boolean bl = (boolean)x;
char c = (char)x;
byte b = (byte)x;
int i = (int)x;
long l = (long)x;
float f = (float)x;
double d = (double)x;
}
void intTest(int x, int y) {
// Arithmetic operators:
x = x * y;
x = x / y;
x = x % y;
x = x + y;
x = x - y;
x++;
x--;
x = +y;
x = -y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
x = ~y;
x = x & y;
x = x | y;
x = x ^ y;
x = x << 1;
x = x >> 1;
x = x >>> 1;
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
x <<= 1;
x >>= 1;
x >>>= 1;
x &= y;
x ^= y;
x |= y;
// Casting:
//! boolean bl = (boolean)x;
char c = (char)x;
byte b = (byte)x;
short s = (short)x;
long l = (long)x;
float f = (float)x;
double d = (double)x;
}
void longTest(long x, long y) {
// Arithmetic operators:
x = x * y;
x = x / y;
x = x % y;
x = x + y;
x = x - y;
x++;
x--;
x = +y;
x = -y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
x = ~y;
x = x & y;
x = x | y;
x = x ^ y;
x = x << 1;
x = x >> 1;
x = x >>> 1;
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
x <<= 1;
x >>= 1;
x >>>= 1;
x &= y;
x ^= y;
x |= y;
// Casting:
//! boolean bl = (boolean)x;
char c = (char)x;
byte b = (byte)x;
short s = (short)x;
int i = (int)x;
float f = (float)x;
double d = (double)x;
}
void floatTest(float x, float y) {
// Arithmetic operators:
x = x * y;
x = x / y;
x = x % y;
x = x + y;
x = x - y;
x++;
x--;
x = +y;
x = -y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
//! x = ~y;
//! x = x & y;
//! x = x | y;
//! x = x ^ y;
//! x = x << 1;
//! x = x >> 1;
//! x = x >>> 1;
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
//! x <<= 1;
//! x >>= 1;
//! x >>>= 1;
//! x &= y;
//! x ^= y;
//! x |= y;
// Casting:
//! boolean bl = (boolean)x;
char c = (char)x;
byte b = (byte)x;
short s = (short)x;
int i = (int)x;
long l = (long)x;
double d = (double)x;
}
void doubleTest(double x, double y) {
// Arithmetic operators:
x = x * y;
x = x / y;
x = x % y;
x = x + y;
x = x - y;
x++;
x--;
x = +y;
x = -y;
// Relational and logical:
f(x > y);
f(x >= y);
f(x < y);
f(x <= y);
f(x == y);
f(x != y);
//! f(!x);
//! f(x && y);
//! f(x || y);
// Bitwise operators:
//! x = ~y;
//! x = x & y;
//! x = x | y;
//! x = x ^ y;
//! x = x << 1;
//! x = x >> 1;
//! x = x >>> 1;
// Compound assignment:
x += y;
x -= y;
x *= y;
x /= y;
x %= y;
//! x <<= 1;
//! x >>= 1;
//! x >>>= 1;
//! x &= y;
//! x ^= y;
//! x |= y;
// Casting:
//! boolean bl = (boolean)x;
char c = (char)x;
byte b = (byte)x;
short s = (short)x;
int i = (int)x;
long l = (long)x;
float f = (float)x;
}
} ///:~