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 |
每个运算符的运算方向决定了如果有多个同级运算符出现在一个表达式中,它们是如何顺序执行的。
命名规则
在Java编程语言中,标识符(Identifier)是用于标识变量、函数、类等实体的名称。命名规则和规范如下:
-
合法字符
- 标识符只能包含字母(A-Z, a-z)、数字(0-9)、下划线(_)和美元符号($)。
- 标识符不能以数字开头。
-
区分大小写
- Java是区分大小写的语言,因此
MyVariable
和myvariable
是两个不同的标识符。
- Java是区分大小写的语言,因此
-
长度限制
- 标识符的长度不受限制,但过长的标识符会影响代码的可读性。
-
关键字和保留字
- 标识符不能使用Java的关键字(如
class
,public
,void
, 等)和保留字。 关键字
:
保留字
:
- 标识符不能使用Java的关键字(如
命名规范
虽然命名规则规定了标识符的合法性,但为了保持代码的可读性和一致性,通常还会遵循一些命名规范:
-
类名
- 使用大写开头的驼峰命名法(Pascal Case)。
- 示例:
MyClass
,EmployeeDetails
-
变量名和方法名
- 使用小写开头的驼峰命名法(Camel Case)。
- 示例:
myVariable
,calculateSalary
-
常量
- 使用全大写字母和下划线分隔词。
- 示例:
MAX_VALUE
,PI
-
包名
- 规范是使用全小写字母,并且层级由点号分隔。
- 通常以公司域名的反转形式开始。
- 示例:
com.example.myapp
-
接口名
- 通常也使用大写开头的驼峰命名法,并且可以使用形容词形式。
- 示例:
Runnable
,Iterable
public class Employee {
private String name;
private int age;
private static final int MAX_AGE = 65;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age <= MAX_AGE) {
this.age = age;
}
}
public static void main(String[] args) {
Employee emp = new Employee("John", 30);
System.out.println("Name: " + emp.getName());
System.out.println("Age: " + emp.getAge());
}
}
在这个示例中:
Employee
是一个类名,使用大写开头的驼峰命名法。name
,age
是变量名,使用小写开头的驼峰命名法。MAX_AGE
是常量,使用全大写字母和下划线。- 方法名如
getName
,setName
,main
使用小写开头的驼峰命名法。
扫描器
示例:
//导入Scanner类,属于util包里面
import java.util.Scanner;
public class myScanner {
public static void main(String[] args) {
//新建一个Scanner对象myScannner
Scanner myScanner = new Scanner(System.in);
System.out.println("################输入人员信息###############");
System.out.println("输入姓名:");
String name = myScanner.next();
System.out.println("姓名:" + name);
System.out.println("输入年龄:");
int age = myScanner.nextInt();
System.out.println("年龄:" + age);
System.out.println("输入薪资:");
double sty = myScanner.nextDouble();
System.out.println("薪资:" + sty);
//System.out.println("姓名:" + name +"\t年龄:"+ age +"\t薪资:"+ sty );
System.out.printf("姓名:%s\t年龄:%d\t薪资:%.2f",name,age,sty);
}
}
运行结果:
################输入人员信息###############
输入姓名:
liha
姓名:liha
输入年龄:
21
年龄:21
输入薪资:
10000.1
薪资:10000.1
姓名:liha 年龄:21 薪资:10000.1
进制介绍
以下是二进制
、八进制
、十进制
和十六进制
的对应表格:
十进制 (Decimal) | 二进制 (Binary) | 八进制 (Octal) | 十六进制 (Hexadecimal) |
---|---|---|---|
0 | 0000 | 0 | 0 |
1 | 0001 | 1 | 1 |
2 | 0010 | 2 | 2 |
3 | 0011 | 3 | 3 |
4 | 0100 | 4 | 4 |
5 | 0101 | 5 | 5 |
6 | 0110 | 6 | 6 |
7 | 0111 | 7 | 7 |
8 | 1000 | 10 | 8 |
9 | 1001 | 11 | 9 |
10 | 1010 | 12 | A |
11 | 1011 | 13 | B |
12 | 1100 | 14 | C |
13 | 1101 | 15 | D |
14 | 1110 | 16 | E |
15 | 1111 | 17 | F |
16 | 10000 | 20 | 10 |
下面详细介绍一下进制之间的转换及相关技巧
:
一、十进制转换为其他进制
1. 十进制转换为二进制
-
方法:将十进制数不断
除以
2,取余数
,直到商为0
,然后将余数逆序排列
。 -
例子:把10转换为二进制
- 10 ÷ 2 = 5,余0
- 5 ÷ 2 = 2,余1
- 2 ÷ 2 = 1,余0
- 1 ÷ 2 = 0,余1
最终结果: 1 0 10 = 101 0 2 10_{10} = 1010_{2} 1010=10102
2. 十进制转换为八进制
-
方法:将十进制数不断
除以8
,取余数
,直到商为0
,然后将余数逆序排列
。 -
例子:把83转换为八进制
- 83 ÷ 8 = 10,余3
- 10 ÷ 8 = 1,余2
- 1 ÷ 8 = 0,余1
最终结果: 8 3 10 = 12 3 8 83_{10} = 123_{8} 8310=1238
3. 十进制转换为十六进制
- 方法:将十进制数
不断除以16
,取余数
,直到商为0
,然后将余数逆序排列
(注意用A、B、C、D、E、F表示10、11、12、13、14、15)。 - 例子:把254转换为十六进制
- 254 ÷ 16 = 15,余14(E)
- 15 ÷ 16 = 0,余15(F)
最终结果: 25 4 10 = F E 16 254_{10} = FE_{16} 25410=FE16
- 例子: 把983转换为十六进制
- 16 61 余 … 7
- 16 3 余… 13 (D)
最终结果: 98 3 10 = 3 D 7 16 983_{10} = 3D7_{16} 98310=3D716
二、其他进制转换为十进制
1. 二进制转换为十进制
- 方法:将二进制数每位上的数字
乘以2
的对应次幂
,然后求和。 - 例子:把1010转换为十进制
101 0 2 = 1 × 2 3 + 0 × 2 2 + 1 × 2 1 + 0 × 2 0 = 8 + 0 + 2 + 0 = 1 0 10 1010_{2} = 1 \times 2^3 + 0 \times 2^2 + 1 \times 2^1 + 0 \times 2^0 = 8 + 0 + 2 + 0 = 10_{10} 10102=1×23+0×22+1×21+0×20=8+0+2+0=1010
2. 八进制转换为十进制
- 方法:将八进制数每位上的数字
乘以
8的对应次幂
,然后求和。 - 例子:把123转换为十进制
12 3 8 = 1 × 8 2 + 2 × 8 1 + 3 × 8 0 = 64 + 16 + 3 = 8 3 10 123_{8} = 1 \times 8^2 + 2 \times 8^1 + 3 \times 8^0 = 64 + 16 + 3 = 83_{10} 1238=1×82+2×81+3×80=64+16+3=8310
3. 十六进制转换为十进制
- 方法:将十六进制每位上的数字
乘以16
的对应次幂
,然后求和(字母A-F对应十进制的10-15)。 - 例子:把FE转换为十进制
F E 16 = 15 × 1 6 1 + 14 × 1 6 0 = 240 + 14 = 25 4 10 FE_{16} = 15 \times 16^1 + 14 \times 16^0 = 240 + 14 = 254_{10} FE16=15×161+14×160=240+14=25410
三、其他进制之间的转换
1. 二进制转换为八进制
-
方法:将二进制数
每三位一组
(从右向左)分组,不足三位
的左边补零
,每组转换为对应的八进制数。 -
例子:把101010转换为八进制
- 分组:101 010
- 组转换: 10 1 2 = 5 8 101_2 = 5_8 1012=58, 01 0 2 = 2 8 010_2 = 2_8 0102=28
最终结果: 10101 0 2 = 5 2 8 101010_{2} = 52_{8} 1010102=528
2. 二进制转换为十六进制
-
方法:将二进制数每
四位一组
(从右向左)分组,不足四位
的左边补零
,每组转换为对应的十六进制数。 -
例子:把110101转换为十六进制
- 分组:0011 0101
- 组转换: 001 1 2 = 3 16 0011_2 = 3_{16} 00112=316, 010 1 2 = 5 16 0101_2 = 5_{16} 01012=516
最终结果: 11010 1 2 = 3 5 16 110101_{2} = 35_{16} 1101012=3516
3. 八进制转换为二进制
-
方法:将八进制数每个数字转换为
三位
二进制数。 -
例子:把52转换为二进制
- 5 8 = 10 1 2 5_8 = 101_2 58=1012
- 2 8 = 01 0 2 2_8 = 010_2 28=0102
最终结果: 5 2 8 = 10101 0 2 52_{8} = 101010_{2} 528=1010102
4. 十六进制转换为二进制
-
方法:将十六进制数每个数字转换为
四位
二进制数。 -
例子:把3E转换为二进制
- 3 16 = 001 1 2 3_{16} = 0011_2 316=00112
- E 16 = 111 0 2 E_{16} = 1110_2 E16=11102
最终结果: 3 E 16 = 0011111 0 2 3E_{16} = 00111110_{2} 3E16=001111102
原码、反码、补码
原码
原理:
- 源码是一种最基础的二进制编码方式,直接根据数值的正负进行表示。对于正数,源码就是其二进制表示;对于负数,源码在正数二进制表示的基础上将最高位设为1,来表示负号。
规则:
- 最高位为符号位:0表示正数,1表示负数
- 其余位为数值部分的二进制表示
反码
原理:
- 反码是在源码的基础上,将数值部分(除符号位以外)逐位取反,1变成0,0变成1。
规则:
- 对于正数,反码与源码相同。
- 对于负数,符号位保留,其余位逐位取反。
补码
原理:
- 补码是在反码的基础上加1,是计算机处理中负数的标准表示方式,因为补码运算可以简化加减运算。
规则:
- 对于正数,补码和源码相同。
- 对于负数,在反码的基础上加1。
位运算
下面采用一个例子更好的理解源码、反码和补码的原理。
实例说明 ~2
和 ~-2
的计算过程
假设使用 int
数据类型(在大多数编程语言中,int
通常占用32位)进行以下示例。
1. 计算 2
的源码、反码、补码
十进制数 2
在二进制下的表示为:00000000 00000000 00000000 00000010
-
源码(原码):
2
的源码为:00000000 00000000 00000000 00000010
-
反码:
- 对于正数,反码与源码相同:
00000000 00000000 00000000 00000010
- 对于正数,反码与源码相同:
-
补码:
- 对于正数,补码与源码相同:
00000000 00000000 00000000 00000010
- 对于正数,补码与源码相同:
2. 按位取反 ~2
的结果
按位取反 ~2
:
- 取反每一位:
11111111 11111111 11111111 11111101
3. 结果转换回十进制
由于最高位是1,表示这是一个负数:
- 先找到其补码对应的负数:
- 反码:
00000000 00000000 00000000 00000010
- 加 1:
00000000 00000000 00000000 00000011
- 对应十进制数为
3
- 反码:
- 因为符号位为1,表示负数,所以结果为
-3
结论:~2
按位取反后的十进制结果为 -3
4. 计算 -2
的源码、反码、补码
十进制数 -2
的计算过程:
-
源码:
-2
的源码为:10000000 00000000 00000000 00000010
-
反码:
- 除符号位外逐位取反:
11111111 11111111 11111111 11111101
- 除符号位外逐位取反:
-
补码:
- 在反码基础上加1:
11111111 11111111 11111111 111111#### 5. 按位取反
~-2` 的结果
- 在反码基础上加1:
-
取反每一位:
00000000 00000000 00000000 00000001
5. 结果转换回十进制
由于这是一个正数(最高位为0),直接转换:
- 二进制
00000000 00000000 00000000 00000001
对应十进制为1
结论:~-2
按位取反后的十进制结果为 1
综合总结
通过源码、反码和补码的原理和具体示例计算,得到以下结果:
2
的源码、反码和补码:00000000 00000000 00000000 00000010
~2
在转换为十进制后的结果为-3
-2
的源码:10000000 00000000 00000000 00000010
-2
的反码:11111111 11111111 11111111 11111101
-2
的补码:11111111 11111111 11111111 11111110
~-2
在转换为十进制后的结果为1