Java-基本操作
Java核心
1. Java程序设计概述
略
2. Java程序设计环境
编译和运行
javac hello.java
// javac程序是一个java编译器
// 编译创建的java文件,如果有错误,则会编译不通过
// 会生成class文件
java hello
// java程序用于启动java虚拟机
// 运行生成的class文件,注意此时不再需要带扩展名
当然也可以使用集成开发环境来进行编译和运行
3. Java的基本程序设计结构
程序的一般形式
public class Hello{
public static void main(String[] args){
System.out.println("Hello");
}
}
// public称为访问修饰符,控制其他程序对该代码块的访问级别
// class表示程序中的全部内容都包含在类中
// 类名以大写开始,多个单词首字母大写
// 在类的源文件中必须包含一个main方法,也可以将用户自定义的方法添加到类中,然后在main方法中调用
// 一个代码块(由{}进行标记)包含多个语句(使用;来进行标记)
// 打印时调用了System.out对象的println方法,此处点号表示调用方法
// 格式如同object.method(parameters)
注释
// 单行注释
/* 多行注释 */
/** 多行注释,可以自动生成文档 */
数据类型
- 整型,表示没有小数部分的数值,允许是负数
类型 | 存储需求 | 取值范围 | 有效位数
- | - | -
int | 4 | - 2147483648 ~ 2147483647 (20亿级) | 9 ~ 10位
short | 2 | -32768 ~ 32767 (万级) | 4 ~ 5位
long | 8 | 很大 | 18 ~ 19位
byte | 1 | -128 ~127 (百级) | 2 ~ 3位
对于int,定义4个字节为32位,就有2的32次方种选择(包括正负)
主要是两个区间 - 2147483648 ~ - 1 和 0 ~ 2147483647
0一般是包含在正数这个区间
对于short,定义2个字节为16位,就有2的16次方种选择(包括正负)
主要是两个区间 -32768 ~ -1 和 0 ~ 32767
后面的依次类推即可
long类型需要在后侧添加L符号
- 浮点类型,表示有小数部分的数值
类型 | 存储需求 | 取值范围 | 有效位数
- | - | - | -
float | 4 | | 6~7位
double | 8 | | 15位
float类型有一个后缀F
if (x == Double.NaN)
// 件始终无法成立,因为所有非数值的值都认为是不相同的
if (Double.isNaN(x))
// 使用函数的形式来进行检查
- char类型,需要使用单引号括起来
可以表示一些字母以及特殊符号
其同样可以表示为16进制的值,范围从\u0000到\Uffff,也就是常说的unicode值
转义序列 | 名称 | Unicode值
- | - | -
\b | 退格 | \u0008
\t | 制表 | \u0009
\n | 换行 | \u000a
\r | 回车 | \u000d
" | 双引号 | \u0022
' | 单引号 | \u0027
\ | 反斜杠 | \u005c'
'A'是一个编码值为65所对应的字符常量
“A”是包含一个字符A的字符串
尽量不要使用char类型,而是使用字符串来进行代替
- boolean类型有两个值,false和true,用来判定逻辑条件
需要注意到,整型值和布尔值之间不能互换
变量
每个变量都具有一个type,并且需要进行显式初始化
double selectedItem; // 变量声明
selectedItem = 100; // 变量初始化
常量
即不可更改的量
使用final关键字来指示常量
final double SelectedItem = 100;
// 表示此变量赋值为100且不可更改,即为常量
// 常量名一般全部为大写
类常量
此常量可以在一个类的多个方法中使用
public class Constants{
public static final double SelectedItem1 = 100:
// 可以在多个类中使用,因为其被声明为public
public static void main(String[] args){
final double SelectedItem2 = 100:
// 只能在main这个类中使用
}
}
运算符
对于除法/,参与的两个都是整数,则为整数除法,否则就是小数除法
整数除以0将产生异常,浮点数除以0将会得到无穷大或者NaN
数学函数
double x = 4
double y = Math.sqrt(x) // 进行求平方根的运算
double z = Math.pow(x,3) // 求三次方
其他的数学函数及常量
Math.sin
Math.cos
Math.tan
Math.atan
Math.exp
Math.log
Math.log10
Math.PI
Math.E
数值转换
可能导致精度损失的转换(注意是可能,与数值本身大小有关)
int(4字节) --> float(4字节)
// 字节相同,但是编码方式不同,所以有效位数不同
// 因为int为9到10位,而float为6~7位,所以int在达到8位时,在转换为float时即会发生精度损失
long(8字节) --> float(4字节)
// 因为long可以达到19为,而float为6~7位,所以转换时极有可能出现精度损失
long(8字节) --> double(8字节)
// 同理,double最高只能到15位,所以转换时也可能出现精度损失
其他类型的高字节向低字节的转换都有可能出现精度损失
二元计算中的自动类型提升(转换为同一类型再进行计算)
- 如果,有一个为double,另一个也会变为double再进行计算
- 否则,有一个为float,另一个转换为float再进行计算
- 否则,有一个为long,另一个转换为long再进行计算
- 如果以上都不是,两个都转换为int进行计算
强制类型转换
double x = 9.997;
int nx = (int) x; // 值为9,其为直接进行截断
int nx = (int) Math.round(x); // 值为10,使用了四舍五入
如果试图将一个数值从一个类型转换为另一种类型,而又超出了目标类型的表示范围,结果会截断成一个完全不同的值
结合赋值
x += 4; // 结合赋值
int x = 5;
x += 3.5;
// 与(int)(x+3.5)相同,x先被转换为float进行计算,然后再使用int进行转换
// 可以看出,结合运算符并不允许原类型被改变
自增和自减
int a = 2 * ++m // 运算之前即自增
int b = 2 * n++ // 运算之后即自增
布尔运算
3 == 7;
3 !- 7;
3 < 7;
3 > 7;
(3 < 7) && (3 > 7);
(3 < 7) || (3 > 7);
// 交并计算中,最好对条件加上括号同时注意可能发生的短路
位运算符
- & 位与:意味着0会将原值替换为0(替换特定位为0),1会直接取原值(取特定位)
3&5
// 0000 0011 & 0000 0101 = 0000 0001,因此 3&5 的值得1
0000 0011 & 0000 0000
// 0000 0000
// 对0000 0011进行清零
0000 0011 & 0000 1111
// 0000 0011
// 取0000 0011的低四位
if ((a & 1) == 0)
// 此处的a为二进制数,直接判断其最后一位即可判断奇偶
- | 位或:意味着0直接取原值(取特定位),1会将原值替换为1(替换特定位为1)
1010 1110 | 0000 1111
// 1010 1111
// 因为0在或运算中不改变原值,使用1可以将某些位直接替换为1
// 常用来对一个数据的某些位设置为1
- ^ 异或:相同为0,相异为1,意味着0直接取原值(取特定位),1会将原值进行反转(替换特定位为反值)
1010 1110 ^ 0000 1111
// 1010 0001
// 反转特定位
a ^= b;
b ^= a;
a ^= b;
// ?????
- ~取反
a & ~1
// ~1的值为 1111 1111 1111 1110
// 使最低为为0
- << 左移运算符:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)
若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2
a=1010 1110
a = a << 2
// a=1011 1000
- >> 右移运算符:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃
操作数每右移一位,相当于该数除以2
a= a >> 2
运算优先级
运算符 | 结合性
- | -
[] . ()(方法调用) | 从左向右
! ~ ++ -- + (一元运算) - (一元运算) () (强制类型转换)new | 从右到左
- / % | 从左到右
-
- | 从左到右
<< >> >>> | 从左向右
< <= > >= | 从左向右
== != | 从左向右
& | 从左向右
^ | 从左向右
| | 从左向右
&& | 从左向右
|| | 从左向右
?: | 从右向左
= += -= *= /= %= &= |= ^= <<= >>= >>>= | 从右向左
- | 从左到右
字符串
Java中没有内置的字符串类型,而是直接提供了一个标准类,称之为String
String e = "";
String greeting = "Hello" \\ 产生了一个字符串对象
String s = greeting.substring(0,3); \\ 此时接收的结果就是Hel,类似于切片的形式
String a = "aa";
String b = "bb";
String ab = a + b;
// 此时字符串之间完成拼接就构成了字符串
// 当将一个字符串与另一个字符串的值进行拼接时,后者会被转化为字符串
// 一般来说,任何一个java对象都可以转换为字符串
int answer = 13;
System.out.println("the answer is" + answer);
// 可以利用这个特点直接进行输出
String all = String.join("\","1","2");
// 输出1\2
// 注意此时使用的是String类的静态join方法
字符串的修改
在java中,String类对象称为不可变字符串
String greeting = "Hello";
greeting = greeting.substring(0,3) + "p";
// Help
// 字符串为不可变对象,表示greeting这个字符串变量引用的字符串是不可更改的
// 如果想要更改,可以更换字符串变量greeting引用的字符串
// 但是要注意,此时存储池中就有两个字符串,分别是Hello和Help
s.equals(t)
// 表达式,返回布尔值,用于验证是否相等
s == t
// 这种方式比对的字符串的存储位置是否一致,但是可能存在内容一样,但位置不同的字符串
""为一个长度为0的字符串,其串长度为(0),内容(空)
str.length() == 0;
str.equals("");
// 返回布尔值
字符串的内容也可以为null,表示没有任何对象与该变量相关联
str == null;
// 返回布尔值
if (str != null && str.length() != 0)
// 应该首先检查null,因为null调用方法会进行报错
编码(补充)
0×20以下的字节状态称为”控制码”,不打印内容,而是控制状态或者格式
把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号此为,ANSI 的ASCII编码
GB2312 是对 ASCII 的中文扩展,用于简体汉字的扩充
后面GB2312扩展成了GBK,包含了更多的繁体字
增加了少数民族的语言,GBK又扩展成为GB18030
出于各国的交流之需,万国码UNICODE被发明
UNICODE直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于 ascii 里的那些”半角”字符,UNICODE 保持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高 8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间
UTF(UCS Transfer Format)标准也是一种编码格式,顾名思义,UTF8 就是每次8个位传输数据,而 UTF16 就是每次16个位
0000 – 007F // unicode
0xxxxxxx // utf-8单字节模板
0080 – 07FF
110xxxxx 10xxxxxx // utf-8双字节模板
0800 – FFFF
1110xxxx 10xxxxxx 10xxxxxx // utf-8三字节模板
// 不同的Unicode码对应的不同的utf-8字节模板
// 由于Unicode只能填充2字节,也就是16位,将其转换为2进制填充到x内即可
举例如下:
新建汉字"联通"
汉字 --> GBK16进制(2字节) --> 二进制(2字节)
联 --> C1 AA --> 1100 0001 1010 1010
通 --> CD A8 --> 1100 1101 1010 1000
// 发现联字与utf-8的双字节模板保持一致,可能会被系统误认为是utf-8(本身是GBK)从而乱码
需要注意的是,二进制编码是所有字符的底层基础,也是转换的枢纽,也是各种系统自动识别的基础
码点和代码单元
码点是指一个编码表中的某个字符(char)对应的代码值
Unicode的码点分为17个代码级别
第一个级别是基本的多语言级别,码点从U+0000——U+FFFF,每个字符用16位表示代码单元
其余的16个级别从U+10000——U+10FFFF,其中包括一些辅助字符(使用连续的代码单元进行表示,也就是一个码点可能对应多个代码单元)(辅助字符一般包含了两个代码单元)
char数据类型其实就是一个采用utf-16编码表示的unicode码点的代码单元
代码单元理解为实际存储的数据量,码点理解为实际包含的有效内容量
举例如下:
String hello = "hi𝕆";
System.out.println(hello.length());
// 4,表示该字符串由4个char组成,𝕆占用了两个代码单元(也就是两个char)为U+D835和U+DD46,但其只有一个代码点为U+1D546
System.out.println(hello.codePointCount(0, hello.length()));
// 3
// 使用特定函数计算码点数,参数表示切片的位置,可以发现其只有3个码点
// str.length()用于计算字符串代码单元数目,str.codePointCount()用于计算字符串的码点数目
System.out.println(hello.charAt(3));
// 此时会返回𝕆的第二个代码单元,为了避免这种情况,不要使用char类型
int[] codePoints = hello.codePoints().toArray()
// 可以产生一个由码点组成的数组,这样可以避免遍历到单个代码单元
字符串对应的常用API
char charAt(int index)
// 返回指定位置的代码单元,较为底层
int codePointAt(int index)
// 返回给定位置开始的码点
int offserByCOdePoints(int startIndex, int cpCount)
// 返回从startIndex代码点开始,位移cpCount后的码点索引
int compareTo(String 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)
// 忽略大小写进行字符比对
boolean startWith(String prefix)
bollean endWith(String suffix)
// 字符串以suffix开头或者结尾,则返回True
int indexOf(String str)
int indexOf(String str, int fromIndex)
int indexOf(int cp)
int indexOf(int cp, int fromIndex)
// 返回与字符串str或者代码点cp匹配的第一个子串的开始位置
// 指定了fromIndex则从此位置开始计算,否则从0开始
// 无结果返回-1
int lastIndexOf(String str)
int lastIndexOf(String str, int fromIndex)
int lastIndexOf(int cp)
int lastIndexOf(int cp, int fromIndex)
// 返回与字符串str或者代码点cp匹配的最后一个子串的开始位置
int length()
// 返回字符串的长度
int codePointCount(int startIndex, int endIndex)
// 返回startIndex和endIndex-1之间的代码点数目,实际上就是切片
String replace(CharSequence oldString, charSequence newString)
// 返回一个新字符串
String substring(int beginIndex)
String substring(int beginIndex, int endIndex)
// 指定切片索引,获取代码单元
String toLowerCase()
String toUpperCase()
// 返回一个新的字符串,将大写更改为小写,或者相反
String trim()
// 删除头部和尾部的空格,返回一个新的字符串
String join(CharSequence delimiter, CharSequence... elements)
// 返回一个新的字符串,并按照定界符连接(这意味着定界符会使用多次)
构建字符串的高效方法
构建流程
StringBuilder builder = new Stringbuidler
// 这是一个字符串构建类,而不是字符串类
builder.append(ch)
// 在字符串构建类中追加字符(也就是代码单元)
builder.append(str)
// 在字符串构建类中追加字符串
builder.appendCodePoint(int cp)
// 在字符串构建类中追加代码点,此时代码点会被转化为一个或者两个代码单元
String completedString = builder.toString()
// 将构建类转换为字符串对象
其他操作
int length()
// 返回缓冲器中的代码单元个数
void setCharAt(int i,char c)
// 将第i个代码单元设置为c
StringBuilder insert(int offset, String str)
// 在offset位置插入字符串
StringBuilder delete(int startIndex, int endIndex)
// 删除索引切片的代码单元
输入
Scanner in = new Scanner(System.in)
// System.in 为标准输入流,通过控制台进行输入
// 当然也有其他类型的输入流
// Scanner拥有各种方法来处理输入
// 此时并不会在控制台进行输入,只是初始化
String name = in.nextLine()
// 表示输入一行,包含空格,以换行符作为分隔符
// 此时会在控制台进行输入,以回车结束
String firstName = in.next()
// 读取单词,也就是以空格作为分隔符
int age = in.nextInt()
// 输入一个整数,如果输入其他类型会报错
double age = in.nextDouble()
// 用于输入双精度浮点
boolean input = in.hasNext()
// 检查输入中是否含有其他单词
// 此时会在控制台进行输入
boolean input = in.hasNextInt()
// 检查输入是否有表示整数的项
注意Scanner类定义在java.util包内,使用的时候可能进行如下导入
import java.util.*;
输入密码
Console cons = System.console()
// 使用Console类来完成密码输入,其输入不可见
String username = cons.readline("username:")
// 一次读取一行输入
char[] passwd = cons.readPassword("passwd:")
// 使用一维字符数组来接收密码,处理之后起会被填充
输出
格式化输出
转换符用于指定类型,置于%之后
转换符 | 类型 | 举例
- | -| -
d | 十进制整数 | 159
s | 字符串(可以使用此转换任何对象) | Hello
x | 十六进制整数 | 9f
c | 字符 | H
o | 八进制整数 | 237
b | 布尔 | True
f | 定点浮点数 | 15.9
e | 指数浮点数 | 1.59e+01
标志符用于进行详细指定,置于%和转换符之间
标志 | 目的 | 距离
- | - | -
- | 正负的符号 | +33.33
空格 | 整数之前添加空格填充(默认为右对齐) | | 33.33|
0 | 数字之前添加0填充(默认为右对齐) | 0033.33
- | 左对齐 | |33.33 |
( | 将负数放在括号内 | ( 33.33)
, | 添加分组分隔符 | 3,333.33
# | 包含小数点(对于f格式) | 3,333.
# | 添加前缀0x或者0(对于x或者0格式)| 0xcafe
$ | 给定被格式化的参数索引(索引从1开始) | %1$d表示以十进制打印第一个参数
同时也有关于时间的标识符,此处略
一般转换
% --> 参数索引$ --> 标志符 --> 宽度 --> .精度 --> 转换字符
用于时间转换
% --> 参数索引$ --> 标志符 --> 宽度 --> t转换字符
文件输入输出
Scanner in = new Scanner(Paths.get("file.txt"),"UTF-8")
// 创建Scanner对象,以UTF-8的形式读取文件,此时参数是一个file对象
// 此时文件输入就是一个输入流
// 如果文件名(比如使用决定路径)有反斜杠,则多加一个反斜杠
Scanner in = new Scanner("file.txt")
// 此时参数为字符串对象
// 此处直接使用相对路径,可能会将文件名误认为数据
PrintWriter out = new PrintWriter("file.txt","utf-8")
// 创建PrintWriter对象,以UTF-8的形式写入文件
// 如果文件不存在则会创建
使用不存在的文件构建Scanner或者用一个不能创建的文件名构建PrintWriter,就会出现异常
流程控制
不能在嵌套的两个块(由大括号来区分)内声明同名的变量
if语句
if (condition1)
{
statement1;
}
else if (condition2) // 此处与前面的if是并列关系,而不是嵌套
{
statement2;
}
else
// 如果出现多个if嵌套,else会与最邻近的if构成一组
// 此处的else与condition1的if配对
{
statement3;
}
while(前置判断)及do-while(后置判断)语句
while (condition)
{
statement;
}
// 此种形式,有可能块中的内容完全不执行
do
{
statement;
}
while (condition)
// 至少执行一次
for(递增判断)语句
for (int i = 1; i<= 10; i++)
{
statement;
}
\\ 其通过一个计数器来进行条件判断
\\ 计数器首先声明变量(尽量不要声明浮点数),然后变量判断,进入循环体,最后递增,以此重复
在for循环中内部定义一个变量(包括计数器),该变量不能在外部使用
如果想要在外部使用,则需要在外部首先声明,再在内部使用
switch语句(用于简化多重if-else语句)
switch (choice)
{
case 1:
statement1;
break;
case 2:
statement2;
break;
default:
statement3;
break;
}
// 注意,如果没有进行break,则可能触发多个case分支语句,直至遇到break或者switch语句结束
此处的case对应的不再是简单的condition
而可以是char,byte,short,int的常量表达式,枚举常量,字符串字面量
带标签的break(相当于给一个作用域进行命名)
labelname:
while (condition)
{
statement1;
break labelname;
}
同时也有break和continue可选
大数值
使用来自java.math包中的BigInteger类(任意精度的整数运算)和BigDecimal类(任意精度的浮点数运算)
BigInteger a = BigInteger.valeOf(100)
// 将普通整型转换为大数值的整型
BigInteger c = a.add(b)
BigInteger d = a.nultiply(c)
// 使用add来对大数值进行求和或者积
// 也有减(subtract)除(divide)余(mod)
数组
数组是一种数据结构,存储同一类型值(在声明时定义类型)的集合

浙公网安备 33010602011771号