title: java 基本程序设计
tag: 核心卷知识
categories: Java基础
comment: 关于书籍知识总结
description: 描述
Java基本程序设计
数据类型
Java是一种强类型语言。必须为每一个变量声明一种类型。在Java中一共包括8种基本数据类型,其中4种整型、2种浮点类型、一种用于表示Unicode编码的字符单元的字符类型char和1种表示真值的boolean类型。
整型:![owr5W9.png](https://i-blog.csdnimg.cn/blog_migrate/af6da410e9875aecf7527f3e4bc232ec.png)
在Java中,整型的范围与运行Java代码的机器无关。
变量
变量初始化
声明一个变量后,必须使用赋值语句对变量的变化进行初始化,不能够使用未初始化的变量。
反例:
int vacationDays;
System.out.prtintln(vacationDays);
正例:
int vacationDays;
vacationDays = 12;
或者
int vacationDays = 12;
Java中可以将声明放在代码中的任何地方。变量的声明尽可能地靠近变量第一次使用的地方,这是一种良好的编程编写风格。
常量
java中通常使用final关键字修饰常量,final关键字表示这个变量只能被赋值一次,赋值之后就不能在修改了。习惯上我们将常量都是使用大写字母。
final double MONEY = 2.54
当我们希望某个常量可以在一个类中的多个方法中使用,此时将这些常量称为类常量。可以使用关键字static final 设置一个类常量。
static final double MONEY = 2.54
数学函数与常量
java中的平方根
double x = 4;
double y = Math.sqrt(x);
System.out.println(y);
强制类型转换
强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名:
double x = 9.997
int nx = (int) x;
自增与自减运算符
++n和n++;在表达式中是有区别的,前者是先完成加1,后者是先使用原来变量的值
int m = 7;
int n = 7;
int a = 2 * ++m;//16
int b = 2 * n++;//14
在表达式中一般不使用++,因为这样的代码会使人产生困扰。
括号与运算符级别
根据下表给出的运算符优先级次序进行计算,同一个级别的运算符按照从左到右的次序进行计算
枚举类型
有时候,变量的值只在一个有限的集合中。枚举类型包括有限个命名的值。
enum Size{SMALL,MEDIUM,LARGE,EXTRA_LARGE}
字符串
在标准Java类库中提供了一个预定义类,我们很自然地叫做String。每个用双括号括起来的字符串都是String类的一个实例。
子串
String类的substring方法可以从一个较大的字符串中提取出一个子串。
String greeting = "Hello";
String s = greeting.substring(0,3);//Hlo
substring方法的第二个参数是不想复制的第一个位置。这里需要复制的位置为0,1,2的字符。在substring中从0开始计数,直到3为止,但是不包含3.
字符串s.substring(a,b)的长度为b-a;
拼接
java语言支持使用+号连接两个字符串。
int age = 13;
String rating = "PG" + age;// "PG13"
将一个字符串与一个非字符串的值进行拼接时,后者会被转换成字符串。
检测字符串是否相等
可以使用equals方法检测两个字符串是否相等。
s.equals(t)
如果字符串s与字符串t相等,返回true,否则返回false.s与t可以是字符串变量,也可以是字符串字面量。下面的表达式也是合理的:
"Hello",equals(greeting)
如想检测两个字符串是否相等,而不区分大小写,可以使用equalsIgnoreCase方法。
"Hello".equalsIgnoreCase("Hello")
一定不要用==运算符检测两个字符串是否相等!这个运算符只能够确定两个字符串是否放置在同一个位置上。当然,放置在同一个位置上的它们必然相等,但是也完全有可能将内容的多个字符串的拷贝放置在不同的位置上。
空串与Null串
空串""是长度为0的字符串。可以运用以下代码检测一个字符串是否为空:
if(str.length() == 0)
或
if(str.equals(""))
空串是一个Java对象,有自己的串长度和内容。String变量中还可以存放一个特殊的值,名为null,这表示目前没有任何对象与该变量关联。要检测一个字符串是否为Nulll,可以运用以下:
if(str == null)
要检查一个字符串既不是null也不是空串,可以使用以下的条件:
if(str != null && str.length() != 0)
首先需要检查str不为null.
String API
java.lang.string类名中
char charAt(int index)
// 返回给定位置的代码单元
int codePointAt(int index)
// 返回从给定位置开始的码点
int offsetByCodePoints(int startIndex,int cpCount)
// 返回从startIndex开始,位移cpCount后的码点索引
int compareTo(String other)
// 按照字典顺序,如果字符串位于other之前,返回一个负数;如果字符串位于other之后,返回一个整数,如果两个字符串相等,返回0
IntStream codePoints()
// 将这个字符串的码点作为一个流返回。调用toArray将它们放在一个数组中。
new String(int[] codePoints,int offset,int count)
// 用数组中从offset开始的count个码点构造一个字符串
boolean equals(Object other)
// 如果字符串与other相等,返回true
boolean equalsIgnoreCase(String other)
// 如果字符串与other相等(忽略大小写),返回true
boolean startWith(String suffix)
boolean endsWith(String suffix)
// 如果字符串以suffix开头或结尾,则返回true.
int idnexOf(String str)
int indexOf(String str,int fromIndex)
int indexOf(int cp)
int indexOf(int cp,int fromIndex)
// 返回与字符串str或代码点cp匹配的第一个子串的开始位置。这个位置从索引0或fromIndex开始计算。如果原字符串中不存在str,则会返回-1.
int length()
// 返回字符串的长度
int codePointCount(int startIndex, int endIndex)
// 返回startIndex和endIndex-1之间的代码点数量。没有配成对的代用字符将计入代码点。
String replace(CharSequence oldString,CharSequence newString)
// 返回一个新字符串。这个字符串用newString代码原始字符串中所有的oldString.
String substring(int beginIndex)
String substring(int beginIndex,int endIndex)
// 返回一个新字符串。这个字符串包含原始字符串中从beginIndex到串尾或者endIndex-1的所有代码单元。
String trim()
// 返回一个新字符串。这个字符创将删除了原始字符串头部和尾部的空格。
构建字符串
有些时候,需要由较短的字符串构建字符串。采用字符串连接的方式达到此目的的效率比较低。每次拼接一个新的String对象,既耗时,又浪费空间,
使用StringBuilder类就可以避免这个问题发生。
首先,构建一个空的字符串构建器:
StringBuilder builder = new StringBuilder();
当每次需要添加一部分内容是,调用append方法。
builder.append(ch);
builder.append(str);
常用的API
StringBuilder()
// 构建一个空的字符串构建器
int length()
// 返回构建器或缓冲器的代码单元数量
StringBuilder append(String str)
// 追加一个字符串并返回this
StringBuilder append(char c)
// 追加一个代码单元并返回this
void setCharAt(int i,char c)
// 将第i个代码单元设置为c
StringBuilder insert(int offset,String str)
// 在offset位置插入一个字符串并返回this
StringBuilder insert(int offset,Char c)
// 在offset位置插入一个代码单元并返回this
StringBuilder delete(int startIndex,int endIndex)
// 删除偏移量从startIndex 到endIndex-1代码单元并返回this
String toString()
// 返回一个与构建器或缓冲器内容相同的字符串
输入输出
读取输入
要想通过控制台进行输入,首先需要构造一个Scanner对象,并与“标注输入流“System.in关联。
Scanner in = new Scanner(System.in);
利用Scanner类的各种方法实现输入操作,nextLine方法将输入一行,nextLine方法是因为在输入行中有可能包含空格。
String name = in.nextLine();
如果想要读取一个单词,以空白符为分隔符,就调用next方法
String firstName = in.next();
要想读取一个整数,就调用nextInt方法。
int age = in.nextInt();
Java.util.scanner API
Scanner (InputStream in) //用给定的输入流创建一个Scanner对象
String nextLine() // 读取输入的下一行内容
String next() // 读取输入的下一个单词(以空格为分隔符)
int nextInt()
double nextDouble
// 读取并转换下一个表示整数或浮点数的字符序列
boolean hasNext() // 检测输入中是否还有其他单词
boolean hasNextInt()
boolean hasNextDouble()
//检测是否还有表示整数或浮点数的下一个字符序列
文件输入与输出
要想对文件进程读取,就需要一个用File对象构造一个Scanner对象,如下所示:
Scanner in = new Scanner(Paths.get("myfile.txt"),"UTF-8");
要想写入文件,就需要构造一个PrintWriter对象,在构造器中,只需要提供文件名:
PrintWriter out = new PrintWriter("myfile.txt","UTF-8");
控制循环
与任何程序设计语言一样,Java使用条件语句和循环语句结构控制流程。
块作用域
块(即复合语句)是指由一对大括号括起来的若干条简单的Java语句。一个块可以嵌套在另一个块中。
public static void main(String[] args) {
int n;
{
int k;
}
}
但是,不能在嵌套的两个块中声明同名的变量。下面的代码就是错误的:
public static void main(String[] args) {
int n;
{
int k;
int n; // can't redefine n in inner block
}
}
条件语句
条件语句的格式为:
if(conditon) statement
条件语句中else子句与最邻近的if构成一组。
if(x <= 0)if(x == 0)sign = 0;else sign = -1;
此处的else与第2个if配对。
循环
当条件为true时,while循环执行一条语句。一般格式为
while(condition) statement
while循环语句首先检测循环条件。因此,循环体中的代码有可能不被执行。如果希望循环体至少执行一次,则应该将检测条件放在最后。使用do/while循环语句可以实现这种操作方式
do statement while(condition)
确定循环
for循环语句是支持迭代的一种通用结构,利用每次迭代之后更新的计数器或类型的变量来控制迭代次数。
for(int i =1; i <= 10; i++){
System.out.println(i);
}
for语句中的第1部分用于对计数器初始化;第2部分给出每次新一轮循环前执行前要检测的循环条件;第3部分指示如何更新计数器。
有一条不成文的规定:for语句的3个部分应该对同一个计数器变量进行初始化、检测和更新。
多重选择:switch语句
在处理多个选项时,使用if/else结构显得有些笨拙。
Scanner in = new Scanner(System.in);
in choice = in.nextInt();
switch(choice){
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
case 4:
...
break;
default:
...
break;
}
switch语句将从选项值相匹配的case标签处开始执行直到遇到break语句,或者执行到switch语句的结束处为止。如果没有相匹配的case标签,而又default子句,就执行这个子句。
case的标签可以是:
- 类型为char、byte、short或int的常量表达式
- 枚举常量
- 从JavaSE7 开始,case标签还可以是字符串字面量。
中断控制流程语句
与C++不同,Java还提供了一种带标签的break语句,用于跳出多重嵌套的循环语句。有时候,在嵌套很深的循环语句中会发生一些不可预料的事情。此时可能更加希望调到嵌套的所有循环语句之外。通过添加一些额外的条件判断实现各层循环的检测很不方便。
请注意,标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号。
如果输入有误,通过执行带标签的break跳转到带标签的语句块末尾。对于任何使用break语句的代码都需要检测循环正常结束,还是由break跳出。
还有一个continue语句。与break语句一样,它将中断正常的控制流程,continue语句将控制转移到最内层循环的首部。
Scanner in = new Scanner(System.in);
while( sum < goal){
n = in.nextInt();
if(n < 0)continue;
sum += n;
}
// 如果n<0,则continue语句超过了当前循环体的剩余部分,立刻跳到循环首部
如果将continue语句用于for循环中,就可以跳到for循环的“更新“部分。
for(count = 1; count <= 100;count++){
n = in.nextInt();
if(n < 0) continue;
sum += n;
}
// 如果n < 0,则continue语句跳到count++语句
大数值
如果基本的整数和浮点数精度不能满足需求,那么可以使用java.math包中的两个很有用的类:BigInteger和BigDecimal.这两个类可以处理包含任意长度数字序列的数值。BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点数运算。
使用静态的valueOf方法可以将普通的数值转换为大数值
BigInteger a = BigInteger.valueOf(100);
使用大数值类中的add和multiply方法。
BigInteger c = a.add(b);// c = a+b
BigInteger d = c.multiply(b.add(BigInteger.valueOf(2))); // d = c*(b+2)
数组
数组是一种数据结构,用来存储同一类型的集合。通过一个整型下标可以访问数组中的每一个值。
在声明数组变量时,需要指出数组类型(数组元素类型紧跟[])和数组变量的名字。
int[] a // 只声明了变量a,并没有将a初始化为一个真正的数组
int[] a = new int[100]; // 创建一个可以存储100个整数的数组。
使用for循环给数组赋值
int[] a = new int[100];
for(int i = 0; i < 100; i++){
a[i] = i;
}
// 创建一个数字数组时,所有元素都初始化为0。boolean数组的元素初始化为false.对象数组的元素则初始化为一个特殊值null,这表示这些元素还为存放任何对象。
for each循环
Java有一种功能很强的循环结构,可以用来依次处理数组中的每个元素而不必为指定下表值而分心。
增强for循环的语句格式为:
for(variable : collection)statement
// 定义一个变量用于暂存集合中的每一个元素,并执行相应的语句。collection这一集合表达式必须是一个数组或者是一个Iterable接口的类对象。
例:
for(int element : a){
System.out.println(element);
}
// 打印数组a的每一个元素,一个元素占一行
数组初始化以及匿名数组
在java中,提供了一种创建数组对象并同时赋予初始值的简化书写形式。下面是一个例子:
int[] a = {2,4,6,8,10}
// 在使用这种语句时,不需要调用new
new int[]{17,19,23,31,37}
// 初始化一个匿名的数组
a = new int[]{2,4,6,8,10}
// 可以在不创建新变量的情况下重写初始化一个数组
数组拷贝
在java中,允许将一个数组变量拷贝给另一个数组变量。
如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用Arrays类的copyOf方法:
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers,luckyNumber.length);
// 第2个参数是新数组的长度。
luckyNumbers = Arrays.copyOf(luckyNumbers,2*luckyNumbers.length);
// 如果数组元素是数值型,那么多余的元素将被赋值为0;如果数组元素是布尔型,则将赋值为false.相反,如果长度小于原始数组的长度,则只拷贝最前面的数据元素。
数组排序
可以使用Arrays类中的sort方法:
int[] a = new int[1000];
....
Arrays.sort(a)
// 这个方法使用了优化的快速排序算法。排序算法对于大多数数据集合来说都是效率比较高的。
例子:
public class Example {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int k = in.nextInt();
int n = in.nextInt();
// 创建一个数组用于存储所有元素
int[] numbers = new int[n];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = i+1;
}
// 运用第二个数组来存储抽取出来的值
int[] result = new int[k];
for (int i = 0; i < result.length; i++){
// 获取抽取的值
int r = (int) (Math.random()*n);
result[i] = numbers[r];
// 将最后一个元素移动到已经被抽取的元素处
numbers[r] = numbers[n-1];
n--;
}
// 对获取的数据进行排序
Arrays.sort(result);
for (int r:result) {
System.out.println(r);
}
}
}
API
static String toString(type[] a)
// 返回包含a中数据元素的字符串,这些数据元素被放在括号内,并于逗号分隔。
参数: a 类型为int、long、short、char、byte、boolean、float或double的数组
static type copyOf(type[] a,int length)
static type copyOfRange(type[] a,int start,int end)
// 返回与a类型相同的一个数组,其长度为length或者end-start,数组元素为a的值。
参数: a 类型为int、long、short、char、byte、boolean、float或double的数组
start 起始下标(包含这个值)
end 终止下标(不包含这个值),这个值有可能大a.length。这种情况下,结果为0或false.
length 拷贝的数据元素长度。如果length值大于a.length,结果为0或false;否则,数组中只有前面length个数据元素的拷贝值。
static void sort(type[] a)
// 采用优化的快速排序算法对数组进行排序
参数: a 类型为int、long、short、char、byte、boolean、float或double的数组
static int binarySearch(type[] a,type v)
static int binarySearch(type[] a,int start,int end, type v)
// 采用二分搜索算法查找值V。如果查找成功则返回相应的下标;否则,返回一个负数值r.
参数: a 类型为int、long、short、char、byte、boolean、float或double的数组
start 起始下标(包含这个值)
end 终止下标(不包含这个值)
v 同a的数据元素类型相同的值。
static void fill(type[] a,type v)
// 将数组的所有元素值设置为v
参数: a 类型为int、long、short、char、byte、boolean、float或double的数组
v 与a数据元素类型相同的一个值
static boolean equals(type[] a,type[] b)
// 如果两个数组大小相同,并且下标相同的元素都对应相等,返回true
参数a,b 类型为int、long、short、char、byte、boolean、float或double的数组
多维数组
在java中,声明一个二维数组很简单,如
double[][] balances;
与一维数组一样,在调用new 对多维数组进行初始化之前不能使用它。
balances = new double[n][n];
多维数组的初始化。
int[][] array ={
{16,3,2,13},
{5,10,11,8},
{9,6,7,12},
{4,15,14,1}
};
不规则数组
Java实际上没有多维数组,只有一维数组。多维数组被解释为“数组的数组“
表达式array[i]引用第i个子数组,也就是二维表的第i行。它本身也是一个数组,array[i][j]引用这个数组的第j项。
由于可以单独地存取数组的某一行,所以可以让两行交换
array[] temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
可以方便的创建一个不规则的数组,即数组的每一行有不同的长度。
想要创建一个不规则的数组,首先需要分配一个具有所含行数的数组
int[][] odds = new int[MAX + 1][];
接下来分配这些行
for(int n = 0; n <= MAX; n++)
odds[n] = new int[n + 1];
分配数组之后,假定没有超出边界,就可以采用通常的方式访问其中的元素了
for(int n = 0; n < odds.length; n++){
for(int k = 0; k < odds[n].length; k++){
....
odds[n][k] = lotterOdds;
}
}
11,8},
{9,6,7,12},
{4,15,14,1}
};
#### 不规则数组
Java实际上没有多维数组,只有一维数组。多维数组被解释为“数组的数组“
```java
表达式array[i]引用第i个子数组,也就是二维表的第i行。它本身也是一个数组,array[i][j]引用这个数组的第j项。
由于可以单独地存取数组的某一行,所以可以让两行交换
array[] temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
可以方便的创建一个不规则的数组,即数组的每一行有不同的长度。
想要创建一个不规则的数组,首先需要分配一个具有所含行数的数组
int[][] odds = new int[MAX + 1][];
接下来分配这些行
for(int n = 0; n <= MAX; n++)
odds[n] = new int[n + 1];
分配数组之后,假定没有超出边界,就可以采用通常的方式访问其中的元素了
for(int n = 0; n < odds.length; n++){
for(int k = 0; k < odds[n].length; k++){
....
odds[n][k] = lotterOdds;
}
}