[Javaweb开发]3.Java运算符上-Day2

JAVA运算符

算数运算符

运算符和表达式

  • 运算符

    对字面量或者变量进行操作的符号

  • 表达式

    用运算符把字面量或者变量连接起来符合JAVA语法的式子就称为表达式

  • 举例说明
    int a = 10;
    int b = 20;
    int c = a + b;

    +: 是运算符,并且是算数运算符
    a + b:是表达式,由于+是算术运算符,所以这个表达式叫算数表达式

符号作用说明
+数学加法运算
-数学减法运算
*数学乘法运算
/数学除法运算数学除法运算
%取余获取的是两个数据做除法的余数

注意事项

/ 和 % 的区别:两个数做除法, / 取结果的商, % 取结果的余数
整数操作只能得到整数,要想得到小数,必须有浮点数参与运算

案例
需求: 键盘录入一个三位数,将其拆分为个位 十位 百位后,打印在控制台
代码如下:

import java.util.Scanner;
public class NoteDemo {
public static void main(String[] args){
  Scanner sc = new Scanner(System.in);
  System.out.println("请输入三个数字:例如123");
  int age = sc.nextInt();
  int a = age %10;
  int b = age /10%10;
  int c = age /10/10%10;
  System.out.println(a);//结果余数为3
  System.out.println(b);//结果余数为2
  System.out.println(c);//结果余数为1
}
}

分析

  1. 使用Scanner键盘录入一个三位数123
  2. 个位的计算通过数值 % 10

123除以10 (商12,余数为3)

  1. 十位的计算通过数值 / 10 % 10

123 除以 10(商12,余数为3,整数相除只能得到整数)
12 除以 10(商1,余数2)

  1. 百位计算通过数值 / 10 / 10 / %10

123 / 10 / 10 % 10(123 / 10 得到12,12 / 10 得到1,1 % 10得到1)

结果打印出来是个位为: 3 , 十位为: 2 , 百位为: 1

规律:
如果想继续拆分千位,万位,十万位,百万位等,代码如下:

import java.util.Scanner;
public class NoteDemo {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入七个数字:例如5969876");
        int age = sc.nextInt();
        int a = age %10;//余数为6
        int b = age /10%10;//余数为7
        int c = age /10/10%10;//余数为8
        int d = age /10/10/10%10;//余数为9
        int e = age /10/10/10/10%10;//余数为6
        int f = age /10/10/10/10/10%10;//余数为9
        int g = age /10/10/10/10/10/10%10;//余数为5
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
        System.out.println(e);
        System.out.println(f);
        System.out.println(g);
    }
}

优化代码:

import java.util.Scanner;
public class NoteDemo {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入七个数字");
int age = sc.nextInt();
int a = age %10;
int b = age /10%10;
int c = age /10/10%10;
int d = age /1000%10;
int e = age /10000%10;
int f = age /100000%10;
int g = age /1000000%10;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(e);
System.out.println(f);
System.out.println(g);
}
}

字符串拼接操作

当 + 操作中,遇到了字符串,这时 + 就是字符串连接符,而不是算术运算
代码如下:

public class NoteDemo {
public static void main(String[] args){
// + 字符只有遇到字符串才会进行字串连接操作,没有遇到字符串前他会进行算术运算
System.out.println(1+23);//24
//先遇到字符串时他会如贪吃蛇一样连接右边的字符成为自身
System.out.println("年龄为:" + 23);//年龄为:23
//由于代码运行是有顺序的,他先遇到1 + 99,还没有遇到后面的字符串前会先进行加法运算,再进行字符串连接
System.out.println(1 + 99 + "年帅哥");//100年帅哥
//先遇到字符串后会连接字符串,变成了字符串"年龄为23"后,继续连接后面的值成为自身
System.out.println("年龄为:" + 23+1);//年龄为:231
}
}

如果在连接字符串中需要算术运算时,可以通过()将要运算的数据括起来,代码如下:

>public class NoteDemo {
public static void main(String[] args){
//使用()提升算数优先级,会将括号数据先进行算术运算,得到结果24,再进行字符串连接操作
System.out.println("年龄为:" + (23+1));//年龄为:24   
}
}

通过字符串拼接操作将上面的拆分个位 十位 百位 的案例所打印的结果进行优化

import java.util.Scanner;
public class NoteDemo {
public static void main(String[] args){
  Scanner sc = new Scanner(System.in);
  System.out.println("请输入七个数字:例如5969876");
  System.out.println("请输入七个数字");
  int age = sc.nextInt();
  int a = age % 10;
  int b = age / 10 % 10;
  int c = age / 10 / 10 % 10;
  int d = age / 1000 % 10;
  int e = age / 10000 % 10;
  int f = age / 100000 % 10;
  int g = age / 1000000 % 10;
  System.out.println("整数:" + age + "的个位为:" + a);
  System.out.println("整数:" + age + "的十位为:" + b);
  System.out.println("整数:" + age + "的百位为:" + c);
  System.out.println("整数:" + age + "的千位为:" + d);
  System.out.println("整数:" + age + "的万位为:" + e);
  System.out.println("整数:" + age + "的十万位为:" + f);
  System.out.println("整数:" + age + "的百万位为:" + g);
}
}

自增自减运算符

符号作用说明
++自增变量自身的值加1
- -自减变量自身的值减1

如何使用

单独使用

一句代码中,只做 ++ 或者 - - , ++- - 无论是放在变量前面还是变量后面,结果都是一样的

实例:

public class NoteDemo {
   public static void main(String[] args) {
       int a = 10, b = 20;//定义一个变量a,将10赋值给它
       System.out.println("操作前a的值为:"+ a);//10
       System.out.println("操作前b的值为:"+ b);//20
       a++;//让变量a在原来的值10上,自身加1
       b--;
       System.out.println("操作后a的值为:"+ a);//结果为11
       System.out.println("操作后b的值为:"+ b);//结果为19

       System.out.println("======================");

       int  c = 10, d = 20;//定义一个变量a,将10赋值给它
       System.out.println("操作前c的值为:"+ c);//10
       System.out.println("操作前d的值为:"+ d);//20
       ++c;//让变量c在原来的值10上,自身加1
       --d;//让变量d在原来的值20上,自身加1
       System.out.println("操作后c的值为:"+ c);//结果为11
       System.out.println("操作后d的值为:"+ d);//结果为19
   }
}

结论:无论是**++或者- -**,放在变量的前面还是后面,在单独使用的情况下,结果都是一样的

参与操作运算

如果放在变量的后面,会先拿变量的值进行运算,再对变量的值进行+1或者-1

public class NoteDemo {
public static void main(String[] args) {
int a = 10;
System.out.println("a原来是:" +a);//结果为10
//变量a首先将其原来的值10,先赋值给变量b,此时b=10,变量a再自增1,此时a=11   
int b = a++;
System.out.println("b赋值后变成:" + b);//结果为10
System.out.println("a++后值变成:" +a);//结果为11
}
}

结论: ++ 或者 - - 参与运算操作时,放在变量的前面和后面,会有两种不同的结果

  • 放在后面,例如: int a=10; int b=a++; 参与运算操作这种情况下,变量a 首先将其原来的值,先赋值给 变量b , 此时 b 拿到值并存储后, 变量a 才会操作自身的值 自增1自减1
  • 放在前面,例如 int c=20; int d=++a; 参与运算操作这种情况下, 变量c 自身的值首先会先 自增1自减1 后,又将操作后的值赋值给 变量d ,此时变量a变量d 的值相同

尝试练习并分析结果:
案例一:

public class NoteDemo {
public static void main(String[] args) {
//首先x原来的值是10
int x = 10;
//变量y=x ++,++在后面,先操作变量x=10的值给变量y,此时y=10,变量x自增1后变成了x=11
int y = x++;
//z= ++y, ++在前面,变量y先操作自增1后,变成y=11,再将变量y的值赋值给变量z,变成z=11
int z = ++y;
System.out.println(x);//结果为11
System.out.println(y);//结果为11
System.out.println(z);//结果为11
}
}

案例二

   public static void main(String[] args) {
       int a = 8;
       //第一个(- -a)为先自减1再操作变成a=7;第二个(++a)先自增1变成a=8;第三个(a++),先操作a=8,再自增1;第四个(a*10),通过前三个的自增自减操作变量a=9,通过计算9*10=90,所以最后的结果为b=7+8+8+90
       int b = (--a) + (++a) + (a++) + (a*10);
       System.out.println(a);//9
       System.out.println(b);//结果为113
   }
}

注意事项:++ - - 只能操作变量,不能操作常量


类型转换

隐式类型转换

把一个取值范围小的数值或者变量,赋值给另一个取值范围大的变量
代码如下:

public class NoteDemo {
public static void main(String[] args) {
//变量a为int类型,4个字节大小   
int a = 10;
//变量b为double类型,8个字节大小
//int整数变量a=10赋值给double浮点数类型的变量b时,由于数据类型不同,结果变成了10.0,也就是说类型悄然发生了变化,这种变化并非人为对其进行手动转换的,而是内部自动进行转换的,所以这种就叫做隐式转换   
double b=a;
  System.out.println(b);//结果为10.0
}
}

简单记: 小的给大的,可以直接给,这就叫做隐式转换

取值范围从小到大

byte(1字节) -> short(2字节) -> int(4字节) -> long(8字节) -> float(4字节) -> double(8字节)

char(1个字节)

疑问:float占用内存4个字节,long占用内存8个字节,为什么long放在了float的后面?
解释:虽然float占用内存之后4个字节,但是float[取值范围]要比占用内存8个字节的long[取值范围]大
原因: 小数的二进制存储形式更加节省内存

运算过程中的隐式转换

取值范围小的数据和取值范围大的数据进行数据运算时,小的会先提升为大的之后,再进行转换

public class NoteDemo {
public static void main(String[] args) {
double a = 10.0;
int b=18;
//在java中,如果数据类型不统一是不能直接做运算的,取值范围小的数据类型,会将自己提升为大的数据类型,与其进行运算操作,同时数据类型也会进行转换
double c = a + b;
  System.out.println(c);
}

上面代码中,double类型的变量a与int类型的变量b进行运算操作时,变量b作为取值范围小的数据类型,会将自己提升为和double类型的变量a一样的数据类型后,再与之进行运算,也就变成了 double a = 10.0; 和 double b = 18.0;两个double数据类型进行加法运算,结果还是double数据类型的结果:28.0.

byte short char 这三种数据在运算的时候,都会提升为int,然后再进行运算

public class NoteDemo {
   public static void main(String[] args) {
   byte a = 10;
   byte b = 20;
   //两个内存占用1个字节的byte类型的数据在进行运算时,会将自己提升为内存占用4个字节的两个int后,再进行运算
   int c = a+b;
    System.out.println(c);
   }
}

强制转换

把一个取值范围大的数值或者变量,赋值给另一个取值范围小的变量

首先不可这样赋值,错误代码如下:

public class NoteDemo {
public static void main(String[] args) {
double a = 10.0;
//这里编辑器会报错,变量a取值范围大,不能直接赋值给取值范围小的变量b
int b = a; 
}
}

不允许直接复制,需要加入强制转换
格式:目标数据类型 变量名 = (目标数据类型) 被强转的数据

public class NoteDemo {
public static void main(String[] args) {
double a = 10.0;
//double类型的变量a,通过强制转换后,会
int b = (int)a; 
System.out.println(a);
System.out.println(b)
}
}

注意:通过上面的代码可以看出,强制转换有可能会出现精度损失的情况,并不是一定的

代码如下:

public class NoteDemo {
public static void main(String[] args) {
int a = 130;
byte b = (byte)a;
System.out.println(a);//130
System.out.println(b);//结果为 -126 为什么?
}
}

通过上面的代码,变量a =30 , 为 int类型,变量b为 byte类型,变量a通过强制转换成byte,赋值给变量b,大的给小的通过强制转换可以给,但是为什么变量a原来的值为30,结果在强转赋值给变量b后是**-126**呢?

知识拓展

通过二进制的知识来解释:
先了解什么是进制?

由于计算机中存储数据的单位为:字节,而每一个字节在计算机底层都是以二进制形式进行体现的
计算机中进制的分类和书写格式

进制说明前缀
十六进制用数字0到9和字母A到F(或a ~ f)表示,其中:a ~ f 表示10~15,这些称作十六进制 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [a] [b] [c] [d] [e] [f]0x
十进制由0,1,2,3,4,5,6,7,8,9进行表示,逢十进一,借一当十
八进制由0,1,2,3,4,5,6,7八个数表示,逢八 进一0
二进制二进制数据是用0和1两个数码来表示的,二进制规则是"逢二进一",借位规则是"借一当二"0b

二进制转换十进制方法一

公式:系数 * 基数的权次幂,然后相加

系数: 就是每一位上的数
基数: 当前的进制数
权 : 从右到左,一次为0 1 2 3 4 5 6 7 8 …
例如:

1 0 1
系数*基数的权次幂系数*基数的权次幂系数*基数的权次幂
1*2^20*2^11*2^0
4+0+1
-------------------------------------------------------------------------------------------------------------
结果为 5

二进制转十进制方法二
二进制中,每一位的1都是代表着一个固定的数值,把每一位的1代表的十进制数加起来得到的结果就是它所代表的十进制
8421转换法:

1286432168421

以二进制0b1101为例

1101
841

通过8421转换法,计算上面表格中得到的值8+4+1=13如下:

841
1+4+8结果为:13

也就是说二进制0b1101转换为十进制后结果为:13

二进制的原码 反码 补码
数据的二进制形式,每一个字节由8个二进制位组成

+二进制高位其余二进制位所表示二进制的数据
0000101010
10001010-10
----------------------------------------------------------------------------
10010100
10010100
通过下面的8 4 2 1快速转换(遇到二进制的0则不取)
1286432168421
转换后的结果为:
1(高位为1代表负数)1644+16= -20

高位:二进制数据中,最左侧的数据,通过高位代表的符号位

原码

原码
10001010

反码
正数的反码与其原码相同
负数的反码是以其原码逐位取反,但符号位除外

原码
10001010
反码
11110101

补码

什么是补码: 补码是通过反码推出来的
正数的补码与其原码相同
负数的补码是在其反码的末位加1

+原码
10001010
反码
11110101
补码是在其反码的末位加1进行运算如下:
1
补码
11110110
上面二进制的补码对应的十进制数据为 -10

**正确运算:**通过上面得到的-10(负数)的补码与10(正数)的补码(正数的原 反 补 相同)来进行下面正确运算操作

+下面是十进制负数 -10 的补码
11110110-10
下面是十进制正数 10 的补码
0000101010
----------------------------------------------------------------------------
100000000

通过上面的正确运算操作,就得到了(-10 + 10=0)的正确结果
由于一个字节是由8个二进制位组成的,所以第9个进的1被挤出去不要了

原 反 补总结:计算机在运算的时候,都是以二进制补码的形式在运算,也就是只有以补码的形式进行运算操作,得到的结果才是正确的

言归正传回到JAVA

**JAVA强转中的精度损失的问题**
public class NoteDemo {
public static void main(String[] args) {
int a = 130;
byte b = (byte)a;
System.out.println(a);//130
System.out.println(b);//结果为 -126 为什么?
}
}

第一步: 首先将上面代码中int变量a的值130的十进制数据转换成二进制,再得到其补码状态的二进制

由于变量a的数据类型为int类型,而int类型占用4个字节,1个字节由8个二进制位组成,那么也就是说130的完整二进制位为4组8个二进制位,不够的会做补零操作,如下:

>由于我们对int类型的变量a做了byte类型强制转换操作,然而,byte类型占用只用1个字节,一个字节由4个二进制位组成,也就是说,一个字节强制转为一个字节,会暴力砍掉后面所有的,只保留一个字节

这里需要注意,上面强转之前的高位是0 (0表示正数,1表示负数)

强转之后高位变成了1 (0表示正数,1表示负数)

int类型的十进制数据130完整的的二进制表示如下
00000000000000000000000010000010
int类型十进制130数据强转为byte类型后二进制表示如下
10000010

这里我们又发现一个问题,这组二进制数据"10000010"还是补码的状态,配合上面提到过的[8421转换法]得到如下结果如下:

11000010
通过下面的8 4 2 1快速转换(遇到二进制的0则不取)
1286432168421
转换后的结果为:
1(高位为1代表负数)2结果为: -2

上面表格中的结果,我们发现二进制10000010 通过[8421转换法]转换出来的结果不是130,而是 -2 (高位为1所以是负数)

第二步:尝试通过补码反向推出原码

原码需要通过将补码状态的二进制 10000010 取反得到反码(负数的反码是以其原码逐位取反,但符号位除外),再反码的末位加1求得原码

+补码
10000010
反码
11111101
求原码需要在反码末位加1进行运算如下:
1
原码
11111110
下面再通过[8421转换法](遇到二进制的0则不取) 求出该原码的十进制数据
1286432168421
转换后的结果为:
1(高位为1代表负数)643216842
2+4+8+16+32+64=结果为:-126

通过上面的[知识拓展]部分的阐述,至此,代码:

public class NoteDemo {
public static void main(String[] args) {
int a = 130;
byte b = (byte)a;
System.out.println(a);//130
System.out.println(b);//结果为 -126 为什么?
}
}

中为什么int类型变量a=130;强制转换为byte=(byte)a;输出结果为什么是-126而不是原来存储的130,其计算机内部转换的过程就大概了解清楚了
类型转换面试题测试

1.下面代码是否存在错误,如果有,请指出说明,并改正错误;

public class NoteDemo{
   public static void main(String[] args){
    	byte a =3;
        byte b = 4;
        byte c= a + b;
   }
}

错误的原因:

1.变量a和变量b两个数据类型都为byte,然而我们知道,byte short char三种数据类型在进行运算操作的时候都会将自己提升为int类型进行数据运算操作,byte类型的变量a和变量b,在提升为int之后,所运算的结果还是int类型.因此,将提升为int类型的变量a与变量b所相加的结果赋值给byte类型的变量c,属于大的给小的赋值,不能直接给

解决错误:

public class NoteDemo{
    public static void main(String[] args){
    	byte a = 3;
        byte b = 4;
        int c = a + b;//变量a,b提升为int类型运算后给int类型的变量c可以直接给
        Stytem.out.println(c);//运行结果为7
    }
}

↑由上面的面试题引出拓展知识:↑
先看代码:

public class NoteDemo{
public static void main(String[] args{
  byte a = 3 + 4;//思考这样的定义变量为什么不会报错?
  System.out.println(a);
}
}

按照目前所了解的知识:

上面的3和4是两个字面量,之前了解过,所有整数都默认是int类型,所以这里按理来说应该是两个int数据类型在做运算.运算后的结果还是int类型,.如果int类型的结果给byte类型的变量赋值,属于大的给小的赋值,是不能直接给的,会出现编译错误的
然而,思考一下为什么上面这样的定义变量为什么不会报错,而且会正常输出结果为7?

解答
Java是存在常量优化机制的,在编译的时候(也就是在执行javac过程)就会将3和4两个字面量进行运算操作.所产生的字节码文件(也就是.class文件)中的代码会直接编译为:

public class NoteDemo{
public static void main(String[] args){
	byte a = 7;
System.out.println(a)//运行结果为7
}
}

这里需要注意:如果上面的字面量运算操作的结果超出byte类型的取值范围时,是会直接报错的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值