anonymous的Java学习笔记(2)——数据类型和运算符

数据类型和运算符

[toc]

Java语言是一门强类型语言。强类型包含两方面的含义

  • 所有的变量必须先声明、后使用
  • 指定类型的变量只能接受类型与之匹配的值。

强类型语言可以在编译过程中发现源代码的错误 ,从而保证程序更加健壮。

Java语言提供了丰富的基本数据类型,例如整型、字符型、浮点型和布尔型等。基本类型大致上可以分为两类:

  • 数值类型
    • 数值类型包括整型、字符型和浮点型,所有数值类型之间可以进行类型转换,这种类型转换包括自动类型转换强制类型转换
  • 布尔类型
    • true/false

注释

编写程序时总需要为程序添加一些注释,用以说明某段代码的作用,或者说明某个类的用途、某个方法的功能,以及该方法的参数和返回值的数据类型及意义等。

除此之外,添加注释也是调试程序的一个重要方法。如果觉得某段代码可能有问题,可以先把这段代码注释起来,让编译器忽略这段代码,再次编译、运行,如果程序可以正常执行,则可以说明错误就是由这段代码引起的,这样就缩小了错误所在的范围,有利于排错;如果依然出现相同的错误,则可以说明错误不是由这段代码引起的,同样也缩小了错误所在的范围。

  • 单行注释
    • 语法://
    • 解释:单行注释就是在程序中注释一行代码,在Java语言中,将双斜线(//)放在需要注释的内容之前就可以了
  • 多行注释
    • 语法:/* */
    • 多行注释是指一次性地将程序中多行代码注释掉,在Java语言中,使用/**/将程序中需要注释的内容包含起来,/*表示注释开始,而*/表示注释结束。

程序实例:

public class DataTypesAndOperators {
    public static void main(String [] args){
        /*
        这是多行注释
        */
        /**
         这是文档注释
         这是文档注释
         这是文档注释
         这是文档注释
         */
        //这是单行注释
        System.out.println("HelloJava");
//        System.out.println("这行代码被注释了,程序运行时这行代码不会被执行");
    }
}
  • 文档注释
    • 语法:/** */
    • 解释:文档注释以斜线后紧跟两个星号(/**)开始,以星号后紧跟一个斜线(*/)结束,中间部分全部都是文档注释.

标识符和关键字

分隔符

Java语言里的分号;、花括号{}、方括号[]、圆括号()、空格、圆点.都具有特殊的分隔作用,因此被统称为分隔符。

  • 分号:Java语言采用分号;作为语句的分隔,因此每个Java语句必须使用分号作为结尾。
  • 花括号:花括号的作用就是定义一个代码块,一个代码块指的就是{}所包含的一段代码,代码块在逻辑上是一个整体。花括号一般是成对出现的
  • 方括号:方括号的主要作用是用于访问数组元素,方括号通常紧跟数组变量名,而方括号里指定希望访问的数组元素的索引。
  • 圆括号:圆括号是一个功能非常丰富的分隔符:
    • 定义方法时必须使用圆括号来包含所有的形参声明,调用方法时也必须使用圆括号来传入实参值;
    • 圆括号还可以将表达式中某个部分括成一个整体,保证这个部分优先计算
    • 圆括号还可以作为强制类型转换的运算符。
  • 空格
    • Java语言使用空格分隔一条语句的不同部分。
    • Java语言是一门格式自由的语言,所以空格几乎可以出现在Java程序的任何地方,也可以出现任意多个空格,但不要使用空格把一个变量名隔开成两个,这将导致程序出错。
    • Java语言中的空格包含空格符Space、制表符Tab和回车Enter等。
    • Java源程序还会使用空格来合理缩进Java代码,从而提供更好的可读性。
  • 圆点:圆点.通常用作类对象和它的成员(包括成员变量、方法和内部类)之间的分隔符,表明调用某个类或某个实例的指定成员

Java标识符规则

标识符就是用于给程序中变量、类、方法命名的符号,Java言的标识符必须以字母、下画线_、美元符$开头,后面可以跟任意数目字母数字、下画线_和美元符$
使用标识符时,需要注意如下规则:

  • 标识符可以由字母、数字、下画线_和美元符$组成,其中数字不能打头。
  • 标识符不能是Java关键字和保留字,但可以包含关键和保留字。
  • 标识符不能包含空格
  • 标识符只能包含美元符$,不能包含@#等其他特殊字符

Java关键字

abstract contmue for new switch
assert default if package synchronized
boolean do goto private this
break double implements protected throw
byte else import public throws
case enum instanceof retum transient
catch extends int short try
char final inteface static void
class finally long strictfp volatile
const float native super while

数据类型分类

Java语言是强类型(strongly typed)语言,强类型包含两方面的含义:

  • 所有的变量必须先声明
  • 指定类型的变量只能接受类型与之匹配的值
    声明变量的语法:type varName[ =初始值];

Java语言支持的类型分为两类,基本类型(Primitive Type)和引用类型(Reference Type):

基本数据类型

  • 基本类型包括boolean类型数值类型
    • 数值类型有整数类型浮点类型
      • 整数类型包括byte short int long char(char代表字符型,实际上字符型也是一种整数类型,相当于无符号整数类型)
      • 浮点类型包括float double
    • boolean类型:truefalse

引用数据类型

  • 引用类型包括类、接口和数组类型,还有一种特殊的null类型
    • 所谓引用数据类型就是对一个对象的引用,对象包括实例和数组两种。实际上,引用类型变量就是一个指针,只Java语言里不再使用指针这个说法
    • 空类型null type就是null值的类型,这种类型没有名称。因为null类型没有名称,所以不可能声明一个null类型的变量或者转换到null类型。空引用(null)是null类型变量唯一的值。空引用null可以转换为任何引用类型
    • 在实际开发中程序员可以忽略null类型,假定null只是引用类型的一个特殊直接量。(空引用(null)只能被转换成引用类型不能转换成基本类型,因此不要把一个`null值赋给基本数据类型的变量)

基本数据类型分类

Java的基本数据类型分为两大类:boolean类型和数值类型。
image-20200322150243567-813b3c26a10a49f0944c6f7e6f601d71
Java 只包含这8种基本数据类型,值得指出的是,字符串不是基本数据类型 字符串是一个类,也就是一个引用数据类型。

整型

通常所说的整型,实际指的是如下4种类型

  • byte:一个byte类型整数在内存里占8位,表数范围:-128(-27) ~ 127(27-1)
  • short:一个short类型整数在内存里占16位,表数范围:-32768(-215) ~ 32768(215-1)
  • int:一个int类型整数在内存里占32位,表数范围:-2147483648(-231) ~ 2147483648(231-1)
  • long:一个long类型整数在内存里占64位,表数范围:-263 ~ 263-1

字符型

//字符型
char my_char1 = '中';
char my_char2 = '国';
//制表符
System.out.println("my_char1\tmy_char2:" + my_char1 + my_char2);
//双引号double_a + "":9999999.56461346
byte_to_short:5
byte_to_char:
byte_to_int:5
byte_to_float:5.0
byte_to_long:5
byte_to_double:5.0
System.out.println("\"my_char1\"\t\"my_char2\":" + my_char1 + my_char2);
//单引号
System.out.println("\'my_char1\'\t\'my_char2\':" + my_char1 + my_char2);
//反斜线
System.out.println("\\my_char1\\\t\\my_char2\\:" + my_char1 + my_char2);
//退格符
System.out.println("my_char1\bmy_char2:" + my_char1 + my_char2);//my_charmy_char2:中国  删除了'my_char1'中的'1'
//换行符
System.out.println("my_char1:" + my_char1 + "\nmy_char2:" + my_char2);
//回车符
System.out.println("my_char1\rmy_char2:" + my_char1 + my_char2);
//char类型赋值给int类型
char name = '张';
int char_to_int = name;
System.out.println("char_to_int:" + char_to_int);//24352
//int类型赋值给char类型
char int_to_char = 10000;
System.out.println("int_to_char:" + int_to_char);//✐

浮点型float和double

/*
因为 Java 浮点数使用二进制数据的科学计数法来表示浮点数,因此可能不能精确表
示一个浮点数。例如把 5.2345556f 值赋给一个 float 类型变量,接着输出这个变量时看到
这个变量的值已经发生了改变 使用 double 类型的浮点数比 float 类型的浮点数更精确,
但如果浮点数的精度足够高(小数点后的数字很多 时) ,依然可能发生这种情况。
如果开发者需要精确保存一个浮点数,则可以考虑使用 BigDecimal类

double 类型代表双精度浮点数 float 类型代表单精度浮点数 。
一 double 类型的数值占8字节、64 位, 一个float 类型的数值占4字节、 32 位。
如果希望 Java把一个浮点类型值当成 float 类型处理,应该在这个浮点类型值后紧跟f或F。
 */
float my_float_num = 456f;
System.out.println("my_float_num:" + my_float_num);
double my_double_num = 456.23541;
System.out.println("my_double_num:" + my_double_num);
double zero = 0.0;
System.out.println(my_float_num/zero);
System.out.println("******************************");
//Java 还提供了3个特殊的浮点数值:正无穷大、负无穷大和非数
/*
正无穷大通过 Double、float 类的 POSITIVE_INFINITY 表示
负无穷大通Double、Float 类的 NEGATIVE_INFINITY 表示
非数通过 Double、Float 类的 NaN 表示
必须指出的是,所有的正无穷大数值都是相等的,所有的负无穷大数值都是相等的
 NaN 不与任何数值相等,甚至和 NaN 都不相等
 */
//float和double的负无穷大
float a_float1 = Float.POSITIVE_INFINITY;
double double_float1 = Double.POSITIVE_INFINITY;
System.out.println("Float.NEGATIVE_INFINITY:" + Float.POSITIVE_INFINITY);
System.out.println("Double.NEGATIVE_INFINITY:" + Double.POSITIVE_INFINITY);
System.out.println("a_float1:" + a_float1);
System.out.println("double_float1:" + double_float1);
System.out.println(a_float1 == double_float1);//true
System.out.println("******************************");
//float和double的负无穷大
float a_float2 = Float.NEGATIVE_INFINITY;
double double_float2 = Double.NEGATIVE_INFINITY;
System.out.println("Float.NEGATIVE_INFINITY:" + Float.NEGATIVE_INFINITY);
System.out.println("Double.NEGATIVE_INFINITY:" + Double.NEGATIVE_INFINITY);
System.out.println("a_float2:" + a_float2);
System.out.println("double_float2:" + double_float2);
System.out.println(a_float2 == double_float2);//true
System.out.println("******************************");
//float和double的非数
float a_float3 = Float.NaN;
double double_float3 = Double.NaN;
System.out.println("Float.NEGATIVE_INFINITY:" + Float.NaN);
System.out.println("Double.NEGATIVE_INFINITY:" + Double.NaN);
System.out.println("a_float3:" + a_float3);
System.out.println("double_float3:" + double_float3);
System.out.println(a_float3 == double_float3);//false

布尔类型boolean true和false

/*
布尔型只有 boolean 类型,用于表示逻辑上的"真"或"假"。
在 Java 语言中, boolean 类型的数值只能是 true或false ,不能用0或者非0来代表。
其他基本数据类型的值也不能转换成 boolean 类型。

字符串 "true" "false" 不会直接转换成 boolean 类型.
但如果使用一个boolean 类型的值和字符串进行连接运算,则 boolean 类型的值将会自动转换成字符串 看下面代码
*/
boolean boolean1 = true;
boolean boolean2 = false;
String str1 = boolean1 + "";
String str2 = boolean2 + "";
System.out.println("str1:" + str1);
System.out.println("str2:" + str2);

基本类型的类型转换

自动类型转换

  • Java 所有的数值型变量可以相互转换,如果系统支持把某种基本类型的值直接赋给另1种基本类型的变量,则这种方式被称为自动类型转换。当把1个表数范围小的数值或变量直接赋给另1个表数范围大的变量时,系统将可以进行自动类型转换:否则就需要强制转换.
  • 表数范围小的可以向表数范围大的进行自动类型转换,就如同有两瓶水,当把小瓶里的水倒入大瓶中时,不会有任何问题 Java 支持自动类型转换的类型如图
    image-20200322182706647-427ae67671bf4ee981ead181011f1575
  • 上图中所示的箭头左边的数值类型可以自动类型转换为箭头右边的数值类型
  • 当把任何基本类型的值和字符串值进行连接运算时,基本类型的值将自动类型转换为字符串类型,虽然字符串类型不是基本类型,而是引用类型。因此,如果希望把基本类型的值转换为对应的字符串时,可以把基本类型的值和一个空字符串进行连接。

代码示例:

package com.abc.part_two;

public class AutomaticTypeConversion {
    /**
     * 自动类型转换
     */
    public static void main(String[] args) {
        byte byte_a = 5;//1字节,在内存中占8位
        char char_a = '中';//2字节,在内存中占16位
        short short_a = 56;//2字节,在内存中占16位
        int int_a = 3000;//4字节,在内存中占32位
        float float_a = 65161.25f;//4字节,在内存中占32位
        long long_a = 99999999L;//8字节,在内存中占64位
        double double_a = 9999999.56461346;//8字节,在内存中占64位

        //如果希望把基本类型的值转换为对应的字符串时,可以把基本类型的值和一个空字符串进行连接。
        System.out.println("double_a + \"\":" + double_a + "");
        // 下面语句输出:7Hello!
        System.out.println(3 + 4 + "Hello!");
        // 下面语句输出:Hello!34,因为Hello! + 3会把3当成字符串处理,而后再把4当做字符串处理
        System.out.println("Hello!" + 3 + 4);

        //byte类型数据向表数范围大的数据类型自动转换
        //byte转short
        short byte_to_short = byte_a;
        System.out.println("byte_to_short:" + byte_to_short);//`+`不仅可作为加法运算符使用,还可作为字符串连接运算符使用。
        //byte转char 会报错,byte类型不能自动类型转换为char类型,需要强制类型转换。
        char byte_to_char = (char) byte_a;
        System.out.println("byte_to_char:" + byte_to_char);
        //byte转int
        int byte_to_int = byte_a;
        System.out.println("byte_to_int:" + byte_to_int);
        //byte转float
        float byte_to_float = byte_a;
        System.out.println("byte_to_float:" + byte_to_float);
        //byte转long
        long byte_to_long = byte_a;
        System.out.println("byte_to_long:" + byte_to_long);
        //byte转double
        double byte_to_double = byte_a;
        System.out.println("byte_to_double:" + byte_to_double);
    }
}

输出:

double_a + "":9999999.56461346
7Hello!
Hello!34
byte_to_short:5
byte_to_char:
byte_to_int:5
byte_to_float:5.0
byte_to_long:5
byte_to_double:5.0

强制类型转换

强制类型转换换的语法格式是 (targetType )value ,强制类型转换的运算符是圆括号 (()) 。当进行强制类型转换时,类似于把一个大瓶子里的水倒入一个小瓶子,如果大瓶子里的水不多还好,但如果大瓶子里的水很多,小瓶子将会引起溢出 ,从而造成数据丢失 这种转换也被称为"缩小转换 (Narrow Conversion)"。

代码示例:

package com.abc.part_two;

public class Coercion {
    /**
     * 强制类型转换
     * 强制类型转换换的语法格式是 (targetType )value ,强制类型转换的运算符是圆括号 (()) 。当进行强制类型转换时,
     * 类似于把一个大瓶子里的水倒入一个小瓶子,如果大瓶子里的水不多还好,但如果大瓶子里的水很多,
     * 小瓶子将会引起溢出 ,从而造成数据丢失 这种转换也被称为"缩小转换 (Narrow Conversion)"
     *
     * @param args
     */
    public static void main(String[] args) {
        int iValue = 233;
//      强制把一个 int 类型的值转换为 byte 类型 的值
        byte bValue = (byte) iValue;
//      将输出 -23
        System.out.println(bValue);//-23
        double dValue = 3.98;
//      强制把 double 类型的值转换为 int 类型的值
        int tol = (int) dValue;
//      将输出3
        System.out.println(tol);//3
        /**
         * 在上面程序中,把1个浮点数强制类型转换为整数时, Java 将直接截断浮点数的小数部分。
         * 除此之外,上面程序还把 233 强制类型转换为 byte 类型的整数,从而变成了-23,这就是典型的溢出
         */

        //生成一个6位的随机字符串
        //定义一个空字符串
        String result = "";
        //进行6次循环
        for (int i = 0; i < 6; i++) {
            int int_number = (int) (Math.random() * 26 + 97);
            result = result + (char) int_number;
        }
        System.out.println("本次随机生成的6位字符串为:" + result);
        //double强转float
        //39.642默认是一个 double 类型的浮点数
        float double_to_float = (float) 39.642;
        System.out.printf("double 强转为 float:%f", double_to_float);//double 强转为 float:39.641998
        System.out.println();
        //字符串转int
        String name1 = "中";
        String name2 = "1999";
        String name3 = "1999.5678";
//        int string_to_int1 = Integer.parseInt(name1);//会报错:Exception in thread "main" java.lang.NumberFormatException: For input string: "中"
        //只能将数字类型的字符串如:"456", "1024"转换成基本数据类型
        int string_to_int2 = Integer.parseInt(name2);
//        System.out.println("string_to_int1:" + string_to_int1);
        System.out.println("string_to_int2:" + string_to_int2);

        //格式化输出
        String str = "sss";
        System.out.printf("字符串str格式化输出:%s", str);//字符串str格式化输出:sss
    }
}

输出:

-23
3
本次随机生成的6位字符串为:mrfhft
double 强转为 float:39.641998
string_to_int2:1999
字符串str格式化输出:sss

Java为8种基本类型都提供了对应的包装类:

  • boolean ---> Boolean
  • byte ---> Byte
  • short ---> Short
  • int ---> Integer
  • long ---> Long
  • char ---> Character
  • float ---> Float
  • double ---> Double

8个包装类都提供了parseXxx(String str)静态方法用于将字符串转换成基本类型。

表达式类型的自动提升

代码示例:

//表达式类型的自动提升
short short_num1 = 9;
//表达式右边中的short_num1将自动提升到 int 类型,则右边的表达式类型为int, 将一个 int 类型值直接赋给 short 类型变量将发生错误
//        short_num1 = short_num1 - 3;
//这时候需要手动强转为short类型数据
short_num1 = (short) (short_num1 - 3);
System.out.printf("short类型数据:%s", short_num1);
//换行
System.out.println();
//以下是正确的表达式类型的自动提升
byte byte_num1 = 12;
char char_num1 = '阿';
short short_num2 = 1245;
double double_num1 = 12.56;
// 右边表达式中最高等级操作数为double_num1(double类型), 则右边表达式的类型为double类型,故赋给一个double类型变量
double double_result = byte_num1 + char_num1 + short_num2 + double_num1;
System.out.println(double_result);
System.out.println((double) char_num1);//38463.0

//必须指出,表达式的类型将严格保持和表达式中最高等级操作数相同的类型。下面代码中两个int类型整数进行除法运算,即使无法除尽,也将得到int类型结果
int int_num1 = 29;
//表达式右边两个操作数都是int类型,所以右边表达式的类型为int。
//虽然29/3不能除尽,但依然会得到一个int类型整数
int int_result = int_num1 / 3;
System.out.printf("int_num1 / 3 = %s", int_result);//9
//从上边的结算结果来看,当两个整数进行除法运算时,如果不能整除,得到的结果将是把小数部分截断后取整数部分。
System.out.println();
//如果表达式中包含了字符串,则又是另1番情形了 因为当把加号(+)放在字符串和基本类型值之间时 这个加号是1个字符串连接运算符 而不是进行加法运算 看如下代码:
System.out.println("Java!" + '哈' + 3);//Java!哈3
System.out.println((int) '哈');//21704
System.out.println('哈' + 3 + "Java!");//21707Java!
/**
 * 对于第1个表达式 "Java!" + '哈' + 3,先进行"Java!" + '哈'运算, '哈'转换成字符串,拼接成字符串 Java!哈, 接着进行 "Java!哈" + 3运算,这也是字符串连接运算,结果是 Java!哈3
 * 对于第2个表达式 先进行 '哈' + 3 加法运算,其中'哈'自动提升到int类型,变成'哈'对应的ASCII值:21704, 21704 + 3 = 21707, 然后进行 21707 + "Hello ! 运算 21707会自动转换成字符串,将变成两个字符串的连接运算 从而得到 21707Java!
 */

直接量

直接量是指在程序中通过源代码直接给出的值,int a=5这行代码中, 为变a所分配的初始值,就是1个直接量。

直接量的类型

并不是所有的数据类型都可以指定直接量,能指定直接量的通常只有3种类型 基本类型、字符串类型和null类型,具体而言,Java支持如下8种类型的直接量。

  • int 类型的直接量:在程序中直接给出的整型数值, 可分为二进制、十进制、八进制和十六进制4种,其中二进制需要 OB/Ob开头,八进制需要以0开头,十六进制需要Ox/OX开头。例如123、012(对应十进制的10)、Ox12 (对应十进制的18)等
  • long 类型的直接量:在整型数值后添加l或L后就变long类型的直接量。例如 3L、Ox12L(对应十进制的18L)
  • float 类型的直接量: 在一个浮点数后添加f/F就变成了 float 类型的直接量,这个浮点数可以是标准小数形式,也可以是科学计数法形式 例如 5.34F、3.14E5f
  • double 类型的直接量:直接给出1个标准小数形式或者科学计数法形式的浮点数就是 double类型的直接量。 例如 5.34、3.14E5
  • boolean 类型的直接量:这个类型的直接量只有 true/false
  • char 类型的直接量: char 类型的直接量有三种形式,分别是用单引号括起来的字符、转义字符和Unicode 值表示的字符。例如'a'、'\n'、'\u0061'。
  • String 类型的直接量:1个用双引号括起来的字符序列就是 String 类型的直接量。
  • null 类型的直接量:这个类型的直接量只有1个值,即 null。

在上面的8种类型的直接量中, null 类型是1种特殊类型,它只有1个值:null,而且这个直接量可以赋给任何引用类型的变量,用以表示这个引用类型变量中保存的地址为空,即还未指向任何有效对象。

直接量的赋值

//直接量的赋值,通常总是把1个直接量赋值给对应类型的变量,例如下面代码都是合法的:
int a = 5;
char c = 'a';
boolean b = true;
float f = 5.12f;
double d = 4.12;
String author = "小花花";
String book = "Go语言学习入门";

知识点

  • String 类型的直接量不能赋给其他类型的变量, null 类型的直接量可以直接赋给任何引用类型的变量,包括 String 类型。
  • boolean 类型的直接量只能赋给 boolean 类型的变 ,不能赋给其他任何类型的变量。
  • 关于字符串直接量有一点需要指出, 当程序第一次使用某个字符串直接量时, Java 会使用常量池(constant pool) 来缓存该字符串直接量 ,如果程序后面的部分需要用到该字符串直接量时 Java 会直接使用常量池 (constant pool) 中的字符串直接量。
  • 由于 String 类是一个典型的不可变类,因此 String对象创建出来就不可能被改变,因此无须担心共享 String 对象会导致混乱。
  • 常量池( constant pool )指的是在编译期被确定,并被保存在己编译的 .class 文件中的一些数据,它包括关于类、方法、接口中的 常量, 也包括字符串直接量。
    代码示例:
String s0 = "hello";
String s1 = "hello";
String s2 = "he" + "llo";
System.out.println(s0 == s1);//true
System.out.println(s0 == s2);//true
  • Java会确保每个字符串常量只有1个,不会产生多个副本,例子中的 sO和s1中的 "hello" 是字符串常量,它在编译期就被确定了,所 sO == s1返回true;
  • "he'和"ll0" 也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它本身就是字符串常量, s2一样在编译期就被解析为1个字符串常量,所 s2也是常量池中 "hello" 的引用。因此,程序输出 sO == s1返回 true ,s1 == s2 返回 true。

运算符

算术运算符

加法运算符 +

  • 示例
    //加法运算符 +
    int num1 = 10;
    int num2 = 14;
    int num_sum = num1 + num2;
    System.out.println(num_sum);//24
    

减法运算符 -

  • 示例
    //减法运算符 -
    int num_subtraction = num1 - num2;
    System.out.println(num_subtraction);//-4
    

乘法运算符 *

  • 示例
    //乘法运算符 *
    int num_multiplication = num1 * num2;
    System.out.println(num_multiplication);//140
    

除法运算符 /

  • 如果除法运算符的两个操作数都是整数类型(其中除数不可以为0),计算结果取商
  • 如果除法运算符的两个操作数有一个是浮点数或者两个都是浮点数,则计算结果也是浮点数。此时允许除数为0或者0.0,得到的结果是正无穷大或负无穷大。
int num2 = 14;
double num3 = 18.54;
double num4 = 58.54;
int division_num1 = num2 / num1;
//        int division_num2 = num2 / 0;//除数不可以为0
double division_num3 = num3 / num1;
double division_num4 = num4 / num3;
double division_num5 = num3 / 0;
double division_num6 = num3 / 0.0;
//        System.out.println(num2 / num1);
System.out.println(division_num1);//1
//        System.out.println(division_num2);
System.out.println(division_num3);//1.8539999999999999
System.out.println(division_num4);//3.157497303128371
System.out.println(division_num5);//正无穷大  Infinity
System.out.println(division_num6);//正无穷大  Infinity
System.out.println(-num3 / 0);//负无穷大  -Infinity
System.out.println(-num3 / 0.0);//负无穷大  -Infinity

取余运算符 %

  • 求余运算符.求余运算的结果不1定总是整数,它的计算结果是使用第一个操作数除以第2操作数后得到1个整除的结果后剩下的值就是余数。
  • 由于求余运算也 要进行除法运算,因此如果求余运算的两个操作数都是整数类型,则求余运算的第2个操作数不能是0,否则将引发除以零异常.
  • 如果求余运算的两个操作数中有1个或者两个都是浮点数,则允许第2个操作数是0或0.0 ,只是求余运算的结果是非数: NaN
  • 0或0.0 对零以外的任何数求余都将得到0或0.0
int num2 = 14;
System.out.println(num2 % num1);//4
System.out.println(num3 % num2);//4.539999999999999
System.out.println(num3 % 0);//非数 NaN
System.out.println(num3 % 0.0);//非数 NaN
System.out.println(-num3 / 0);//负无穷大  -Infinity
System.out.println(-num3 / 0.0);//负无穷大  -Infinity
System.out.println(0 / 5);//0
System.out.println(0.0 / 5);//0.0

自加 ++ 将操作数的值加1

  • 自加是单目运算符,只能操作一个操作数
  • 自加运算符只能操作单个数值型(整型、浮点型都行)的变量,不能操作常量或表达式.
  • 运算符既可以出现在操作数的左边,也可以出现在操作数的右边
  • 但出现在左边和右边的效果是不1样的,如果把++放在左边,则先把操作数加1,然后才把操作数放入表达式中运算
  • 如果把++放在右边,则先把操作数放入表达式中运算,然后才把操作数加1
    int a = 3;
    //        int a_new1 = a++ + 3;//a先不自增1,直接加3.此时a_new1=3+3=6,然后a在自增1此时a=4
    //        System.out.println(a + "\t" + a_new1);//4   6
    int a_new2 = ++a + 3;//a先自增1,直接加3.此时a_new1=4+3=6,然后a在自增1此时a=4
    System.out.println(a + "\t" + a_new2);//4   7
    

自减 -- 用法与++自增用法一致 将操作数的值减1

  • 示例
    int b = 5;
    int b_new1 = b-- - 1;
    System.out.println(b + "\t" + b_new1);//4   4
    //        int b_new2 = --b - 1;
    //        System.out.println(b + "\t" + b_new2);//4   3
    

自加和自减总结

  • 自加和自减只能用于操作变量,不能用于操作数值直接量、常量或表达式
  • Java 并没有提供其他更复杂的运算符,如果需要完成乘方、开方等运算,则可借助于 java.lang.Math类的工具方法完成复杂的数学运算
  • Math 类下包含了丰富的静态方法,用于完成各种复杂的数学运算。

赋值运算符

赋值运算符用于为变量指定变量值,与C类似, Java也使用=作为赋值运算符。通常,使用赋值运算符将一个直接量值赋给变量。

//为变量赋值
String str1 = "Java";
String str2 = "Python";
int age = 21;
//        将一个变量的值赋值给另一个变量
String myFavoriteProgramLanguage = str1;
System.out.printf("我最喜欢的编程语言之一是%s\n其次是%s\n我今年%d岁了," +
        "我相信自己可以学会这两门编程语言~", myFavoriteProgramLanguage, str2, age);

赋值运算符是从右向左执行计算的,程序先计算得到=右边的值,然后将该值"装入"=左边的变量,因此赋值运算符(=)左边只能是变量。

赋值表达式是有值的,赋值表达式的值就是右边被赋的值

  • 例如 String str2 = str表达式的值就是str.因此,赋值运算符支持连续赋值,通过使用多个赋值运算符,可以一次为多个变量赋值
    • 示例
      System.out.println();
      int a;
      int b;
      int c;
      //连续为多个变量进行赋值
      a = b = c = 666;
      System.out.printf("a:%d\nb:%d\nc:%d", a, b, c);
      

位运算符

Java支持的位运算符有如下7个

  • & 按位与。当两位同时为1时才返回1
  • | 按位或。只要有 位为1即可返回1
  • ~ 按位非。单目运算符,将操作数的每个位(包括符号位) 全部取反
  • ^ :按位异或 当两位相同时返回0 不同时返回1
  • << : 左移运算符
  • >> : 右移运算符
  • >>> : 无符号右移运算符

一般来说,位运算符只能操作整数类型的变量或值

扩展后的赋值运算符

赋值运算符可与算术运算符、位移运算符结合,扩展成功能更加强大的运算符,扩展后的赋值运算符如下

  • +=;对于x+=y,即对应于x=x+y
  • -=;对于x-=y,即对应于x=x-y
  • *=;对于x*=y,即对应于x=x*y
  • /=;对于x/=y,即对应于x=x/y
  • %=;对于x%=y,即对应于x=x%y
  • &=;对于x&=y,即对应于x=x&y
  • |=;对于x|=y,即对应于x=x|y
  • ^=;对于x^=y,即对应于x=x^y
  • <<=;对于x<<=y,即对应于x=x<<y
  • >>=;对于x>>=y,即对应于x=x>>y
  • >>>=;对于x>>>=y,即对应于x=x>>>y
  • 示例
    byte a = 6;
    a = (byte) (a + 4);//需要强转,否则会报错
    byte b = 6;
    b += 4;
    System.out.printf("a:%d\nb:%d", a, b);
    

比较运算符

比较运算符用于判断两个变量或常量的大小,比较运算的结果是一个布尔值(true false)。Java支持的比较运算符如下

  • >: 大于,只支持左右两边操作数是数值类型。如果前面变量的值大于后面变量的值,则返回 true
  • >=: 大于等于,只支持左右两边操作数是数值类型。如果前面变量的值大于等于后面变量的值,则返回 true
  • <: 小于,只支持左右两边操作数是数值类型。如果前面变量的值小于后面变量的值,则返回 true
  • <=: 小于等于,只支持左右两边操作数是数值类型。如果前面变量的值小于等于后面变量的值,返回 true
  • ==: 等于,如果进行比较的两个操作数都是数值类型,即使它们的数据类型不相同,只要它们的值相等,也都将返回true
    • 例如 97 == 'a'返回true. 5.0 == 也返回 true
    • 如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,而且这两个引用必须指向同一个对象才会返回true
    • Java也支持两个boolean类型的值进行行比较,例如,true == false, 将返回 false
  • !=:不等于,如果进行比较的两个操作数都是数值类型,无论它们的数据类型是否相同,只要它们的值不相等,也都将返回true
    • 如果两个操作数都是引用类型,只有当两个引用变量的类型具有父子关系时才可以比较,只要两个引用指向的不是同一个对象就会返回true。
  • 示例
    int a = 5;
    int b = 6;
    int c = 6;
    System.out.printf("a < b? %b\nb == c? %b\na != c? %b\n", a < b, b == c, a != c);//a < b? true  b == c? true a != c? tru
    String name1 = "小明";
    String name2 = "小明";
    System.out.printf("name1 != name2? %b\nname1 == name2? %b\n", name1 != name2, name1 == name2);//a < b? true  b == c? true
    System.out.printf("true != false? %b\ntrue == false? %b\n", true != false, true == false);//true != false? true  true == false? false
    //创建两个Coercion类的对象,分别赋值给t1和t2两个变量引用
    Coercion t1 =new Coercion();
    Coercion t2 = new Coercion();
    // tl和t2 是同一个类的两个实例的引用,所以可以比较
    //但t1和t2 引用不同的对象,所以返回 false
    System.out.println("t1 是否等于 t2: " + (t1 == t2)) ;//t1 是否等于 t2: false
    //直接将 t1 的值赋给t3, 即让t3 指向 t1 指向的对象
    Coercion t3 = t1 ;
    //t1和t3 指向同一个对象,所以返回 true
    System.out.println("t1 是否等于 3 : " + ( t1 == t3)) ;//t1 是否等于 3 : true
    

逻辑运算符

逻辑运算符用于操作两个布尔型的变量或常量 逻辑运算符主要有如下6个

  • &&: 与,前后两个操作数必须都是true才返回 true,否则返回 false
  • &:不短路与,作用与&&相同,但不会短路
  • &&&的区别:&总会计算前后两个操作数,而&&先计算左边的操作数,如果左边的操作数为false,则直接返回false,根本不会计算右边的操作数
  • ||: 或,只要两个操作数中有一个是true,就可以返回 true ,否则返回 false
  • |: 不短路或,作用与||相同,但不会短路
  • |||的区别:|总会计算前后两个操作数,而||先计算左边的操作数,如果左边的操作数为true,则直接返回true,根本不会计算右边的操作数
  • !: 非,只需要一个操作数,如果操作数为true ,则返回 false 如果操作数为 false ,则返回 true
  • ^: 异或,当两个操作数不同时才返回 true,如果两个操作数相同则返回 false
  • 下面代码示范了或、与、非、异或4个逻辑运算符的执行示意
    String name1 = "潇潇";
    String name2 = "大大";
    System.out.println("&&  &");
    System.out.println(!((name1 == name2) && (name1 != name2)));//true
    System.out.println(!(name1 == name2) && (name1 != name2));//true
    System.out.println((name1 == name2) && !(name1 != name2));//false
    System.out.println(!((name1 == name2) & (name1 != name2)));//true
    System.out.println(!(name1 == name2) & (name1 != name2));//true
    System.out.println((name1 == name2) & !(name1 != name2));//false
    System.out.println("||  |");
    System.out.println(!((name1 == name2) || (name1 != name2)));//false
    System.out.println(!(name1 == name2) || (name1 != name2));//true
    System.out.println((name1 == name2) || !(name1 != name2));//false
    System.out.println(!((name1 == name2) | (name1 != name2)));//false
    System.out.println(!(name1 == name2) | (name1 != name2));//true
    System.out.println((name1 == name2) | !(name1 != name2));//false
    

三目运算符

  • 三目运算符只有一个 ? , 三目运算符的语法格式如下:
    • (expression) ? if-true-statement : if-false-statement;
  • 三目运算符的规则是:先对逻辑表达式 expression 求值,如果逻辑表达式返回 true ,则返回第二操作数的值,如果逻辑表达式返回 false ,则返回第一个操作数的值
  • 大部分时候,三目运算符都是作为 if else 的精简写法
  • 三目运算符和 if else 写法的区别在于: if 后的代码块可以有多个语句,三目运算符是不支持多个语句的。
  • 三目运算符可以嵌套,嵌套后的三目运算符可以处理更复杂的情况

示例

String str = 5 > 1 ? "5大于1" : "5小于1";
System.out.println(str); //5大于1
//        嵌套的三目运算符
boolean result = 6 < 2 ? true : (6 > 3 ? false : true);
System.out.println(result);//false

运算符的结合性和优先级

  • 所有的数学运算都认为是从左向右运算的, Java 语言中大部分运算符也是从左向右结合的,

  • 只有单目运算符、赋值运算符和三目运算符例外,其中,单目运算符、赋值运算符和三目运算符是从右向左结合的 ,也就是从右向左运算

  • 乘法和加法是两个可结合的运算,也就是说,这两个运算符左右两边的操作数可以互换位置而不会影响结果。

  • 运算符有不同的优先级,所谓优先级就是在表达式运算中的运算顺序。下表列出了包括分隔符在内的所有运算符的优先级顺序,上一行中的运算符总是优先于下一行的。

    运算符说明Java 运算符
    分隔符. [] () {} , ;
    单目运算符++ -- ~ !
    强制类型转换运算(type)
    乘法/除法/求余* / %
    加法/减法+ -
    移位运算符<< >> >>>
    关系运算符< <= >= > instanceof
    等价运算符== !=
    按位与&
    按位异或^
    按位或|
    条件与&&
    条件或||
    三目运算? :
    赋值= += -= *= /= &=