JavaSE——基础知识(补:取模运算的本质)

一、基本数据类型的注意点

1.基本数据类型:

---- 数值型(下面按可表示数据的范围大小,范围大小 != 所占存储空间)
-------- byte、short、char -------- int、long ---------- float、double
-------- 1字节、2字节、2字节 ----- 4字节、8字节 ------ 4字节、8字节
---- 布尔型:
-------- boolean
-------- 在JVM中占4个字节

JavaSE——基础知识(补:取模运算的本质)

2.基本数据类型的 类型 问题的相关说明:

① 自动类型提升:表示数值范围小的————>表示数值范围大的 (表示数据的范围与某类型所占存储空间大小是两个概念)

  byte——>short——>int——>long——>float——>double
  ------------ char——>int——>long——>float——>double  
  byte、short、char之间任意类型之间包括自身同类型运算结果都会自动提升为int
  byte、short 与 char之间不存在自动类型提升

② byte、short、char三种类型之间互相或自身类型之间参与算数运算结果都自动类型提升为int

  byte a = 1;
  byte b = 2;
  short c = 12;
  
  //以下表达式均错误
  a = a + b;
  a = a + a;
  c = a + b;
  c = a + c;

  //正确代码
  int sum = a + b;
  int sum1 = a + c;

③ 复合赋值运算符的一个特点(自带类型转换,保证运算结果任然为当前类型)

byte a = 3;
a += 2; //等价于 a = (byte)(a + 2);类型依然是byte,避免自动类型提升为int

④ long和float类型变量的注意事项

//float类型,赋值时必须在数值加后缀f或F
//long类型,赋值时必须在数值加后缀l或L
//double类型是可以后缀d的

//若未加后缀而能成功复制往往是因为自动类型提升

float a = 3.14F //识别为float类型的3.14,正确
float a = 3.14 //不后缀f或F,系统识别为double类型所以编译报错
对整数而言
//对于byte、short、char类型赋值时只要数值没有超出自身存储区范围即可按识别为对应类型
byte a = 3; 
short b = 120;
char c = 124;
int = 24;

//一般情况下是int型
a = b + 12; //在算数运算过程中,认定12为int型
int a = 3;
long b = 12; //12被识别为int,但是会发生自动类型提升long
long c = 14L; //14被识别为long类型

从小范围类型——>大范围类型:自动类型提升
从大范围类型——>小范围类型:强制类型转换

注意:表述数据的范围大小 ≠ 该类型变量所占内存大小

表示数据的范围 小—>大 : byte —> short、char —> int —> long —> float —> double

3.三元运算符 与 if-else

三元运算符: 表达式 ?表达式1 : 表达式2 (表达式1 和表达式2要求是一致的)

这是一个运算符,必然要结合一点变量、常量、语句或其他等组成一个表达式,是表达式则,必然有返回值
所以,要保证这个表达式无论真假取值,最终表达式运算的结果能统一为一个数据类型
例:

//比大小
int a = 5, b = 6;

//正确实例
String str = a > b ? "a大" : "b大";

//错误使用
String str = a > b ? "a大" : b; //表达式最终结果类型无法统一

String str = null;
if (a > b) {
  str = "a大";
}
else {
  str = b; //自动装箱
}

能用三元运算符表示的逻辑,一定可以用if-else结构实现,反之不可
能用三元运算符实现的,且不会过于复杂的逻辑,则选择使用三元运算符实现,效率高,简便

4.取模(取余)% 的实现原理----(真正理解 % 是如何运算的)

  a % b == a - a / b * b;   //庐山真面目
  
  //如果对于浮点型则
  a % b == a - (int)a / b * b;

  //具体其他内容,可自行百度

5.数据存储原理、二进制(解释原反补码原理)解释补码存在的意义

程序员的基本功

1.解释底层存值原理,二进制方式存值

二进制中:0 + 0 = 0, 0 + 1 = 1, 1 + 1 = 10;

除开最高位的符号位,表示正负,其余位的原码的真值就是所对应的变量的值
正数:三码相同
负数:1.原码(最高位符号位为1,其余位按真值计算可得例如-5,5的二进制是101,负数符号用最高位符号位取1表示
             则原码就是 10000000 00000000 00000000 00000101 ,int类型变量在内存中4个字节,32位,存储
             方式即如所写的原码类似---底层实质存储的是补码)
     2.反码(符号位1不变,其余位取反,1->0 或 0->1,反码11111111 11111111 11111111 11111010)
     3.补码(反码 + 1, 11111111 11111111 11111111 11111011)


例:-5 的三个码值  
原码:10000000 00000000 00000000 00000101  
反码:11111111 11111111 11111111 11111010
补码:11111111 11111111 11111111 11111011

首先 5 的三个码值,正数三码相同,5 的二进制是 101
符号位为 0,剩下31位表示 5 的补码(正数就是原码) 
原码:00000000 00000000 00000000 00000101  
反码:00000000 00000000 00000000 00000101
补码:00000000 00000000 00000000 00000101

2.补码实现了加法与减法的统一

    //计算机中存储的数值都是补码
    //为什么?
    //对正数无影响,三码相同。 对负数为何会有取反 + 1,得到补码的操作

    (-5) + 5
    -5 补码:11111111 11111111 11111111 11111011
     5 补码:00000000 00000000 00000000 00000101 +
    ----------------------------------------------
       结果:00000000 00000000 00000000 00000000 (最高位相加后,没有位了,所以进位的1,溢出了,计算完成)

    //再思考一下 5 + (-5)的 反码 = ?
    -5 反码:11111111 11111111 11111111 11111010
     5 补码:00000000 00000000 00000000 00000101 +
    ----------------------------------------------
       结果:11111111 11111111 11111111 11111111
    //显然此时再加1,就成全0了,最高位的进位,因为没有接受空间会溢出
    //这里应该就有所体会了
所以在计算机中,负数的定义,就是找到和对应正数相加等于0的那个数的表示,即为对应的负数

最后再次声明一个点,原码除开最高位的符号位外,其余位的真值就是对应的数值,所以分析内存中的存储后,如果想要知道所对应的值,都应该先转回原码计算结果

应用补码存储数据实现了加减法的统一
    //最后提一个特殊数值
    //例如:在计算机中存储的补码为
      补码:10000000 00000000 00000000 00000000 (32位)
      相当于 -0,所以规定为 表示为可表示范围内的最小数 -2147483648 (-2^31)

具体可见链接博客 ( 关于 -128 ,+128,-0,+0,-1 的反码补码 )
https://blog.csdn.net/weixin_30770783/article/details/97568497?ops_request_misc={"request_id"%3A"163040672016780269869631"%2C"scm"%3A"20140713.130102334.pc_all."}&request_id=163040672016780269869631&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2

二、流程控制

1.if-else

//1.单分支
if (条件) {
  语句;
}

//2.双分支
if(条件){
  语句A;
}
else {
  语句B
}

//3.多分支
if(条件1){
  语句1;
}
else if (条件2) {
  语句2
}
...
else {
  语句n 
}

2.switch-case

switch(变量) { //变量类型: byte、short、int、char、还有enum;需要强调的是:long和String类型不可以
  case 常量表达式1: //表达式,必须是常量
    语句1;
    break; //break是可选项,如果不加break,则程序执行玩语句1后向下顺序执行----(穿透现象)
  case 常量表达式2:
    语句2;
    break;
  ...
  default://位置是任意的,当变量没能与所有的表达式结果匹配,则定位到此处执行
    语句;
}

3.while

//循环变量初始换
while (循环条件) {
  //循环体语句;
  //迭代循环变量;
}

4.do-while

//循环变量初始化
do {
  //循环体语句;
  //迭代循环变量;
} while (循环条件); //分号不能少

5.for

for(循环初始化; 循环条件; 每轮循环最后执行语句) {
  //循环体语句;
}

7.continue 和 break

//执行语句 continue; 则立即结束本次循环,直接进入下一次循环条件判断;
//执行语句 break; 则默认立即结束当前所在最近一层的switch()语句或循环语句,继续执行后续语句;

//continue 和 break都可指定标签
// 例: break 标签;
out:
for(int i = 0; i < 10; i ++ ) {
    for(int j = 0; j < 5; j ++ ) {
        if(j == 2) {
            break out; //遇到break直接跳出out:所指定的范围,直接跳出外层循环
        }
    }
}

//默认不加标签效果,等价标签使用在最近一层
for(int i = 0; i < 10; i ++ ) {
    out: //等价直接使用 break;
    for(int j = 0; j < 5; j ++ ) {
        if(j == 2) {
            break out;
        }
    }
}

//continue同上用法

三、数组(内存解析) 赋值机制

无需记忆一维数组二维数组,本质就是分析数组元素类型即可

//静态初始化
int[] arr = {1,2,3,4,5}; //二者均只能一步完成,不能先声明在赋值;
int[] arr = new int[]{1,2,3,4,5}; //

//动态初始化
int[] arr = new int[5];
int[] arr;
arr = new int[5];

JavaSE——基础知识(补:取模运算的本质)

//数组的元素是数组类型
int[][] arr = new int[5][4];

JavaSE——基础知识(补:取模运算的本质)

JavaSE——基础知识(补:取模运算的本质)

上一篇:【数据结构与算法】反转链表:非递归实现


下一篇:自动执行Python脚本