《Java 核心卷1》ch3 Java 的基本程序设计结构

ch3 Java 的基本程序设计结构

数据类型

  • Java 是一种强类型语言。

  • Java 中,一共有 8 中基本类型

    • 其中有 4 种整型、2 种浮点类型、1 中字符类型 char 和 1 中表示真值的 boolean 类型。

Java 中有一个能有表示任意精度的算书包,称之为“大数”。但是它不是一种基本 Java 类型,而是一个 Java 对象。

整型 【4 种】

java整型

  • 带有后缀 L或者 l 表示 long; (eg:40L)
  • 前缀 0x 或 0X 表示十六进制数值; (eg:0xCAFE)
  • 前缀 0 表示八进制;(eg:010表示十进制8。容易混淆,最好别用
  • 前缀 0b 或 0B 表示二进制数。 (eg:0b1001,就是9)

浮点类型 【2 种】

浮点类型

  • 带有后缀 F 或 f 表示 float 类型;
  • 不带后缀的浮点类型表示 double,也可以带后缀 D 或者 d

char 类型

转义序列

变量与常量

  • 千万不能使用没有初始化的变量

  • 变量的声明尽可能靠近变量第一次使用的地方(非强制,但是可读性更高)

  • 用 final 修饰的表示常量

    • 关键字 final 表示这个变量只能被赋值一次。一旦被赋值后,就不能在更改了 。
    • 习惯上,常量名使用全大写
  • 枚举类型:变量取值只在一个有限的集合内。

    enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE}

运算符

数值类型之间的转换

数值类型之间的转换

  • 6 个实现箭头,表示无信息丢失的转换;
  • 3 个虚线箭头,表示可能有精度损失的转换

当用一个二元运算符两个值时,先要将两个操作数转化为同一种类型,然后再进行计算:

  • 如果两个操作数中有一个是 double 类型,另一个操作数就会转换为 double 类型;
  • 否则,如果其中一个操作数是 float 类型,另一个操作数将会转换为 float 类型;
  • 否则,如果其中一个操作数是 long 类型,另一个操作数将会转换为 long 类型;
  • 否则, 两个操作数都将被转换为 int 类型。

强制类型转化

  • 可能造成信息丢失

  • 语法格式:在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名

    double x = 8.98;
    
    int nx = (int) x; // 强制类型转换 double -> int
    

结合赋值和运算符

  • 可以在赋值中使用二元运算符

    x += 4; 等价与 x = x + 4;

  • 注意: 如果运算符得到一个值,其类型与左侧操作数的类型不同,就会发生强制类型转换。

    例如,如果x是一个int,则以下语句

    x += 3.5;

    是合法的,将把 x 设置为(int)(x + 3.5)。

自增与自减运算符

  • 后缀形式:i++、i–
  • 前缀形式:++i、–i
  • 前缀形式先完成加一;而后缀形式会使用变量原来的值

最好不要在表示式中使用 ++,这样容易迷惑…

关系运算符

  • 关系运算符:>、<、>=、<=、==、!=

  • 逻辑运算符:&&(逻辑 与)、||(逻辑 或)、!(逻辑 非)

  • && 和 || 运算符是按照“短路”方式来求值的

    • 如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。
    • 因此,可以利用这一点来避免错误。

    例如,x != 0 && 1 / x > x + y 可以避免 0 作为分母

位运算符

  • & (“and”)、 | (“or”)、 ^ (“XOR”)、 ~ (“not”)
  • & 和丨运算符不采用“ 短路” 方式来求值
  • 左移 << 、右移 >>
    • n << i,将 n 的二进制左移 i 位,相当于将 n 扩大 2^i 倍;
      • n << i = n * 2^i;
      • eg:3 << 2 等于 12
    • n >> i,将 n 的二进制右移 i 位,相当于将 n 缩小 2^i 倍;
      • n >> i = n / (2^i);
      • eg:12 >> 1等于 6
  • 无符号右移 >>>
    • “>>>” 只用 0 填充最高位,而 “>>”是用符号位填充高位
    • 注意:不存在 “<<<" 运算符。

括号与运算符优先级

  • && 的优先级比|| 的优先级高


字符串

子串

  • s.substring(i, j) ; // 左闭右开区间,取 s 中索引介于 [i, j) 的子串

拼接

  • “+” 拼接两个字符串

    • 当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串
  • 如果需要把多个字符串放在一起, 用一个定界符分隔,可以使用静态 join 方法

    • String all = String.join(" / ", “S”, “M”, “L”, “XL”); // all is the string "S / H / L / XL
  • repeat 方法 (java11提供)

    • String s = “a”.repat(3); // s is “aaa”

不可变字符串

  • String 类没有提供用于修改字符串的方法,不能直接修改字符串中的字符

    • 以下代码中如想,修改greeting 的内容修改为“ Help!”,不能直接地将greeting的最后两个位置的字符修改为 ‘p’ 和 ‘!’。做法应为,子串拼接

    String greeting = “Hello”;

    greeting = greeting.substring(0, 3) + “p!”; // 子串拼接

  • 不能修改其中的任何一个字符,但是可以修改字符串变量 greeting, 让它引用另外一个字符串

  • 拼接字符串比直接修改一个代码单元效率低,那为什么还用?

  • 不可变字符串却有一个优点

    • 编译器可以让字符串共享。

    为了弄清具体的工作方式, 可以想象将各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置。如果复制一个字符串变量, 原始字符串与复制的字符串共享相同的字符。

  • 总而言之,Java 的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。

检测字符串是否相等

  • 用 equals 方法检测两个字符串内容是否相等
  • 不要使用 == 运算符检测两个字符串是否相等,== 只能检测两个字符串使用同一个引用

空串与 Null 串

  • 空串"" 是长度为0 的字符串

    • 空串是一个Java 对象, 有自己的串长度( 0 ) 和内容(空)
  • null 串, 这表示目前没有任何对象与该变量关联

  • 检查一个字符串既不是null 也不为空串

    • if (str != null && str.length() != 0)
    • 两条语句不可颠倒,这里使用逻辑“短路”,避免了 null 调用 lenght() 方法

码点与代码单元

没细看这个码点是个啥…

构建字符串

  • 由较短的字符串构建字符串,采用字符串连接的方式达到此目的效率比较低

  • 每次连接字符串, 都会构建一个新的String 对象,既耗时, 又浪费空间

  • 使用 StringBuilder 类就可以避免这个问题的发生

即,如果需要频繁拼接字符串时,改用 StringBuilder 代替 String。

StringBuilder builder = new StringBuilder();  
builder.append(ch); // appends a single character  
bui1der.append(str); // appends a string  
String completedString = builder.toString(); // 转换为 String  

输入输出

读取输入

  • 首先需要构造一个Scanner 对象,并与“ 标准输人流” System.in 关联

    • Scanner in = new Scanner(System.in);
  • Scanner 类中的方法

    • nextLine()方法:输入一行(允许输入行中包括空格)
    • next() 方法:读取一个单词(以空白符作为分隔符),
    • nextlnt() 方法:读取一个整数
    • nextDouble() 方法:读取下一个浮点数
  • 因为输入是可见的, 所以Scanner 类不适用于从控制台读取密码

    • 使用 Console 类 实现密码读取 (书上p56)

格式化输出

  • 使用 System.out.printf 方法实现格式化输出
  • 可以使用静态的String.format 方法创建一个格式化的字符串, 而不打印输出
  • 格式化输出日期:t 开始 (书上p59)
  • 参数索引:索引必须紧跟 % 后面,以 $ 终止,索引从 1 开始,而不是从 0 开始

文件输入与输出

Path.of() 函数是 Java11特性,但是本机装的是 jdk1.8,没用成。

尝试了下装 java11,结果炸了。又回退到 jdk1.8 了

暂时跳过这里…

控制流程

块作用域

  • (即复合语句)是指由一对大括号括 {} 起来的若干条简单的 Java 语句
  • 一个块可以嵌套在另一个块中,但不能在嵌套的两个块中声明同名的变量

条件语句

  • if (condition) statement
  • if (condition) statementi else statementi
    • else 子句与最邻近的 if 构成一组

循环

  • while {condition ) statement

    • while 循环语句首先检测循环条件
    • 循环体中的代码有可能一次都不被执行
  • do statement while { condition);

    • do while 先执行语句(通常是一个语句块),再检测循环条件;
    • do while 至少执行一次循环体代码
  • for (int i = 1; i <= 10; i++)

    • for 语句的第1 部分通常用于对计数器初始化; 第2 部分给出每次新一轮循环执行前要检测的循环条件; 第3 部分指示如何更新计数器。
    • for 语句的3 个部分应该对同一个计数器变量进行初始化、检测和更新。(不是硬性规定,但是如果不遵守这个可能造成代码晦涩难懂)
  • 泛型循环 : foreach 循环

循环中,检测两个浮点数是否相等需要格外小心

for (double x = 0; x != 10; x += 0 . 1) . . .

可能永远不会结束。由于舍入的误差, 最终可能得不到精确值

在上面的循环中,因为 0.1 无法精确地用二进制表示, 所以,x 将从9.999 999 999 999 98 跳到
10.099 999 999 999 98

多重选择:switch 语句

  • 有可能触发多个case 分支;
  • 如果在case 分支语句的末尾没有break 语句, 那么就会接着执行下一个case 分支语句

所以,使用 switch 时每个单独情况的 case 后面一定要带上 break;多个 case 处理同一情况,则不必加 break

  • case 标签可以是:
    • 类型为 char、byte、short 或 int 的常量表达式
    • 枚举常量
    • Java 7 开始, case 标签还可以是字符串字面量

中断控制流程语句

  • goto 是 Java 的保留字,但是在 Java 中并未使用它;

  • break : 跳出本层循环;

  • 带标签的break 语句 : 用于跳出多重嵌套的循环语句

    • 标签必须放在希望跳出的最外层循环之前, 并且必须紧跟一个冒号。

      read_data: // 标签
      while (. . .) { // this loop statement is tagged with the label  
      	for (. . .) { // this inner loop is not labeled    
      		...  
      		if (n < 0) { // should never happen-can’t go on  
      			break read_data;  
      			// break out of readjata loop  
              }
          }  
      }
      
    • 事实上,可以将标签应用到任何语句中, 甚至可以应用到 if 语句或者块语句中

    • 注意, 只能跳出语句块,而不能跳入语句块。

  • continue 语句 : 越过了当前循环体的剩余部分, 立刻跳到循环首部

大数

Java 基本类型中整数和浮点数精度不可能能够满足需求,java.math 中的 Biglnteger 和 BigDecimal 这两个类可以处理任意长度序列的数值。

  • Biglnteger 类实现了任意精度的整数运算;

  • BigDecimal 实现了任意精度的浮点数运算。

  • 使用静态的 valueOf 方法可以将普通的数值转换为大数值

    • Biglnteger a = Biglnteger.valueOf(100) ;
  • 不能使用人们熟悉的算术运算符(如:+ 和*) 处理大数值,而是使用大数值中的add 和multiply 方法

    • Biglnteger c = a.add(b) ; // c = a + b
    • Biglnteger d = c.nul ti pi y(b.add(Biglnteger.val ueOf(2))); // d = c * (b + 2)
  • 大数不是 Java 基本数据类型,而是对象。

    与 C++ 不同,Java 没有提供运算符重载功能,程序员无法重定义+ 和 * 运算符

数组

声明和创建数组

  • 数组用来存储同一类型值的集合

  • 声明数组变量 : int[] a;

    • int[] a;
    • 以上这条语句只声明了变量a, 并没有将a 初始化为一个真正的数组

    Java 中 有两种声明数组的方式 : int[] a; 或 int a[];

    大多数 Java 应用程序员喜欢使用第一种风格,它将类型int[] ( 整型数组)与变量名分开了,更加清晰直观

  • 创建数组 : 使用 new 运算符创建数组

    • new int[n] 会创建一个长度为 n 的数组
  • 数组创建初始化

    • 使用 new 关键字创建一个数字数组时, 所有元素都初始化为 0;
    • boolean 数组的元素会初始化为 false;
    • 对象数组的元素则初始化为一个特殊值 null , 这表示这些元素(还)未存放任何对象。
  • 一旦创建了数组, 就不能再改变它的大小(但是可以改变数组中每个元素数值,这点不同于 Java 中的 String)

数组初始化和匿名数组

  • 创建数组的简写形式: int[] arr = {1, 3, 4};

    • 在使用这种语句时,不需要调用new
  • 创建匿名数组

    • new int[] {1, 2, 3};

    • 这会创建一个新数组并利用大括号中提供的值进行初始化。它会统计初始值个数,并相应地设置数组大小

      arr = new int {1, 2, 4}; // 本条语句是下面两条语句的简写形式
      						// 这里不能直接arr = {1, 2, 4}; 只有第一次创建数组时候能这样写,比如下面创建 temp 数组时
      
      // 等价于
      
      int[] temp = {1, 2, 4}
      arr = temp;
      
  • 长度为 0 的数组

    • 作用 : 在编写一个结果为数组的方法时,如果碰巧结果为空,此时可以创建一个长度为 0 的数组
    • 创建方式: new elementType[0] 或 new elementType[] {}

    注意:数组长度为 0 与 null 不同

数组拷贝

数组是引用类型变量,栈区存放对象的引用,堆区存放真正的数组中的数据

  • 数组浅拷贝:将一个数组变量拷贝给另一个数组变量

    • 这时, 两个变量将引用同一个数组*(只是拷贝了引用,一变则全变)*

      int[] luckyNumbers = smallPrimes;
      1uckyNumbers[S] = 12; // now smallPrimes[5] is also 12
      
  • 数组深拷贝:使用 Arrays 类的 copyOf 方法

    • 将一个数组的所有值拷贝到一个新的数组中去*(两个数组没什么关系,一个变另外一个不变)*

      int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length) ;
      
      // 第2 个参数是新数组的长度,如果长度大于当前数组长度,则剩余部分被创建初始化为默认值(int:0,boolean:false,对象:null);如果长度小于当前数组长度,只拷贝最前面的数据元素 
      

命令行参数

  • main 方法中的 String arg[],即为命令行参数
  • 如果使用下面这种形式运行这个程序
    • java Message -g cruel world

    • args 数组内容

      • args[0] : “-g”
      • args[1] : “cruel”
      • args[2] : “world”
    • Java 的 main 方法中,程序名并没有存储在 args 数组中

      • args[0] 是“ -h”, 而不是“ Message” 或“ java”

数组排序

  • 使用 Arrays 类中的 sort 方法
  • 这个方法使用了优化的快速排序算法
  • 时间复杂度:平均 O(n lgn)

多维数组

  • 二维数组

    • int[][] arr = {{1, 2}, {3, 4}};
  • Java 实际上没有多维数组, 只有一维数组

  • 多维数组被解释为“ 数组的数组”

  • “不规则” 数组 : 即数组的每一行有不同的长度

    • 创建一个矩阵是三角形的,第 i 行有 i + 1 个元素

      final int NMAX = 10;
      // allocate triangular array
      int[] [] odds = new int[NMAX + 1][]:
      for (int n = 0; n <= NMAX; n++)
      	odds[n] = new int[n + 1];
      

快速打印数组元素

  • 打印一维数组

    • 利用 Arrays 类中的 toString 方法
    • 调用 Arrays.toString(arr),返回一个包含数组元素的字符串
    int[] arr = {1, 2, 3};
    
    System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 3]
    
  • 打印二维数组

    • 利用 Arrays 类中的 deepToString 方法
    int[][] arr = {{1, 2}, {3, 4}};
    
    System.out.println(Arrays.deepToString(arr)); // 输出:[[1, 2], [3, 4]]
    

利用 for 和 foreach 也可达到效果,但是直接调用函数更快 (调包侠上线,哈哈哈…)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值