JAVA的基本程序设计结构(下)
- 字符串
- Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类,叫做 String。
-
String e=""; //an empty String String greeting="hello"; //每个双引号括起来的字符串都是String类的一个实例
-
子串
-
String 类的substring方法可以从一个较大的字符串提取出一个子串。String substring(int beginIndex,int endIndex)
-
String greeting="Hello"; String s=greeting.substring(0,3); //从0开始计数,直到3为止,但不包含3 结果:s="Hel";
-
substring有一个优点:容易计算子串的长度。s.substring(a,b)的长度为b-a 例如,子串"Hel"的长度为3-0=3
-
-
拼接(+号拼接两个字符串)
-
String a="Hello "; String b="World!"; String c=a+b; //结果 c="Hello World!";
-
当一个字符串与一个非字符串的值进行拼接时,后者会转换成字符串
-
int age=13; String rating="PG"+age; //结果 rating="PG13";
-
这种特性通常用在输出语句中。例如:System.out.println("The answer is"+answer);
-
-
如果需要把多个字符串放在一起,用一个界定符分隔,使用静态join方法。
-
String all=String.join("/","S","M","L","XL"); //结果 all="S / M / L / XL";
-
-
Java11,提供 一个repeat方法
-
String repeated="Hello".repeat(3); //结果 repeated="HelloHelloHello";
-
-
- 不可变字符串
- String 类没有提供修改字符串中某个字符的方法,可以提取想要保留的子串,再与希望替换的字符拼接
-
greeting=greeting.substring(0,3)+"p!"; //结果 greeting="HelP!"
-
-
由于不能修改Java字符串中的单个字符,所以在Java文档中将String类对象称为是不可变的。
-
不可变字符串有一个优点,编译器可以让字符串共享。
-
- String 类没有提供修改字符串中某个字符的方法,可以提取想要保留的子串,再与希望替换的字符拼接
-
检测字符串是否相等 boolean equals(Object other)
-
s.equals(t) //s与t可以是字符串变量,也可以字符串字面量 例如:s.equals("hello")
-
不区分大小写,检测两个字符串是否相等。使用 boolean equalsIgnoreCase(String other)
-
"Hello".equalsIgnoreCase("hello");
-
-
使用 == 运算符检测两个字符串是否相等时,注意两个字符串是否存放在同一个位置上。
-
+ 或 substring等操作得到的字符串并不共享,不可以使用==运算符检测
-
-
-
空串与Null串
-
String str=""; //空串有自己的串长度(0)和内容(空)
if(str.length()==0) 或 if(str.equals("")) //检查一个字符串是否为空 -
String str=null; //表示目前没有任何对象与该变量关联
if(str==null) 或 if(str !=null && str.length()!=0) //检查一个字符串是否为null
-
-
码点与代码单元
-
Java字符串有char值序列组成,char数据类型是一个采用UTF-16编码表示Unicode码点的代码单元
-
String greeting="Hello"; int n=greeting.length(); //length()方法返回采用UTF-16编码表示给定字符串所需要的代码单元数量 int cpCount=greeting.codePointCount(0,greeting.length()); //int codePointCount(int startIndex,int endInex)
实际的长度,即码点数量 -
char charAt(int index) 将返回位置index的代码单元,index 介于 0 ~ length() - 1 之间
-
char first=greeting.charAt(0); //结果 first="H"; 注:除非对底层的代码单元感兴趣,否则不需要调用这个方法
-
-
-
String API(Application Programming Interface,应用编程接口)
-
API是一些预先定义的函数,用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。
- Java 中的 String 类包含了50多个方法,例如:
-
String join(CharSequence delimiter,CharSequence...elements); //返回一个新字符串,用给定的定界符连接所有元素
-
CharSequence是一种接口类型,所有字符串都属于这个接口。一个 CharSequence形参(parameter),完全可以传入 String类型的实参(argument)
-
-
- 阅读联机API文档
-
在标准库中有几千个类,方法数量惊人。因此,学会使用联机 API文档,从中可以查阅标准类库中的所有类和方法。
- 可以从Oracle下载 API文档,也可以在浏览器访问 http://docs.oracle.com/javase/8/docs/api 在线查看
-
- 构建字符串(StringBuilder 类)
-
StringBuilder builder=new StringBuilder(); //构建一个空的字符串构建器 builder.append(ch); //添加内容,调用append方法 String commpletedString=builder.toString(); //调用toString方法,将得到一个String对象,其中包含了构建器中字符的字符序列。
-
StringBuilder 类的前身是StringBuffer,它的效率稍有些低,但允许采用多线程的方式添加或删除字符。通常字符串编辑操作都在单个线程中执行。
-
-
输入与输出
-
读取输入
-
import java.util.*; //Scanner 类定义在 java.util包中。当使用的类不是定义在基本 java.lang包中时,都要使用import指令导入相应的包。
...
Scanner in=new Scanner(System.in); //构造一个与"标准输入流" System.in关联的 Scanner对象 System.out.println("What is you name? "); String name=in.nextLine(); //nextLine 方法读取一行输入 String firstName=in.next(); //读取一个单词,以空白符作为分隔符 System.out.println("How old are you? "); int num=in.nextInt(); //读取一个整数 -
由于输入是可见的,Scanner类不适用于从控制台读取密码
-
Console cons=System.console(); //Java6 特别引入了Console类来实现这个目的 String username=cons.readLine("User name:"); char[] passwd=cons.readPassword("Password:"); //为了安全起见,返回的密码存放在一个字符数组中,而不是字符串中。
-
-
-
格式化输出
-
double x=10000.0/3.0;
System.out.print(x); //将以x的类型所允许的最大非0数位个数打印输出x 如果希望显示美元,美分数,这就会有问题
System.out.printf("%8.2f",x); //包括8个字符,精度为小数点后2个字符。会打印一个前导的空格和7个字符,如:3333.33 -
可以为 printf 提供多个参数,例如:
-
System.out.printf("Hello,%s.Next year,you'll be %d",name,age); //结果 Hello,changm.Next year,you'll be 23
-
%格式说明符会用相应的参数替换,%紧跟着的转换符指示要格式化的数值类型
-
用于 printf 的转换符 转换符 类型 示例 转换符 类型 示例 d 十进制整数 159 s 字符串 Hello x 十六进制整数 9f c 字符 H o 八进制整数 237 b 布尔 true f 定点浮点数 15.9 h 散列码 42628b2 e 指数浮点数 1.59e+0.1 tx 或 Tx 日期时间(T 强制大写) 已经过时,应当改为使用
java.time类
g 通用浮点数(e和f中
较短的一个)
— % 百分号 % a 十六进制浮点数 0x1.fccdp3 n 与平台有关的行分隔符 —
-
-
-
文件输入与输出
-
要想读取一个文件,需要构造一个Scanner对象
-
Scanner in=new Scanner(Path.of("myfile.txt"),StandardCharsets.UTF_8); //Path.of 方法是Java11中加入的方法
-
-
- 如果文件名中包含反斜杠符号,就要在每个反斜杠之前再加一个额外的反斜杠转义:”c:\\mydirectory\\myfile.txt“
-
要想写入一个文件,需要构造一个PrintWriter对象
-
PrintWriter out=new PrintWriter("myfile.txt",StandardCharsets.UTF_8); //如果文件不存在,创建该文件。可以像输出到
System.out一样使用print、println以及printf命令
-
-
启动目录是命令解释器的当前目录
-
String dir=System.getProperty("user.dir"); //获取启动目录的位置
-
-
如果用一个不存在的文件构造Scanner,或者用一个无法创建的文件名构造PrintWriter,就会产生异常。Java编译器认为这些异常比”被零除“异常更严重
-
public static void main(String[] args) throws IOException{ //在main方法中用throws子句标记
-
-
-
-
控制流程
-
与任何程序设计语言一样,Java使用条件语句和循环结构确定控制流程
-
块作用域(一对大括号括起来的若干条Java语句)
-
public static void main(String [] args){ int n; { int n; //Error——不能在嵌套的两个块中声明同名的变量 } }
-
-
条件语句
-
if(条件语句)Java语句1 if(条件语句)语句语句1 else Java语句2 //条件语句为true,执行Java语句1;否则执行Java语句2 if(条件语句){ Java语句1 }else{ Java语句2 } if(条件语句1){ //哪个条件语句为ture,执行哪个块里面的Java语句。条件语句都为false,执行Java语句4 Java语句1 }else if(条件语句2){ Java语句2 }else if(条件语句3){ Java语句3 }else{ Java语句4 }
-
-
循环
-
while(条件语句)Java语句 while(条件语句){ Java语句 //条件语句为true,while循环执行Java语句;否则,条件语句为false,while循环一次也不执行 } do{ Java语句 //先执行Java语句,再检测条件语句。如果为true,重复执行Java语句,直到条件语句为false为止 }while(条件语句);
-
-
确定循环
-
for循环语句是支持迭代的一种通用结构,由一个计数器或类似的变量控制迭代次数,每次迭代后这个变量将会更新
-
for(int i=1;i<=10;i++) //第1部分通常是对计数器初始化;第2部分给出每次新一轮循环执行前要检测的循环条件;第3部分指定如何更新计数器 System.out.println(i); //for循环语句的3个部分应该对同一个计数器变量进行初始化、检测和更新
-
在循环中,检测两个浮点数是否相等需要格外小心。
-
for(double i=1;i!=10;i+=0.1) { //由于舍入的误差,可能永远达不到精确的最终值 System.out.println(i); //因为0.1无法精确地用二进制表示 }
-
int i; for(i=1;i<=10;i++){ //for语句中第1部分声明的变量,其作用域只扩展到这个for循环体的末尾
... //若希望在for循环体外使用循环体计数器的最终值,需要在这个循环体外声明变量
}
-
-
多重选择:switch语句
-
@SuppressWarnings("fallthrough")//如果没有break;就会执行下一个case分支,有可能触发多个case分支。加入注解,就不会对这个方法生成警告了
switch (choice) {
case 1: //switch语句将从与选项值匹配的case标签开始执行,break;跳出switch语句
Java语句
break;
case 2:
Java语句
break;
default: //没有相匹配的case标签,而有default子句,执行default
break;
} //注解是为编译器或处理Java源文件或类文件的工具提供信息的一种机制 -
case标签可以是:
-
类型为 char、byte、short 或 int 的常量表达式
-
枚举变量
-
Java7开始,还可以是字符串字面量
-
-
-
中断控制流程的语句
-
break;也可以用于退出循环语句
-
跳出多重嵌套的循环语句
-
read_data:while (. . .) { //创建一个标签并放在需要跳出的最外层循环之前,且紧跟一个冒号 . . . for (. . .) { . . . if(n<0) break read_data; //可以将该标签跳出循环的形式应用到任何语句 . . . } }
-
continue;越过当前循环体的剩余部分,跳到循环首部
-
-
-
-
大数
-
基本的整数和浮点数精度不能够满足要求,使用Java.math包中两个类:BigInteger 和 BigDecimal
-
BigInteger a=BigInteger.valueOf(100); //BigInteger类实现任意精度的整数运算,valueOf方法可以将普通的数值转换为大数
BigInteger reallyBig=new BigInteger("22221548456466416"); //对于更大的数,可以使用一个带字符串参数的构造器
BigInteger c=a.add(b); //c=a+b
BigInteger d=c.multiply(b.add(BigInteger.valueOf(2))); //d=c*(b+2)
-
-
数组
-
数组是一种数据结构,用来存储同一类型值的集合
-
int []b=new int[100]; //声明并初始化了一个可以存储100个整数的数组。一旦创建了数组,就不能再改变它的长度。(可以改变单个的数组元素)
若程序运行中需要经常扩展数组的大小,就使用另一种数据结构——数组列表(array list) -
创建数组对象并同时提供初始值的简写形式
-
int []smallPrimes= {2,3,5,7,11,17}; //不需要使用new,不用指定长度
-
-
访问数组元素
-
循环在数组中填入元素
-
int []a=new int[100]; for(int i=0;i<100;i++) { a[i]=i; }
- 创建一个数组时,所有元素都初始化为0。boolean数组的元素会初始化为false。对象数组的元素则初始化为一个特殊值null,表示这些元素还(未)存放 任何对象
- 可以使用array.length获得数组中的元素个数
-
for(int i=9;i<a.length;i++) //如果创建了一个100个元素的数组,并且访问元素a[100](或在0~99之外的任何下标) System.out.println(a[i]); 就会引发"array index out of bounds"异常
-
- for each循环
- 可以用来依次处理数组(或其他元素集合)中的每个元素,而不必考虑指定下标
-
for(数据类型 变量:数据对象) //增强的for循环的语句格式 for(int element:a) //它定义一个变量用于暂存集合中的每一个元素,并执行相应的语句,
该集合表达式必须是一个数组或是实现了Iterable接口的类对象(例如 ArrayList)
System.out.println(element); //打印a的每一个元素(循环a中的每一个元素) -
使用传统的for循环也可以获得同样的效果
-
for(int i=0;i<a.length;i++) //注释:for each循环语句的循环变量将会遍历数组中的每个元素,而不是下标值 System.out.println(a[i]);
-
Arrays类的 toString方法也可以打印数组中的所有值
-
System.out.println(Arrays.toString(a)); //返回一个包含数组元素的字符串 结果,"[2,3,5,7,11,13]"
-
数组拷贝
-
将一个数组变量拷贝到另一个数组变量
-
int[] luckyNumbers=smallPrimes; luckyNumbers[5]=12; //结果,smallPrimes[5]=12;
-
将一个数组的所有值拷贝到一个新的数组中去,使用 Arrays类的 copyOf方法
-
int[] copiedLuckyNumbers=Arrays.copyOf(luckyNumbers,luckyNumbers.length);
//第二个参数是新数组的长度。这个方法通常用来增加数组的大小
luckyNumbers=Arrays.copyOf(luckyNumbers,2*luckyNumbers.length); //如果数组元素是数值型,那么额外的元素将被赋值为0;如果数组元素
是布尔型,则将赋值为false。相反,如果长度小于原始数组的长度,则只拷贝当前的值
-
-
数组排序
-
对数值型数组进行排序,可以使用 Arrays类中的 sort方法
-
int[] a={1,6,2,8,3,9}; Arrays.sort(a); //这个方法使用了优化的快速排序(QuickSort)算法。该算法对于大多数数据集合来说都是效率比较高的
-
-
多维数组
-
多维数组将使用多个下标访问数组元素,它适用于表示表格或更加复杂的排列形式
-
double[] [] balances; //声明一个二维数组(也成为矩阵) balances=new double[10][6]; //数组进行初始化之前不能使用 int[][] magicSquare={ //直接声明并初始化,就可以不调用new {16,3,2,13}, {5,10,11,8}, //数组初始化后,就可以利用两个中括号访问各个元素,例如,magicSquare[i][j] {9,6,7,12} };
-
for each循环语句不能自动处理二维数组的每一个元素。需要使用两个嵌套的循环
-
for(double[] row:a){ //他会循环处理行,而这些行本身就是一维数组 for(double value:row){ System.out.println(value); } }
-
想要快速的打印一个二维数组的数据元素列表,可以调用:
-
System.out.println(Arrays.deepToString(a)); //输除格式为:[[16,3,2,13],[5,10,11,8],[9,6,7,12]]
-
-
不规则数组
-
Java实际上没有多维数组,只有一维数组。多维数组被解释为"数组的数组"。
-
表达式 balances[i]引用第i个子数组,也就是表格第 i行。它本身也是一个数组,balances[i][j]引用这个数组的第 j个元素
-
doublep[] temp=balances[i]; //由于可以单独地访问数组的某一行,所以可以让两行交换 balances[i]=balances[i+1]; balances[i+1]=temp;
-