第四章 数学函数、字符和字符串
4.1 引言
本章重点介绍数学函数、字符和字符串对象,并使用它们来开发程序。
4.2 常用数学函数
Java在Math类中提供了许多实用的方法,来计算常用的数学函数。
本节介绍Math类中其他的有用方法。这些方法分为三类:
三角函数方法(trigonometric method)、指数函数方法(exponent method)和服务方法(service method)。
服务方法包括取整、求最小值、求最大值求绝对值和随机方法。除了这些方法之外,Math类还提供了两个很有用的double型常量,PI(π)和E(自然对数的底)。可以在任意程序中用Math.PI和Math.E来使用这两个常量。
4.2.1 三角函数方法
下面是Java所提供的常用的三角函数方法:
4.2.2 指数函数方法
下面是Java所提供的常用的指数函数方法:
4.2.3 舍入方法
下面是Java所提供的常用的舍入(取整)方法:
4.2.4 min、max和abs方法
min
和max
方法用于返回两个数(int、long、float或double型)
的最小值和最大值。例如,max(4.4,5.0)
返回5.0
,而min(3,2)
返回2
。
abs方法以返回一个数(int、long、float或double型)
的绝对值。
4.2.5 random方法
random()
方法生成大于等于0.0且小于1.0的double型随机数(0.0<=Math.random()<1.0)
。
4.2.6 示例学习:计算三角形的角度
**需求:**输入三个点的坐标,求这三个点围成的三角形的角的度数。
思路:
1.读入三个点的坐标
2.计算三个点的边长
3.根据三角函数求三个角的度数
4.输出结果
具体实现:
package com.Javabook.Demo;
import java.util.Scanner;
public class P109_ComputeAngles {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//获取三个点的坐标
System.out.print("请输入第一个点的坐标(x, y): ");
double x1 = sc.nextDouble();
double y1 = sc.nextDouble();
System.out.print("请输入第二个点的坐标(x, y): ");
double x2 = sc.nextDouble();
double y2 = sc.nextDouble();
System.out.print("请输入第三个点的坐标(x, y): ");
double x3 = sc.nextDouble();
double y3 = sc.nextDouble();
//计算三角形三边边长
double a = Math.sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3));
double b = Math.sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3));
double c = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
// System.out.println(a + " " + b + " " + c);
//计算三角形三个角的角度
double A = Math.toDegrees(Math.acos((a * a - b * b - c * c) / (-2 * b * c)));
double B = Math.toDegrees(Math.acos((b * b - a * a - c * c) / (-2 * a * c)));
double C = Math.toDegrees(Math.acos((c * c - b * b - a * a) / (-2 * a * b)));
// System.out.println(A + " " + B + " " + C);
//打印结果
System.out.println("三角形三个角的角度分别为:"
+ Math.round(A * 100) / 100.0 + " "
+ Math.round(B * 100) / 100.0 + " "
+ Math.round(C * 100) / 100.0 + " ");
}
}
4.3 字符数据类型和操作
字符数据类型用于表示单个字符。
4.3.1 Unicode和ASCIII码
计算机内部使用二进制数。一个字符在计算机中是以0和1构成的序列的形式来存储的。将字符映射到它的二进制形式的过程称为编码(encoding)。字符有多种不同的编码方式,编码表(encoding scheme)定义该如何编码每个字符。
Java 支持 Unicode码。
大多数计算机采用ASCII(美国标准信息交换码),它是表示所有大小写字母、数字、标点符号和控制字符的8位编码表。Unicode码包括ASCII码,从'\u0000'
到'\u007F'
对应128个ASCII字符。
下面是常用字符的ASCII码和Unicode码:
Java程序中,可以使用像'X'
、'1'
和'$'
这样的ASCII字符,也可以使用Unicode码。
注意:自增和自减操作符也可用在char型变量上,得到该字符前一个或后一个Unicode字符。
4.3.2 特殊字符的转义序列
下面是一些常用的转义字符:
反斜杠\
被称为转义字符。它是一个特殊字符。要显示这个字符,需要使用转义序列\\
。
4.3.3 字符型数据与数值型数据之间的类型转换
char型数据可以转换成任意一种数值类型,反之亦然。
0~FFFF
的任何一个十六进制正整数都可以隐式地类型转换成字符型数据。而不在此范围内的任何其他数值都必须显式地转换为char型。
所有数值操作符都可以用在char型操作数上。如果另一个操作数是一个数字或字符那么char型操作数就会被自动转换成数字。如果另一个操作数是一个字符串,那么字符就与该字符串相连。
4.3.4 比较和测试字符
两个字符可以使用关系操作符进行比较,如同比较两个数字一样。这是通过比较两个字符的 Unicode 值实现的。
4.4 String类型
字符串是一个字符序列。
char 类型只表示一个字符。为了表示一串字符,可以使用称为String(字符串)的数据类型。
String实际上与System类和Scanner类一样,都是Java库中一个预定义的类。String类型不是基本类型,而是引用类型(reference type)。任何Java类都可以作为引用类型来声明一个变量。使用引用类型声明的变量称为引用变量,它引用一个对象。
下面列出String类的常用方法:
String是Java中的对象。表4-7中的方法只能从一个特定的字符串实例来调用。因此,这些方法称为实例方法。非实例方法称为静态方法。静态方法可以不使用对象来调用。定义在Math 类中的所有方法都是静态方法。它们没有绑定到一个特定的对象实例上。
例如Math.pow(2, 3)
就是一个非实例的方法(静态方法),没有具体的示例。
假如有一个字符串定义:String message = "Welcome to Java!"
,我们现在调用方法length()来求该字符串的长度。格式如下:message.length()
。显然,我们为length指定了一个具体的实例,而不能直接进行length()
操作。
4.4.1 获取字符串长度
可以调用字符串的length()
方法获取它的长度。例如下面的代码:
String message ="Welcome to Java";
System.out.printin("The length of " + message + " is " + message.length());
注意:使用一个字符串时,往往是知道它的字面值的。为方便起见,Java允许在不创建新变量的情况下,使用字符串字面值直接引用字符串。这样,"Welcome to Java".length()
是正确的,它返回15
。注意,""
表示空字符串,并且"".length()
为0
。
4.4.2 从字符串中获取字符
方法s.charAt(index)
可用于提取字符串s中的某个特定字符,其中下标index
的取值范围在0~s.length()-1
之间。例如,message.charAt(0)
返回字符W
。
警告:在字符串s中越界访问字符是一种常见的程序设计错误。为了避免此类错误,要确保使用的下标不会超过s.length()-1
。例如,s.charAt(s.length())
会造成一个StringIndex0utOfBoundsException
异常。
4.4.3 连接字符串
可以使用concat
方法连接两个字符串。例如,如下所示的语句将字符串s1
和s2
连接构成s3
:
String s3 = s1.concat(s2);
因为字符串连接在程序设计中应用非常广泛,所以Java提供了一种实现字符串连接的简便办法。可以使用加号(+
)连接两个或多个字符串。因此,上面的语句等价于:
String s3 = s1 + s2;
4.4.4 转换宇符串
方法toLowerCase()
返回一个所有字母为小写的新字符串方法toUpperCase()
返回一个所有字母为大写的新字符串。
例如:
"Welcome".toLowerCase()
返回一个新字符串welcome
。
"Welcome".toUpperCase()
返回一个新字符串WELCOME
。
4.4.5 从控制台读取字符串
为了从控制台读取字符串,可以调用Scanner对象上的next()
方法。
next()
方法读取以空白字符结束的字符串(即'\r'
或'\n'
)。可以使用nextLine()
方法读取一整行文本。nextLine()
方法读取以按下回车键
为结束标志的字符串。
简便起见,我们将使用方法next()
、nextByte()
、nextShort()
、nextInt()
、nextLong()
、nextFloat()
和nextDouble()
的输入称为基于标记的输入,因为它们读取采用空白字符
分隔的单个元素,而不是读取整行。nextLine()
方法称为基于行的输入。
为了避免输入错误,程序中不要在基于标记的输入之后使用基于行的输入。
4.4.6 从控制台读取字符
为了从控制台读取字符,调用nextLine()
方法读取一个字符串,然后在字符串上调用charAt(0)
来返回一个字符。
4.4.7 字符串比较
下面是常用的字符串比较方法:
请注意:操作符==
只能检测string1
和string2
是否指向同一个对象,但它不会告诉你它们的内容是否相同。因此,不能使==
操作符判断两个字符串变量的内容是否相同。取而代之,应该使用equals
方法。
4.4.8 获得子字符串
方法s.charAt(index)
可用于提取字符串s
中的某个特定字符。也可以使用String
类中的substring
方法(见图4-2)从字符串中提取子串,如表4-9所示。
注意:如果beginIndex
为endIndex
,substring(beginIndex,endIndex)
返回一个长度为0
的空字符串。如果beginIndex>endIndex
,将发生运行时错误。
4.4.9 查找字符串中的字符或者子串
String
类提供了几个版本的indexOf
和lastIndexOf
方法,它们可以在字符串中找出一个字符或一个子串,如表 4-10所示。
4.4.10 字符串和数值间的转换
可以将数值型字符串转换为数值。要将字符串转换为int
值,使用Integer.parseInt
方法,如下所示:
int intValue = Integer.parseInt(intString);
要将字符串转换为double
值,使用Double.parseDouble
方法,如下所示:
double doubleValue = Double.parseDouble(doubleString);
可以将数值转换为字符串,只需要简单使用字符串的连接操作符,如下所示:
String s = number + "";
4.5 示例学习
4.5.1 猜测生日
**需求:**可以通过询问朋友5个问题,找到他出生在一个月的哪一天。每个问题都询问生日是否在5个数字集合中。
生日是包含了这一天的集合的第一个数字的和。例如:如果生日是19,那么它会出现在集合1、集合2和集合5中。这三个集合的第一个数字分别是1、2和16。它们的和就是19。
**思路:**这个游戏是很容易编程的。你可能想知道如何创建这个游戏。实际上,这个游戏背后的数学知识是非常简单的。这些数字不是随意组成一组的。它们放在5个集合中的方式是经过深思熟虑的。这5个集合的第一个数分别是1、2、4、8和16,它们分别对应二进制数的1、10、100、1000和10000(二进制数在附录F中介绍)。从1到31的十进制数最多用5个二进制数就可以表示,如图4-3a所示。假设它是 b 5 b 4 b 3 b 2 b 1 b_5b_4b_3b_2b_1 b5b4b3b2b1,那么$b_5b_4b_3b_2b_1 = b_50000+b_4000+b_300+b_20+b1,,如图4-3b所示。如果某天的二进制数在b_k位为数1,那么该数就该出现在Setk中。例如:数字19的二进制形式是10011,所以它就该出现在集合1、集合2和集合5中。它就是二进制数 1+10+10000=10011或者十进制数1+2+16=19。数字31的二进制形式是11111,所以它就会出现在集合1、集合2、集合3、集合4和集合5中。它就是二进制数1+10+100+1000+10000=11111,或者十进制数1+2+4+8+16=31。
具体实现:
package com.Javabook.Demo;
import java.util.Scanner;
public class P125_GuessBirthday {
public static void main(String[] args) {
String set1 =
"1 3 5 7\n"
+ "9 11 13 15\n"
+ "17 19 21 23\n"
+ "25 27 29 31";
String set2 =
"2 3 6 7\n"
+ "10 11 14 15\n"
+ "18 19 22 23\n"
+ "26 27 30 31";
String set3 =
"4 5 6 7\n"
+ "12 13 14 15\n"
+ "20 21 22 23\n"
+ "28 29 30 31";
String set4 =
"8 9 10 11\n"
+ "12 13 14 15\n"
+ "24 25 26 27\n"
+ "28 29 30 31";
String set5 =
"16 17 18 19\n"
+ "20 21 22 23\n"
+ "24 25 26 27\n"
+ "28 29 30 31";
int day = 0;
//创建Scanner
Scanner sc = new Scanner(System.in);
//answer表示用户回答的答案
int answer;
//提示用户回答问题
System.out.print("你的生日在Set1中吗?\n");
System.out.print(set1);
System.out.print("\n请输入0(否)或者1(是):");
answer = sc.nextInt();
if (answer == 1) {
day += 1;
}
//提示用户回答问题
System.out.print("你的生日在Set2中吗?\n");
System.out.print(set2);
System.out.print("\n请输入0(否)或者1(是):");
answer = sc.nextInt();
if (answer == 1) {
day += 2;
}
//提示用户回答问题
System.out.print("你的生日在Set3中吗?\n");
System.out.print(set3);
System.out.print("\n请输入0(否)或者1(是):");
answer = sc.nextInt();
if (answer == 1) {
day += 4;
}
//提示用户回答问题
System.out.print("你的生日在Set4中吗?\n");
System.out.print(set4);
System.out.print("\n请输入0(否)或者1(是):");
answer = sc.nextInt();
if (answer == 1) {
day += 8;
}
//提示用户回答问题
System.out.print("你的生日在Set5中吗?\n");
System.out.print(set5);
System.out.print("\n请输入0(否)或者1(是):");
answer = sc.nextInt();
if (answer == 1) {
day += 16;
}
System.out.println("\n你的生日是 " + day + "!");
}
}
4.6 格式化控制台输出
可以使用System.out.printf
方法在控制台上显示格式化输出。
printf中的f代表格式(format),表示方法将以某种格式来打印。调用这个方法的语法是:
System.out.printf(format,item1,item2,...,itemk);
这里的format是一个由子串和格式限定符构成的字符串。
格式限定符指定每项应该如何显示。这里的项可以是数值、字符、布尔值或字符串。简单的格式标识符是以百分号(%)开头的转换码。表4-11列出了一些常用的简单格式限定符:
所有项必须在顺序、数量和类型上与格式限定符相匹配。例如:count的格式标识符应该是%d
,而 amount的格式标识符应该是%f
。默认情况下,浮点值显示小数点后6
位数字。可以在标识符中指定宽度和精度,如表4-12中的例子所示。