Java 第一章

1. Java语言特点

简单性 、解释性、面向对象、高性能、分布式处理、多线程、健壮性、动态、结构中立、 安全性

开源、跨平台(比较突出的特点)

2. JDK , JRE , JVM 分别是什么

  • JDK:Java Development Kit

    含义:Java开发工具包(java虚拟机第三版:JDK是用于支持Java程序开发的最小环境 )

  • JRE:Java runtime environment

    含义:Java运行环境(java虚拟机第三版:JRE是支持Java程序运行的标准环境 )

  • JVM:Java Virtual Machine

    含义:Java虚拟机

组成:

JDK:由 Java程序设计语言JVMJava类库 三部分组成 ;
JRE:由 Java类库API中的Java SE API子集JVM 两部分组成;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1U1rhDO6-1590233814084)(java photo\JDKJREJVM.png)]

3. Java语言是跨平台的吗? JVM是跨平台的吗?

什么是跨平台性?

通过Java语言编写的应用程序在不同的系统平台上都可以运行

  • Java语言是跨平台运行的
  • JVM并不具有跨平台性
不同平台需要安装对应版本的JVM才能运行(例如:windows系统有windows版的JVM,
linux系统有linux体统的JVM)所以说JVM是不能跨平台的。
Java语言通过不同系统上的JVM(相当于一个桥梁)对Java语言进行编译和运行,所以说
java是跨平台的,而JVM就是Java语言跨平台的关键。

4. 关键字

关键字:被Java语言赋予特定含义的单词,且组成关键字的字母全部小写

4.1 定义数据类型的关键字

● class
● float
● interface(定义接口)
● double
● byte
● char
● short
● boolean
● int
● void
● long

4.2 定义数据类型值的关键字

● true
● false
● null

4.3 定义流程控制的关键字

● if ● else
● switch ● case ● default

● while ● do ● for

● break ● continue ● return

4.4 定义访问权限修饰符的关键字

● public
● protected
● private

4.5 定义类,函数,变量修饰符的关键字

● abstract(抽象)
● final(不可变)
● static(静态的)
● synchronized(控制线程同步)

4.6 定义类与类之间关系的关键字

● extends(继承某个类)
● implements(实现多个接口)

4.7 定义建立实例及引用实例,判断实例的关键字

● new
● this(指向对象本身)
● super(调用父类)
● instanceof(双目运算符,测试一个对象是否为一个类的实例,语法:object(对象名) instanceof class(类名)

4.8 异常处理的关键字

● try ● catch ● finally
● throw(是语句抛出一个异常)
● throws(是方法可能抛出异常的声明)

4.9 包的关键字

● package(包,类所在的包)
● import(引入,引入类中需要的类)

4.10 其他修饰符关键字

● native(是在 java.lang.Object 源码中的一个hashCode方法,public native int hashCode();

● strictfp(FP-strict,规范Java中的浮点类型的计算让计算结果更加精确)

● transient(标识一个成员变量在序列化子系统中应被忽略,不会为这个变量 分配内存 来保存)

● volatile(Java提供的一种轻量级的同步机制)

● assent

5. 标识符

标识符:给类,接口,方法,变量等起名字时使用的字符序列,一个标识符可由几个单词连接而成,以表明它的意思。

命名规则:

  • 包名:全部小写,多个层次之间使用 圆点 隔开,不可以以 数字 为开头,如:cn.edu.ecut;

  • 类名:每一个单词 的 首字母 大写,其他字母 小写,如:RecordInfo;

  • 方法名、变量名:第一个单词 首字母 大写,其他单词 首字母 大写,如:getRecordName;

  • 常量名:每个单词 每个字母 大小,且 多个单词间要用 下划线 “_" 分隔;

6. 注释

注释:用于解释说明程序的文字。

各种注释格式:

- 单行注释: //注释文字
- 多行注释:/* 注释文字 */
- 文档注释:/** 注释文字 */

7. 常量

7.1 基本常量

  1. 整数常量:所有整数,如:10,99;
  2. 小数常量:所有小数,如:3.14,15.6;
  3. 字符常量:用 单引号 ’ ’ 括起来的内容(一般都是单个字符,否则就属于字符串类型了),如:‘a’,‘b’;
  4. 字符串常量:用 双引号 " " 括起来的内容,如:“张三”,“abc”;
  5. 布尔常量:true 和 false;
  6. 空常量:null

7.2 整数常量的4种表现形式

  • 二进制:由 0 和 1 组成,以 0b 开头;
  • 八进制:由 0,1,2,…,7 组成,以 0 开头;
  • 十进制:由 0,1,2,…,9 组成,整数默认是十进制的;
  • 十六进制:由 0,1,2,…,9,a,b,c,d,e,f(大小写均可),以 0x开头;

7.3 原码、反码、补码

在计算机内,有符号数有3种表示法:原码、反码和补码。

计算机中处理数据采用 补码形式。

7.3.1 原码

原码的最高位是符号位,“0”表示正,“1”表示负,其余位表示数值的大小。

7.3.2 反码

正数的表示与原、补码相同,

负数的补码符号位为1,数值位是将原码的数值按位取反,

就得到该数的反码表示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-awJ3xKIa-1590233814089)(java photo\反码.png)]

7.3.3 补码

正数的补码与原码相同;负数的反码是原码除符号位外按位取反。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O6sjXfqF-1590233814092)(java photo\补码.png)]

8. 使用变量注意事项

  • 作用域 :变量定义在哪一级大括号中,哪个大括号的范围就是这个变量的作用域。相同的作用域中不能定义两个同名变量。

  • 初始化值:没有初始化值不能直接使用。

  • 一行上建议只定义一个变量,可以定义多个,但是不建议。

  • 基本数据类型的变量 中存储的是数值本身,引用类型的变量 中存储的是 堆内存 中某个对象的 地址。
    基本数据类型的变量引用类型的变量 之间是不可以进行比较的,就算编译没问题,但比较结果都为 false。
    同数据类型之间可以进行比较的。
    注意:== 运算符对于基本类型的变量来说比较值,对于引用类型的变量来说比较地址。

9. 数据类型

数据类型分为两大部分:基本数据类型 和 引用数据类型 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2lHWrXo-1590233814096)(java photo\数据类型.png)]

9.1 基本数据类型

9.1.1 数值型
9.1.1.1 整数类型
	byte 类型的数值 占 8 Bit (二进制位),范围:-128 ~ 127short 类型的数值 占 16 Bit (二进制位),范围:-32768 ~ 32767int 类型的数值 占 32 Bit (二进制位),范围: -2147483648 ~ 2147483647long 类型的数值 占 64 Bit (二进制位),范围:-9223372036854775808 ~ 9223372036854775807

​ long 类型的数值之后加上 L 或 l(要养成习惯)

  • Java 语言中为 整数类型 提供了相应的包装类

    ​ byte <===> Byte

    ​ short <===> Short

    ​ int <===> Integer

    ​ long <===> Long

  • 在 java 语言中整数可以采用 二进制、八进制、十进制、十六进制 形式来书写 字面量(前缀)

    1. 二进制:0b 或 0B 【 从 Java 1.7 开始支持 】 如:0b00001011 (十进制:11)

    2. 八进制:0

    3. 十进制:没有前缀,默认就是

    4. 十六进制:0x 或 0X

      注意:

      byte a = (byte)0b10001011 ; // 默认将 0b10001011 当做 int 对待,必须进行强制类型转换。

  • 整数类型对应 包装类 都可以通过 MAX_VALUE 获取最大值,通过 MIN_VALUE 获取最小值

9.1.1.2 浮点类型
不论是 float 还是 double 都遵循 IEEE 754 标准:

	- float 类型的数值占 32 个二进制位;
	- double 类型的数值占 64 个二进制位;

在直接书写的浮点数末尾增加 F 或 f 后缀来表示 float 类型数值

注意:在 Java 源代码中直接书写的 浮点数 默认都是 double 类型

9.1.2 字符型
  • char 类型的数值 占 16 Bit (二进制位)

  • char 类型的取值 可以使用 ‘’ 引起来的 字符、Unicode 编码、转义字符,也可以是 符合 char 数据范围的 正整数。

  • char 类型的取值范围是 \u0000 ~ \uFFFF 之间 ( 对应的正整数范围是 0x0000 ~ 0xffff ),其中 \u0000 表示一个空白字符

9.1.3 布尔型
  • boolean 类型的数值占 1 Bit (二进制位) 【这是规范要求的】
  • Java 中 没有 零表示假、非零即真 这一说

9.2 引用数据类型

  • 引用数据类型分为: 数组、类、接口

  • 基本数据类型引用数据类型区别

    • 基本数据类型 的变量中 存储 的就是相应类型的 数值
    • 引用类型 的变量中 存储 的是一个 内存地址 (通过这个地址可以找到真正的数据);

★ 为什么八大基本数据类型放栈中 三大引用类型放堆中

原因:

八大基本数据类型的大小创建时候已经确立大小 ;

三大引用类型创建时候 无法确定大小;

9.3 类型转换

boolean (布尔类型) 不参与 类型转换!!!!

  • JAVA基本数据类型之间转换的两种方式:

    1. 自动(隐式)类型转换:从小类型到大类型,不需要强制转换符

      int a = 5;
      double b = a;
      

      此处将int类型变量a的值赋值给double类型变量b,因为是小类型转换成大类型,int类型变量a的值会自动转换成double类型并赋值给变量b。

      • 类型从小到大依次为:

      ​ byte short int long float double

      ​ (char)

      • 整数类型可以自动转化为浮点类型,可能会产生舍入误差;
    2. 关于byte、short、char赋值与运算的 强制转换 规则:

      a. 不参与运算,整数直接量可以直接赋值给 byte,short,char,不需要强转。

      b. byte,short,char型变量参与运算时,需要强转。

      byte b1 = 5;
      byte b2 = 2;
      byte b3 = (byte)(bi + b2)
      

      b1与b2不参与运算,整数直接量可以直接赋值给byte;参与运算后,b1+b2和的值默认为int类型,需要强制转换成byte类型再赋值给byte类型变量b3。

注意:

  • 强转有可能产生精度丢失。
  • 例如:double类型变量a的值为5.123,强制转换成int类型后数值为5,小数位舍弃,产生了精度丢失。
9.3.1 自动类型转换

█ 自动类型提升必须满足的条件:

  • 两种类型兼容
  • 目标类型大于源类型

█ 类型从小到大依次为:

​ byte short int long float double
------ (char)

如果类型从 大 转换为 小 ,编译会报错,“ 不兼容的类型:从 XX(大) 转换到 XX(小) 可能会有损失 ”

9.3.1.1 整数型 自动类型提升

【 近"大"者"大" 】

数字范围较小的类型的变量的值 与 数字范围较大的类型的变量值 混合运算时:

较小范围类型的值 会首先 提升为 较大范围类型 然后再参与运算

例子:

byte first = 100 ;

   short second = 2000 ;

   int third = 30000 ;

   long fourth = 400000L ; // long 类型的数值之后加上 L 或 l (要养成习惯)


   // first 变量的值 和 second 变量的值 在加法运算之前都自动提升为 int

   int result1 = first + second ; // 自动类型提升: 两种类型兼容、目标类型大于源类型

   System.out.println( result1 
                      
                      
                      
   // second 变量的值 自动提升为 int 后再执行加法操作

   int result2 = second + third ; // 自动类型提升

   System.out.println( result2 );
                     
                      

   // third 变量的值 首先自动提升为 long 类型后再与 fourth 的指执行加法运算

   long result3 = third + fourth ; // 自动类型提升

   System.out.println( result3 );
9.3.1.2 字符型 自动类型提升
  • 两个 char 类型的取值 是可以相加的,加完之后是个 正整数

  • byte 、short 、char 如果 混合运算 则会首先 提升为 int

  • boolean 类型取值 不会自动类型提升,也不参与类型转换

例子:

   char first = 'A' ; // 65
   char second = 'B' ; // 66


   // char result = first + second ; // 错误: 不兼容的类型: 从int转换到char可能会有损失

   int result1 = first + second ; // 自动类型提升

   System.out.println( result1 );


   short third = 97 ;

   int result2 = first + third ; // 自动类型提升

   System.out.println( result2 );


   boolean b = true ;

   boolean c = false ;

   // int d = b + c ; // 错误: 二元运算符 '+' 的操作数类型错误

   // byte x = b ; // 错误: 不兼容的类型: boolean无法转换为byte
9.3.1.3 short 和 char 的 自动类型提升
  • short 和 char 之间不能实现【自动类型转换】

  • short 和 char 都可以【自动类型提升】为 数字范围较大 的类型 ( int 、long 、float 、double )

   // short : 16bit 
   short first = 97 ;
   System.out.println( first );


   // char second = first ; // 【编译失败】错误: 不兼容的类型: 从short转换到char可能会有损失


   int second = first ; // 本来是 short 类型的 first 变量中存储的数值会自动提升为 int 类型后再赋值给 second 变量
   System.out.println( second );

 

   // char : 16bit
   char third = 'a' ;
   System.out.println( third );


   // short fourth = third ; // 【编译失败】错误: 不兼容的类型: 从short转换到char可能会有损失


   int fourth = third ; // 本来是 char 类型的 third 变量中存储的数值会自动提升为 int 类型后再赋值给 fourth 变量
   System.out.println( fourth );
9.3.1.4 float 和 double 的 自动类型提升
  • 在 Java 语言中,如果遇到 范围比 int 小的类型发生运算时,首先需要提升为 int 类型后再运算

  • 在 Java 语言中,两个 float 类型的变量相加后仍然是 float 类型 ( Java 8 和 Java 11 测试通过 )

  • 在 Java 语言中,一个 float 类型的数值 与 一个 double 类型的数值 发生运算时,float 数值首先提升为 double 类型后再运算,结果是double类型

例子:

   byte first = 100 ;
   byte second = 50 ;

   // byte third = first + second ; // 【编译失败】错误: 不兼容的类型: 从int转换到byte可能会有损失
   // 两个 byte 类型的 变量 相加时,会首先自动类型提升为 int 类型,再运算

   int third = first + second ; 
   System.out.println( third );


   short fourth = 100 ;
   short fifth = 200 ;

 // short sixth = fourth + fifth ; // 【编译失败】错误: 不兼容的类型: 从int转换到short可能会有损失
   // 两个 short 类型的 变量 相加时,会首先自动类型提升为 int 类型,再运算

   int sixth = fourth + fifth ; 
   System.out.println( sixth );


   float one = 3.14F ;
   float two = 3.14F ;

   float three = one + two ; // 注意: 这里至少在 Java 8 中测试是通过的
   System.out.println( three );


   double four = 3.1415926 ;

 
   // float five = one + four ; // 【编译失败】错误: 不兼容的类型: 从double转换到float可能会有损失

   double five = one + four ; 
   System.out.println( five );
9.3.2 强制类型转换
9.3.2.1 简单理解 强制类型转换
  • 强制类型转换的使用方法:

目标类型 变量名称 = (目标类型) 源变量名或数值 ;

  • 整数类型的强制类型转换会 舍弃高位、留下低位 [舍弃小数部分] (舍弃多少高位、留下多少低位,取决于源类型和目标类型)

注意:超出了 某数据类型 范围时就是显示 该数据类型类型 的最大值。而不是取后面32位。

例子:

int first = 100 ; // 0000_0000_0000_0000_0000_0000_0110_0100
   System.out.println( first );


   // byte second = first ; // 不兼容的类型: 从 int 转换到 byte 可能会有损失

      byte    second   =   (byte)    first ; // 0110_0100
      System.out.println( second );

 
      short third = (short) first ; // 0000_0000_0110_0100
      System.out.println( third );

 

   //      130 : 0000_0000_0000_0000_0000_0000_1000_0010 【32bit】

   // (byte)130 : 1000_0010 【8bit】

      byte fourth = (byte) 130 ;
      System.out.println( fourth );


// double 转变为 short:
   // 输出为 1234567.89(double为双精度类型,精度为16位有效数字)
        double second =1234567.89 ;


        short fourth = (short) second ;
        System.out.println( fourth );

        // 输出为 -10617 (double -----> short ,即 64bit 转换成 16bit)
        // 1234567.89(十进制) ----> 1001_0110_1011_0100_0011_1.111_0001_1110_1011_1000_0101_0001_11101(64bit二进制)
        // 转换时舍弃小数部分,整数部分从右往左数第16位是1,符号位是1则对应负数,所以确定转换后为负数
        // 根据整数强制类型转换舍弃高位、留下低位的原则,转换后即为 -10617
9.3.2.2 规范理解 强制类型转换

第 1 步:

【 1 】In the first step: (在第1步中:)
the floating-point number is converted either to a long , if T is long, or to an int, if T is byte, short, char, or int, as follows:
译:浮点数转换为long(如果T是long)或int(如果T是byte、short、char或int),如下所示:
【 1.1 】If the floating-point number is NaN ( Not a Number ), the result of the first step of the conversion is an int or long 0 .
译:如果浮点数是NaN(不是数字),则转换的第一步的结果是int或long 0
【 1.2 】Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V,rounding toward zero using IEEE 754 round-toward-zero mode (§4.2.3). Then there are two cases:
译:否则,如果浮点数不是无穷大,则将浮点数舍入为整数值V,使用IEEE 754 round-to-zero模式(《TheJavaLanguageSpecification-8th》 书的 第4.2.3节)舍入为零。然后有两种情况:
【 1.2.1 】If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V
译:如果T是long,这个整数值可以表示为long,那么第一步的结果是long值V
【 1.2.2 】Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.
译:否则,如果该整数值可以表示为int,则第一步的结果是int值V。
【 1.3 】Otherwise, one of the following two cases must be true:
译:否则,以下两种情况之一必须为真:
【 1.3.1 】The value must be too small ( a negative value of large magnitude or negative infinity ),and the result of the first step is the smallest representable value of type int or long.
译:该值必须太小(一个大数值或负无穷大的负值),第一步的结果是int或long类型的最小可表示值
【 1.3.2 】The value must be too large ( a positive value of large magnitude or positive infinity ),and the result of the first step is the largest representable value of type int or long.
译:该值必须太大(一个大数值或正无穷大的正值),并且第一步的结果是int或long类型的最大可表示值。

第2步:

【 2 】In the second step: (在第2步中:)
【 2.1 】 If T is int or long, the result of the conversion is the result of the first step.
译:如果T是int或long,则转换的结果是第一步的结果。
【 2.2 】 If T is byte, char, or short, the result of the conversion is the result of a narrowing conversion to type T of the result of the first step
译:如果T是byte、char或short,则转换的结果是将第一步的结果缩小为T类型的结果

结合例子理解:

public class NarrowingPrimitive {

    public static void main(String[] args) {

        // 【 1 】In the first step, (在第一步中)
        // the floating-point number is converted either to a long , if T is long, or to an int, if T is byte, short, char, or int, as follows:
        // 浮点数转换为long(如果T是long)或int(如果T是byte、short、char或int),如下所示:

        // 【 1.1 】If the floating-point number is NaN ( Not a Number ), the result of the first step of the conversion is an int or long 0 .
        //   如果浮点数是NaN(不是数字),则转换的第一步的结果是int或long 0
        
        double nan = Double.NaN ; // NaN 是 Double 类中声明的一个常量
        System.out.println( nan );
        System.out.println( "byte : " + (byte) nan + " , short : " + (short) nan + " , int : " + (int) nan + " , long : " + (long) nan );
        //                            byte : 0 , short : 0 , int : 0 , long : 0
        System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );

        // 【 1.2 】Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V, 
        //              rounding toward zero using IEEE 754 round-toward-zero mode (§4.2.3). Then there are two cases:
        //              否则,如果浮点数不是无穷大,则将浮点数舍入为整数值V,使用IEEE 754 round-to-zero模式(《TheJavaLanguageSpecification-8th》 书的 第4.2.3节)舍入为零。然后有两种情况:

        // 【 1.2.1 】If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V
        //                 如果T是long,这个整数值可以表示为long,那么第一步的结果是long值V
        
        double lv = 0xFFFFFFFFL + 0.625; // 假设 double 变量中存储的数值的整数部分恰好是 long 类型可以表示的整数
        System.out.println( lv );                           // 4.294967295625E9
        System.out.println( "long : " + (long) lv );  // long : 4294967295
        System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );

        // 【 1.2.2 】Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.
        //                 否则,如果该整数值可以表示为int,则第一步的结果是int值V。
        
        double iv = 0xFFFFFF + 0.625; // 假设 double 变量中存储的数值的整数部分恰好是 int 类型可以表示的整数
        System.out.println( iv );                        // 1.6777215625E7
        System.out.println( "int : " + (int) iv );   // int : 16777215
        System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );

        // 【 1.3 】Otherwise, one of the following two cases must be true:
        //              否则,以下两种情况之一必须为真:

        // 【 1.3.1 】The value must be too small ( a negative value of large magnitude or negative infinity ), 
        //                 and the result of the first step is the smallest representable value of type int or long.
        //                 该值必须太小(一个大数值或负无穷大的负值),第一步的结果是int或long类型的最小可表示值

        // double negative = Double.NEGATIVE_INFINITY ; // NEGATIVE_INFINITY 是 Double 类中定义的常量,表示负无穷大
        double negative = 0x8000_0000_0000_0000L - 10000.0 ; // 一定要让 long 类型的值 减去 double 类型的数值
        System.out.println( negative );                                                                      // -9.223372036854786E18
        System.out.println( "int : " + (int) negative + " , long : " + (long) negative );    // int : -2147483648 , long : -9223372036854775808
        // int min value : 0x8000_0000 ( 0b1000_0000_0000_0000_0000_0000_0000_0000 )
        // long min value : 0x8000_0000_0000_0000L

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

        // 【 1.3.2 】The value must be too large ( a positive value of large magnitude or positive infinity ), 
        //                 and the result of the first step is the largest representable value of type int or long.
        //                 该值必须太大(一个大数值或正无穷大的正值),并且第一步的结果是int或long类型的最大可表示值。

        // double positive = Double.POSITIVE_INFINITY ; // POSITIVE_INFINITY 是 Double 类中定义的常量,表示正无穷大
        double positive = 0x7FFF_FFFF_FFFF_FFFFL + 10000.0 ; // 一定要让 long 类型的值 加上 double 类型的数值 
        System.out.println( positive );                                                                     // 9.223372036854786E18
        System.out.println( "int : " + (int) positive + " , long : " + (long) positive );    // int : 2147483647 , long : 9223372036854775807
        // int max value : 0x7FFF_FFFF ( 0b0111_1111_1111_1111_1111_1111_1111_1111 )
        // long max value : 0x7FFF_FFFF_FFFF_FFFFL

        double x = 0xFFFF + 0.1415926 ;
        //【 2 】In the second step: (在第二步中:)
        //【 2.1 】 If T is int or long, the result of the conversion is the result of the first step.
        //              如果T是int或long,则转换的结果是第一步的结果。
        
        System.out.println( "int : " + (int) x + " , long : " + (long) x );                        // int : 65535 , long : 65535

        //【 2.2 】 If T is byte, char, or short, the result of the conversion is the result of a narrowing conversion to type T of the result of the first step
        //               如果T是byte、char或short,则转换的结果是将第一步的结果缩小为T类型的结果
        
        System.out.println( "byte : " + (byte) x + " , char : " + (char) x + " , short : " + (short) x ); //byte : -1 , char :  , short : -1-1

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

         // (byte) positive 表示从 long max value 中截取 低 8 位 : 1111_1111
         System.out.println( (byte)0b1111_1111 );   // -1
         // 将8位的 1111_1111 当做补码,可以获取到相应的反码为 1111_1110 ,遂后保持符号位不变、数值部分逐位取反得到原码 1000_0001
 
         // (short) positive 表示从 long max value 中截取 低 16 位 : 1111_1111_1111_1111
         System.out.println( (short)0b1111_1111_1111_1111 );  // -1
         // 将16位的 1111_1111_1111_1111 当做补码,可以获取到相应的反码为 1111_1111_1111_1110 ,遂后保持符号位不变、数值部分逐位取反得到原码 1000_0000_0000_0001 

    }

}

10. 运算符

10.1 算术运算符

  • ’ + ’ 加法
  • ’ - ’ 减法

  • ’ * ’ 乘法

  • ’ / ’ 除法

  • ’ % ’ 取模 ( 整除取余数 ) 【 注意 整数 和 浮点数 都可以实现 模运算】

  • ’ ++ ’ 自增 【 注意 i++ 与 ++i 的区别 】 ( x = 100 ) --------> 其实就是 自增 和 其他操作 的先后顺序的问题

    • System.out.println( x++ ); // 输出100 ,x 已经是101 【先输出原来的值、再执行自增操作】
    • System.out.println( ++x ); // 输出101 ,x 已经是101【先执行自增操作、再执行输出操作】

    总结: + 在前,先自增; + 在后,后自增

  • ’ – ’ 自减 【 注意 i-- 与 --i 的区别 】

    同理

几个特殊例子:

例1(整除,除尽,除0,除无穷):

        System.out.print( "5 / 2 = " ) ;
        System.out.println( 5 / 2 ); // 整除

        System.out.print( "5 / 2.0 = " ) ; 
        System.out.println( 5 / 2.0 ); // 除尽 ( 与数学中的除法相同 )

        // System.out.print( "5 / 0 = " ) ; 
        // System.out.println( 5 / 0 ); // 运行时出错: java.lang.ArithmeticException

        System.out.print( "5 / 0.0 = " ) ; 
        System.out.println( 5 / 0.0 ); // Infinity ( 正无穷大 )

        System.out.print( "-5 / 0.0 = " ) ; 
        System.out.println( -5 / 0.0 ); // -Infinity ( 负无穷大 )

        System.out.print( "5 / ( 5 / 0.0 ) = " ) ; 
        System.out.println( 5 / ( 5 / 0.0 ) ); // 0.0

例2(取整模,取尽模,遇上0取模):

        System.out.print( "5 % 2 = " ) ;
        System.out.println( 5 % 2 ); // 取模 : 整除取余数 ( 1 )

        System.out.print( "5.45 % 2.2 = " ) ;
        System.out.println( 5.45 % 2.2 ); // 取模 : 整除取余数 ( 1.05 )

        System.out.print( "5 % 0.0 = " ) ;
        // System.out.println( 5 % 0 ); // 运行时错误 : java.lang.ArithmeticException
        System.out.println( 5 % 0.0 );  // NaN : Not a Number , 不是一个数字

例3(i++,++i,i–,--i):

        int x = 100 ;
        System.out.println( x ); // 100
        System.out.println( x++ ); // 100【先输出原来的值、再执行自增操作】
        System.out.println( x ); // 101

        short s = 100 ;
        System.out.println( s ); // 100
        System.out.println( ++s ); // 101 【先执行自增操作、再执行输出操作】
        System.out.println( s ); // 101

        byte b = 100 ;
        byte y = b-- ; // 【先将b变量原来的值赋值给y变量、再执行b变量的自减操作】
        System.out.println( "y = " + y + " , b = " + b ); // y = 100 , b = 99

        long c = 1000L ;
        long z = --c ; // 【先执行c变量的自减操作,再将b变量的值赋值给z变量】
        System.out.println( "z = " + z + " , c = " + c ); // z = 999 , c = 999

10.2 赋值运算符

赋值运算符 为:=,+=, -=, *=, /=, %=

赋值运算符 的 运算规则 是: 从右到左

int a = 100;  //  将 100 赋给 变量a

int b = 10;
b += 20;   // 等价于 b=b+20;

10.3 比较运算符(关系运算符)

比较运算符 :

== (等于) 、!= (不等于)、> (大于)、< (小于)、>= (大于等于)、<=(小于等于)

注意:== 运算符对于基本类型的变量来说比较值,对于引用类型的变量来说比较地址。

10.4 逻辑运算符

10.4.1 基本逻辑运算符
  1. 逻辑与 && :两个值中都为 true 时结果才是 true

  2. 逻辑或 || :两个值中只要有一个为 true 结果就为 true

  3. 逻辑非 ! :与本身相反即可

  4. 逻辑与 & :两个值中都为 true 时结果才是 true

  5. 逻辑或 | :两个值中只要有一个为 true 结果就为 true

  6. 逻辑异或 ^:两个逻辑值不相同时结果为 true

10.4.2 & 和 && 的区别 、| 和 || 的区别
  • 逻辑或: || (短路)、|(不短路)
  • 逻辑与: && (短路)、&(不短路)

例子:

public class Logic3 {

    public static void main(String[] args) {
        
        int a = 100 ;
        int b = 100 ;
        System.out.println( "a = " + a + " , b = " + b ); // a = 100 , b = 100
        System.out.println( ++a > 99 | ++b > 99 ); // 不短路
        System.out.println( "a = " + a + " , b = " + b ); // a = 101 , b = 101

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

        int c = 100 ;
        int d = 100 ;
        System.out.println( "c = " + c + " , d = " + d ); // c = 100 , d = 100
        System.out.println( ++c > 99 || ++d > 99 ); // 短路
        System.out.println( "c = " + c + " , d = " + d ); // c = 101 , d = 100

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

        int m = 100 ;
        int n = 100 ;

        System.out.println( "m = " + m + " , n = " + n ); // m = 100 , n = 100
        System.out.println( ++m < 99 & ++n < 99 ); // 不短路
        System.out.println( "m = " + m + " , n = " + n );// m = 101 , n = 101

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

        int x = 100 ;
        int y = 100 ;

        System.out.println( "x = " + x + " , y = " + y ); // x = 100 , y = 100
        System.out.println( ++x < 99 && ++y < 99 ); // 短路
        System.out.println( "x = " + x + " , y = " + y ); // x = 101 , y = 100
    }

}

10.5 位运算符

10.5.1 移位(>>、<<)

1、>> :向右移位,使用方法为 x >> n 表示 二进制格式的补码的 x 向右移动 n 位

​ – 对于 正数 来说,向右移位时,高位补0,低位被挤掉

​ – 对于 负数 来说,向右移位时,高位补1,低位被挤掉

2、<< :向 左移 位,使用方法为 x << n 表示 x 向左移动 n 位

​ – 不论是正数还是负数,向左移位时,都是挤掉高位,低位补0

[ 注意 ]:

正数 --> 原码、反码、补码相同

负数 --> 反码 = 原码除符号位其余按位取反 、 补码 = 反码 + 1

结合例子理解:

public class BitOperator1 {

    public static void main(String[] args) {
        
        // 被 final 修饰的变量被称作【最终变量】,它是最终的、不可更改的变量 【不要当做"常量"对待】
        final int x = 5 ; // 0b00000000_00000000_00000000_00000101  正数:原码、反码、补码相同
        System.out.println( x );  // 5
        // 尝试再次为 final 修饰的变量赋值
        // x = 6 ; // 错误: 无法为最终变量x分配值

        // 将 最终变量 x 中存储的二进制格式数值向右移动1位后赋值给 y 变量
        int y = x >> 1 ; // 0b0_00000000_00000000_00000000_0000010
        System.out.println( y );  // 2

        int z = x << 1 ; // 0b0000000_00000000_00000000_00000101_0
        System.out.println( z );  // 10

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

        // -5【原码】: 1000_0000_0000_0000_0000_0000_0000_0101
        // -5【反码】: 1111_1111_1111_1111_1111_1111_1111_1010
        // -5【补码】: 1111_1111_1111_1111_1111_1111_1111_1011
        final int m = -5 ; // 0b1111_1111_1111_1111_1111_1111_1111_1011
        System.out.println( m );  //-5

        int n = m >> 1 ; // 0b1_1111_1111_1111_1111_1111_1111_1111_101
        //【补码】1_1111_1111_1111_1111_1111_1111_1111_101
        //【反码】1_1111_1111_1111_1111_1111_1111_1111_100
        //【原码】1_0000_0000_0000_0000_0000_0000_0000_011
        System.out.println( n );  // -3

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

        int p = m << 1 ; //  0b111_1111_1111_1111_1111_1111_1111_1011_0
        //【补码】111_1111_1111_1111_1111_1111_1111_1011_0
        //【反码】111_1111_1111_1111_1111_1111_1111_1010_1
        //【原码】100_0000_0000_0000_0000_0000_0000_0101_0
        System.out.println( p );  // -10

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

        int r = 0x7FFFFFFF ;  // 二进制:0111_1111_1111_1111_1111_1111_1111_1111
        System.out.println( r );  // 2147483647
        
        // 2147483647【原码】: 0111_1111_1111_1111_1111_1111_1111_1111
        // 2147483647【反码】: 0111_1111_1111_1111_1111_1111_1111_1111
        // 2147483647【补码】: 0111_1111_1111_1111_1111_1111_1111_1111
        
        int s = r << 1 ;  //  0b1111_1111_1111_1111_1111_1111_1111_1110
        //【补码】1111_1111_1111_1111_1111_1111_1111_1110
        //【反码】1111_1111_1111_1111_1111_1111_1111_1101
        //【原码】1000_0000_0000_0000_0000_0000_0000_0010
        
        System.out.println( s );  // -2

    }

}

10.5.2 移位(>>>)

无符号右移 >>>:不论是 正数 还是 负数,向 右移 位时,高位一律补0,低位被挤掉

结合例子理解:

public class BitOperator2 {

    public static void main(String[] args) {
        
        final int x = 5 ; // 0b00000000_00000000_00000000_00000101 补码
        final int y = -5 ; // 0b1111_1111_1111_1111_1111_1111_1111_1011 补码

        System.out.println( x >> 1 ); // 0b0_00000000_00000000_00000000_0000010 补码
        System.out.println( y >> 1 ); // 0b1_1111_1111_1111_1111_1111_1111_1111_101 补码

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

        System.out.println( x >>> 1 ); // 0b0_00000000_00000000_00000000_0000010 补码
        System.out.println( y >>> 1 ); // 0b0_1111_1111_1111_1111_1111_1111_1111_101 补码

    }

}
Java 中没有 <<< 运算符 【划重点】
10.5.3 按位或 |,按位与 &,按位异或 ^,按位取反 ~
  1. | 按位或 ( 逐位或 )
  2. & 按位与 ( 逐位与 )
  3. ^ 按位异或 (逐位异或 )
  4. ~ 按位取反 (逐位取反) 【注意连符号位也一起取反】

例子:

public class BitOperator4 {

    public static void main(String[] args) {
        
        final int x = 5 ; // 0b00000000_00000000_00000000_00000101
        final int y = 7 ; // 0b00000000_00000000_00000000_00000111

        //【 5 】0b00000000_00000000_00000000_00000101
        //【 7 】0b00000000_00000000_00000000_00000111
        int a = x | y ; // 按位或: 0b00000000_00000000_00000000_00000111
        System.out.println( a );

        //【 5 】0b00000000_00000000_00000000_00000101
        //【 7 】0b00000000_00000000_00000000_00000111
        int b = x & y ; // 按位与: 0b00000000_00000000_00000000_00000101
        System.out.println( b );

        //【 5 】0b00000000_00000000_00000000_00000101
        //【 7 】0b00000000_00000000_00000000_00000111
        int c = x ^ y ; // 按位异或: 0b00000000_00000000_00000000_00000010
        System.out.println( c );

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

        int r = 5 ; // 0b00000000_00000000_00000000_00000101
        int s = 7 ; // 0b00000000_00000000_00000000_00000111
        System.out.println( "r = " + r + " , s = " + s );

        // int temp = s ; s = r ; r = temp ;
        r = r ^ s ; // 0b00000000_00000000_00000000_00000010
        s = r ^ s ; // 0b00000000_00000000_00000000_00000101
        r = r ^ s ; // 0b00000000_00000000_00000000_00000111

        System.out.println( "r = " + r + " , s = " + s );

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

        int j = 5 ; // 0b00000000_00000000_00000000_00000101
        // 注意使用 ~ 按位取反时,会对整数的符号位也取反
        int k = ~j ; //0b11111111_11111111_11111111_11111010
        //【补码】 11111111_11111111_11111111_11111010
        //【反码】 11111111_11111111_11111111_11111001
        //【原码】 10000000_00000000_00000000_00000110
        System.out.println( "j = " + j + " , k = " + k );

    }

}
10.5.4 特殊案例(移动的位数是 负数)
  • 向右 或 向左移位时,移动的位数 如果是 负数、零、正数 ,分别什么含义?

  • 对于一个 int 类型的数值起来说,向左 或 向右 移动 33 位 其结果是什么? 为什么?

    【 答案:】

    • 因为int类型位移的位数实际是对32进行取余,如果移动32位实际是没有移动。

      • int类型移动大于32位:5 << 33,位移的效果就是 5<<1。

      • int类型移动负数位 :5 << -1,位移的效果就是 5<<31。

      • int类型移动 0 位 :5 << 0 , 即没有发生位移。

      • int类型移动 32以内的正数 位 :5 << 10,即按正常的移位规则移位即可。

public class BitOperator3 {

   public static void main(String[] args) {
       
   final int x = 5 ; // 0b00000000_00000000_00000000_00000101 正数:原码、反码、补码相同
   System.out.println( x >> 0 ); // 5  0b00000000_00000000_00000000_00000101
       
       
   System.out.println( x >> -1 ); // 0 
   //  5 补码:0b00000000_00000000_00000000_00000101
       
   //  因为int类型位移的位数实际是对32进行取余,如果移动32位实际是没有移动。
   //    - int类型移动大于32位:5>>33,位移的效果就是 5>>1。
   //    - int类型移动负数位:5>>-1,位移的效果就是 5>>31。
       
   // 5 >> -1 == 5 >> 31  : 0b00000000_00000000_00000000_00000000
       
       
       
   System.out.println( x >> 36 ); // 0  
   //  5 补码:0b00000000_00000000_00000000_00000101
       
   // 5 >> 36 == 5 >> 4  : 0b00000000_00000000_00000000_00000000
       
       
       
   System.out.println( x >> -32 ); // 5  
   //  5 补码:0b00000000_00000000_00000000_00000101
 
   // 5 >> -32 == 5 >> 0  : 0b00000000_00000000_00000000_00000101
   
       
       
   System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
   
   final int m = -5 ; // 0b1111_1111_1111_1111_1111_1111_1111_1011 补码
   System.out.println( m >> 0 ); // -5 
       
       
   System.out.println( m >> -1 ); // -1
   // -5 >> -1 == -5 >> 31  : 0b11111111_11111111_11111111_11111111
   // 右移:对 负数 来说 ,向右移位时,高位补1,低位被挤掉
       
   // 0b11111111_11111111_11111111_11111111
   //【补码】0b11111111_11111111_11111111_11111111
   //【反码】0b11111111_11111111_11111111_11111110
   //【原码】0b10000000_00000000_00000000_00000001
       
       
   System.out.println( m >> 36 ); // -1 
   // -5 >> 36 == -5 >> 4  : 0b11111111_11111111_11111111_11111111
   // 右移:对 负数 来说 ,向右移位时,高位补1,低位被挤掉
       
   // 0b11111111_11111111_11111111_11111111
   //【补码】0b11111111_11111111_11111111_11111111
   //【反码】0b11111111_11111111_11111111_11111110
   //【原码】0b10000000_00000000_00000000_00000001
       
       
   System.out.println( m >> -32 ); // -5
   // -5 >> -32 == -5 >> 0 
   }

}

10.6 三目、双目、单目运算符

  1. 三目运算符 ( 也叫 三元运算符 或 条件运算符 )

    • expression ? first : second
      • 如果 expression 返回结果为 true 则取 first
      • 如果 expression 返回结果为 false 则取 second
  2. 双目运算符:

    •  a + b 、a - b 、......
      
  3. 单目运算符:

    •   ~a 、-5 、+5 
      

例子:

import java.util.Random;

public class Condition {

    public static void main(String[] args) {

        // 创建一个 Random 类的实例并将该实例的内存地址赋值给 rand 变量
        Random rand = new Random(); // 这个先用起来,暂不详细研究

        // 通过 Random 类中定义的实例方法 nextBoolean 来产生伪随机数
        boolean x = rand.nextBoolean() ; // 每次调用 nextBoolean 都会产生一个随机数
        System.out.println( x );
        System.out.println( x ? "真的" : "假的" ) ;

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

        byte a = 100 ;
        short b = 200 ;
        // variable = expression  ? first : second ;
        // 如果期望通过一个变量接受三目运算符产生的结果,则这个变量 variable 的类型 必须跟 first 和 second 两个值的类型兼容
        short c = a < b ? a : b ;
        System.out.println( c );

    }

}
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐