Java 中的基本数据类型主要包括以下7种:
- byte:字节型,占用 1 字节,范围-128 到 127。
- char:字符型,占用 2 字节,范围 0 到 65535。
- short:短整型,占用 2 字节,范围-32768 到 32767。
- int:整型,占用 4 字节,范围-2147483648 到 2147483647。
- long:长整型,占用 8 字节,范围-9223372036854775808 到 9223372036854775807。
- float:单精度浮点型,占用 4 字节,有效位可以达到 6-7 位。精确到小数点后 6~7 位。
- double:双精度浮点型,占用 8 字节,有效位可以达到 15 位。精确到小数点后 15~16 位。
这些类型在内存中的占用大小是固定的,但是它们可以存储的值的大小或者精度是不同的。例如,byte、short、int、long 类型可以存储整数,但是它们存储的最大值和最小值是不同的;float 和 double 可以存储浮点数,但是它们的精度(小数点后几位)是不同的。
按照精度从大到小排列Java中这些基本数据类型,主要针对的是这些类型所能表示的数值范围或精确度,我们按照数值范围和精确度来排序:
- double:双精度浮点型,精度最高,可以表示的数非常大或非常小,精确到小数点后15~16位。
- float:单精度浮点型,精度次之,可以表示的数范围较大,精确到小数点后6~7位。
- long:长整型,可以表示的整数范围很大,从-9223372036854775808到9223372036854775807。
- int:整型,可以表示的整数范围较大,从-2147483648到2147483647。
- short:短整型,表示的整数范围较小,从-32768到32767。
- byte:字节型,表示的整数范围最小,从-128到127。
- char:字符型,虽然它是用来表示Unicode字符的,不过由于它在底层是以一个无符号的16位整数存储,理论上可以视作从0到65535的范围,但是它主要用于表示字符而不是数值,所以在这个列表中的位置比较特殊。如果只从数值的角度考虑,则可以考虑它大致位于
short
和int
之间,但实际用途有所不同。
这里重点是基于能表示的数值范围和精确度进行排序。需要注意的是,精确度主要是指浮点数(float和double)的精确度,而对于整数类型(byte, short, int, long)则主要考虑的是它们能表示的数值范围。而char
主要用于表示字符,但在某些语境下也可能被用作数值处理。
Java 中的常用算术运算符包括以下几种:
-
加号
+
:用于两个数值的加法运算,或者用于字符串的连接操作。 -
减号
-
:用于两个数值的减法运算。 -
乘号
*
:用于两个数值的乘法运算。 -
除号
/
:用于两个数值的除法运算。如果两个操作数都是整数,则执行整数除法,结果为商的整数部分;如果至少有一个操作数为浮点数,则执行浮点除法。 -
取模
%
:俗称取余,用于两个数值的取模运算,结果为两数相除后的余数。 -
自增
++
:将变量的值增加 1,分为前缀形式(例如++i
,先进行自增运算,再返回运算后的值)与后缀形式(例如i++
,先返回当前值,然后再进行自增运算)。 -
自减
--
:将变量的值减少 1,也分为前缀形式(例如--i
)与后缀形式(例如i--
)。
请注意,使用这些运算符时可能需要考虑运算的类型转换和溢出等问题。例如,当两个整数相除时,如果你希望得到浮点数结果,至少需要有一个操作数进行显式或隐式的类型转换为浮点数。
++i
和 i++
,以及 --i
和 i--
都是 Java 中的自增和自减运算符,主要的区别在于它们在表达式中的值和它们对原变量的修改时间不同。
-
++i(前缀自增):首先,将 i 的值加 1,然后返回加 1 后的 i。这就意味着,如果我们在一个表达式中使用
++i
,那么在这个表达式中,i 的值都是自增后的值。 -
i++(后缀自增):首先,返回当前的 i,然后再将 i 的值加 1。这就意味着,如果我们在一个表达式中使用
i++
,那么在这个表达式中,i 的值都是自增前的值。
同样,
-
–i(前缀自减):首先,将 i 的值减 1,然后返回减 1 后的 i。这就意味着,如果我们在一个表达式中使用
--i
,那么在这个表达式中,i 的值都是自减后的值。 -
i–(后缀自减):首先,返回当前的 i,然后再将 i 的值减 1。这就意味着,如果我们在一个表达式中使用
i--
,那么在这个表达式中,i 的值都是自减前的值。
例如:
int i = 10;
System.out.println(++i); // 输出11, i的值现在是11
i = 10; // 重新赋值
System.out.println(i++); // 输出10,但是 i 的值现在是11
同样,对于自减运算符:
int i = 10;
System.out.println(--i); // 输出9,i的值现在是9
i = 10; // 重新赋值
System.out.println(i--); // 输出10,但是i的值现在是9
所以,选择使用哪种形式,前缀还是后缀,取决于你是希望在表达式中使用的是变量改变前的值,还是改变后的值。
取模运算,也叫做取余运算,是一种在数学和计算机科学中常见的运算。优先定义在整数集上,是一种求余数的操作。在Java中,取模运算符为 %
。
取模运算的基本公式为:
a % b = a − F l o o r ( a / b ) ∗ b a \% b = a - Floor(a / b) * b a%b=a−Floor(a/b)∗b
其中,Floor
表示向下取整,a
表示被除数,b
表示除数。
例如:
13 % 5 = 13 - Floor(13 / 5) * 5 = 13 - 2 * 5 = 3
。因此,13 除以 5 的余数是3。
在特定的数学和计算机科学应用中,取模运算有很多用途。例如,在哈希函数或者散列函数中,取模运算常用于将大的数值范围映射到小的数值范围(例:数组的索引)。同样,它也在循环队列和循环数组中发挥着重要的作用,可以简化在数组末尾和开头之间的过渡。
举例:
[root@master ~/java/javacode]# vim ArithmeticOperator.java
public class ArithmeticOperator{
public static void main(String[] args){
System.out.println(10 / 4);
double a = 10;
System.out.println(a / 4);
//默认按照最大精度进行计算
System.out.println(10.0 / 4);
//算术
//单独情况下i++ 与++i是一样的
int i = 10;
//i++; // ==> 11
//++i; // ==> 11
System.out.println(i);
//取模:a % b ==> a - a / b * b
System.out.println(10 % 3); // 1
System.out.println(10 % -3); // 1
System.out.println(-10 % 3); // -1
/*
作为表达式使用:
前++:先自增,后赋值
后++:先赋值,后自增
*/
int j = 10;
//int f = j++; //f=j;j=j+1 f=10 j=11
int f = ++j; //j=j+1;f=j f=11 j=11
System.out.println("f="+f+"\tj="+j);
}
}
在Java中,逻辑运算符用于连接两个或多个布尔表达式,其结果也是布尔值(true
或 false
)。以下是Java中的几种基本逻辑运算符及其规则:
-
&&
- 逻辑与(AND)运算符:- 如果两个操作数都为
true
,结果为true
。 - 如果任何一个操作数为
false
,结果为false
。 &&
是短路运算符,如果第一个操作数为false
,它将不会评估第二个操作数。
- 如果两个操作数都为
-
||
- 逻辑或(OR)运算符:- 如果两个操作数中任意一个为
true
,结果为true
。 - 如果两个操作数都为
false
,结果为false
。 ||
也是短路运算符,如果第一个操作数为true
,它将不会评估第二个操作数。
- 如果两个操作数中任意一个为
-
!
- 逻辑非(NOT)运算符:- 如果操作数为
true
,结果为false
。 - 如果操作数为
false
,结果为true
。
- 如果操作数为
以下是一些逻辑运算符的使用示例:
boolean a = true;
boolean b = false;
// 逻辑与
boolean resultAnd = a && b; // 结果为 false,因为 b 是 false
// 逻辑或
boolean resultOr = a || b; // 结果为 true,因为 a 是 true
// 逻辑非
boolean resultNot = !a; // 结果为 false,因为 a 的取反是 false
使用逻辑运算符时需要特别注意操作符的短路行为,这在编写条件语句时非常有用,可以避免不必要的计算,例如,避免在条件判断中调用一个可能导致异常的方法:
if (obj != null && obj.someMethod()) {
// 只有当 obj 不为 null 时才会调用 someMethod 方法.
}
在上面的代码中,如果 obj
为 null
,由于 &&
的短路特性,将不会调用 someMethod
方法。这样可以有效避免 NullPointerException
的发生。
好的,我将通过例子来详细说明逻辑与(&
)与短路与(&&
),以及逻辑或(|
)与短路或(||
)之间的区别。
逻辑与&
和短路与&&
的比较
首先定义两个方法,这些方法会在被调用时打印一条信息,并返回布尔值:
public class LogicalDemo {
public static void main(String[] args) {
boolean result;
boolean a, b;
a = false;
b = true;
System.out.println("逻辑与 & 的操作:");
result = testA(a) & testB(b);
// 在这里,无论testA()的结果如何,testB()都将被执行
System.out.println("\n短路与 && 的操作:");
result = testA(a) && testB(b);
// 在这里,如果testA()返回false,testB()不会被执行
}
public static boolean testA(boolean a) {
System.out.println("testA 方法被调用,返回:" + a);
return a;
}
public static boolean testB(boolean b) {
System.out.println("testB 方法被调用,返回:" + b);
return b;
}
}
输出:
逻辑与 & 的操作:
testA 方法被调用,返回:false
testB 方法被调用,返回:true
短路与 && 的操作:
testA 方法被调用,返回:false
逻辑或|
和短路或||
的比较
类似地,我们可以使用同样的方法来展示逻辑或和短路或的区别:
a = true;
b = false;
System.out.println("逻辑或 | 的操作:");
result = testA(a) | testB(b);
// 在这里,无论testA()的结果如何,testB()都将被执行
System.out.println("\n短路或 || 的操作:");
result = testA(a) || testB(b);
// 在这里,如果testA()返回true,testB()不会被执行
输出:
逻辑或 | 的操作:
testA 方法被调用,返回:true
testB 方法被调用,返回:false
短路或 || 的操作:
testA 方法被调用,返回:true
在上面的示例中,可以看到:
- 当使用逻辑与
&
时,不论testA()
的结果如何,testB()
都会被执行。 - 当使用短路与
&&
时,由于testA()
返回false
,testB()
不会被执行,因为&&
操作符已经确定整个表达式的结果必定是false
。 - 当使用逻辑或
|
时,不论testA()
的结果如何,testB()
都会被执行。 - 当使用短路或
||
时,由于testA()
返回true
,testB()
不会被执行,因为||
操作符已经确定整个表达式的结果必定是true
。
从这些例子中可以明显看出短路行为对程序执行流程的影响。使用短路逻辑与&&
和短路逻辑或||
通常可以提高效率,特别是当第二个操作数的计算代价高昂或者具有潜在副作用时(比如修改状态或进行I/O操作)。
例子1:
public class RelationalOperator{
public static void main(String[] args){
// int a = 1;
// int b = 3;
// boolean f = b < 3;
// System.out.println(f);
//demo01:
boolean a = false;
boolean b = true;
boolean result , result2;
//logic
result = test1(a) && test2(b) ;
result2 = test1(a) & test2(b) ;
int a1 = 1;
int b1 = 10;
//短路与&&
if ( a1 < 1 && b1++ < 90){
System.out.println("ok");
}
System.out.println("a1="+a1+"\tb1="+b1);
//逻辑与&
if ( a1 < 1 & b1++ < 90){
System.out.println("ok");
}
System.out.println("a1="+a1+"\tb1="+b1);
}
//定义一个方法
public static boolean test1(boolean a){
System.out.println("返回test1==>:"+a);
return a;
}
public static boolean test2(boolean b){
System.out.println("返回test2==>:"+b);
return b;
}
}
运行结果:
[root@master ~/java/javacode]# javac RelationalOperator.java &&java RelationalOperator
返回test1==>:false
返回test1==>:false
返回test2==>:true
a1=1 b1=10
a1=1 b1=11
例子2:
[root@master ~/java/javacode]# vim RelationalOperator03.java
public class RelationalOperator03{
public static void main(String[] args){
int a = 100;
int b = 10;
//逻辑非(NOT)
System.out.println(!(a<10)); // T
System.out.println(!(a>10)); // F
//异或
System.out.println((a < 10)^(b <=10));
}
}
结果:
[root@master ~/java/javacode]# javac RelationalOperator03.java && java RelationalOperator03
true
false
true
例子3:
public class RelationalOperator03{
public static void main(String[] args){
int a = 100;
int b = 10;
if (++a==101 && ++b ==11){
a =120;
}
System.out.println("a="+a+"\tb="+b);
}
}
结果:
a=120 b=11
例子4:
public class RelationalOperator03{
public static void main(String[] args){
int a = 100;
int b = 10;
if (a++==101 & ++b ==11){
a =120;
}
System.out.println("a="+a+"\tb="+b);
}
}
结果:
a=101 b=11
例子5:
public class RelationalOperator03{
public static void main(String[] args){
int a = 100;
int b = 10;
if (a++==100 || ++b ==10){
a =120;
}
System.out.println("a="+a+"\tb="+b);
}
}
结果:
a=120 b=10
例子6:
public class RelationalOperator03{
public static void main(String[] args){
int a = 100;
int b = 10;
if (a++==100 | ++b ==10){
a =120;
}
System.out.println("a="+a+"\tb="+b);
}
}
结果:
a=120 b=11
例子7:
public class RelationalOperator03{
public static void main(String[] args){
boolean x =true;
boolean y = false;
short z = 46;
if ((y = true) && (z++==46)) z++;
if ((x = false) || (++z==49)) z++;
System.out.println("x="+x+"\ty="+y+"\tz="+z);
}
}
结果:
x=false y=true z=50
三元运算符
Java 中的三元运算符(ternary operator)是唯一的一个条件运算符,它包含三个操作数,可以用于代替简单的 if-else 语句,以实现代码简化。它的一般形式如下:
variable = Expression1 ? Expression2 : Expression3;
这里的工作原理解释如下:
Expression1
:这是一个布尔表达式,决定了接下来的计算路径,如果表达式为true
,将执行Expression2
,否则执行Expression3
。Expression2
:这是Expression1
为true
时被赋值给variable
的值。Expression3
:这是Expression1
为false
时被赋值给variable
的值。
使用三元运算符时需要特别注意以下几点:
-
表达式的类型必须是兼容的:
Expression2
和Expression3
应该返回兼容类型的值,或可自动转换为变量类型。否则,可能导致编译错误。 -
三元运算符可以嵌套:但为了阅读和维护的便利性,应尽量避免复杂的嵌套,因为它会使代码难以阅读。
-
三元运算符是右结合的:意味着嵌套的三元运算符会从右向左进行求值。
-
三元运算符无法替代所有的 if-else 逻辑:仅在条件下根据不同的真值选择不同的值时使用,不应用于复杂的程序逻辑或执行多条语句。
下面是一个简单的例子1:
int a = 5;
int b = 10;
int max = (a > b) ? a : b; // 如果a大于b,max值为a,否则为b
例子2:
public class TernaryOperator{
public static void main(String[] args){
int a = 10 , b = 99;
int result = a > b ? a++ : b--;//b--:先进行赋值:result=b ==> 99;在进行b--操作:b=b-1 ==> 98;
System.out.println("result="+result+"\ta="+a+"\tb="+b);
}
}
运行结果:
result=99 a=10 b=98
例子3:
public class TernaryOperator{
public static void main(String[] args){
int a = 10 , b = 99;
int result = a > b ? a++ : --b; //--b:先计算b=b-1 ==>98;在进行赋值:result=b ==> 98;
System.out.println("result="+result+"\ta="+a+"\tb="+b);
}
}
运行结果:
result=98 a=10 b=98
例子4:
public class TernaryOperator{
public static void main(String[] args){
int a = 10 , b = 99;
int result = a < b ? a++ : --b;
System.out.println("result="+result+"\ta="+a+"\tb="+b);
}
}
运行结果:
result=10 a=11 b=99
例子5:
public class TernaryOperator{
public static void main(String[] args){
int a = 10 , b = 99;
int result = a < b ? ++a : b--;
System.out.println("result="+result+"\ta="+a+"\tb="+b);
}
}
运行结果:
result=11 a=11 b=99
在使用时,不仅要考量代码的简洁性,还要保持代码的可读性和后期维护的方便性。
特性:三元运算符数据类型强转
例子:
public class TernaryOperator02{
public static void main(String[] args){
int a = 10 , b = 99;
double result = a < b ? 1.1 : b; //double result = a;
System.out.println("result="+result+"\ta="+a+"\tb="+b);
}
}
运行结果:
result=1.1 a=10 b=99
三元运算符作业
比较3个数,并返回最大值:
解题思路:
- n1 与 n2 做比较得出其中较大的值;
- n3 与 n2/n1中的较大值比较,返回较大值
public class TernaryOperatorExercise{
public static void main(String[] args){
int a = 10 , b = 123 , c = 321;
//1. n1 与 n2 做比较得出其中较大的值;
int result = a > b ? a : b ;
//2. n3 与 n2/n1中的较大值比较,返回较大值
int result2 = c > result ? c :result;
System.out.println("result="+result+"\nresult2="+result2);
}
}
运行结果:
result=123
result2=321
用一条语句解决:
public class TernaryOperatorExercise{
public static void main(String[] args){
int a = 10 , b = 123 , c = 321;
int result2 = c > (a > b ? a : b) ?
c :(a > b ? a : b);
System.out.println("result2="+result2);
}
}
运算优先符
在程序设计中,运算符优先级决定了表达式中各个运算符的运算顺序。了解和掌握每种运算符的优先级是非常重要的,因为它决定了如何对表达式进行求值。下面是一些常见编程语言(如C/C++、Java、Python等)中运算符的优先级列表,从**高到低排序
**(使用“R-->L
”表示从右向左
运算,使用“L->R
”表示从左向右
运算)
下面是更新后的表格:
优先级 | 类别 | 运算符 | 描述 | 运算方向 |
---|---|---|---|---|
1 | 括号 | () | 表达式内的括号优先计算 | L–>R |
2 | 成员访问 | . 、-> | 对象和指针成员访问 | L–>R |
3 | 单目运算符 | ! 、~ 、+ (正)、- (负)、++ (前置)、-- (前置)、* (解引用)、& (取地址) | 单个操作数的运算符 | R–>L |
4 | 类型转换 | 类型转换操作 | 如 (int) , (double) 等 | L–>R |
5 | 乘除模 | * 、/ 、% | 乘法、除法、取模运算 | L–>R |
6 | 加减法 | + 、- | 加法、减法 | L–>R |
7 | 位移运算 | << 、>> | 左右位移 | L–>R |
8 | 关系比较 | < 、> 、<= 、>= | 大小比较 | L–>R |
9 | 相等比较 | == 、!= | 等于、不等于比较 | L–>R |
10 | 位运算 | & 、^ 、` | ` | 按位与、异或、或 |
11 | 逻辑运算 | && 、` | ` | |
12 | 条件运算符 | ?: | 三元条件运算 | R->L |
13 | 赋值运算符 | = 、+= 、-= 、*= 、/= 、%= 、<<= 、>>= 、&= 、^= 、` | =` | 赋值及其复合形式 |
14 | 逗号 | , | 表达式分隔符 | L->R |
每个运算符的运算方向决定了如果有多个同级运算符出现在一个表达式中,它们是如何顺序执行的。