Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
在白皮书中,Java被冠以以下特性:1)简单性、2)面向对象、3)分布式、4)健壮性、5)安全性、6)体系结构中立、7)可移植性、8)解释型、9)高性能、10)多线程、11)动态性
白皮书:https://www.oracle.com/java/technologies/language-environment.html
特性解释:https://horstmann.com/corejava/java-an-overview/7Gosling.pdf
这里了解几个相关术语:
术语名 | 缩写 | 解释 |
---|---|---|
Java Development Kit | JDK | 编写Java程序的程序员使用的软件 |
Java Runtime Environment | JRE | 运行Java程序的用户使用的软件 |
Standard Edition(标准版) | SE | 用于桌面或简单服务器应用的Java平台 |
Enterprise Edition(企业版) | EE | 用于复杂服务器应用的Java平台 |
Micro Edition(微型版) | ME | 用于小型设备的Java平台 |
推荐使用IDEA进行Java程序的编写,Java环境配置及IDEA的安装可参考:Java/JDK下载安装与环境配置(Windows 10 超详细的图文版教程 )
public class FirstSample {
public static void main(String[] args) {
System.out.println("We will not use 'Hello world!'");
}
}
这是一个简单的Java应用程序,它只发送一条消息到控制台窗口中。
若要在cmd环境下运行,可以使用以下代码:
javac FirstSample.java
java FirstSample
java定义函数、类等时遵循以下命名规则:
1.类成员变量:首字母小写和驼峰原则:monthSalary
2.局部变量:首字母小写和驼峰原则
3.常量:大写字母和下划线:MAX_VALUE
4.类名:首字母大写和驼峰原则:Man,GoodMan
5.方法名:首字母小写和驼峰原则:run(),runRun()
1.单行注释:/ /
2.多行注释:/* */
3.文档注释:/** */
注:/* */ 注释不能嵌套
Java共有8种基本类型,其中有4种整形、2种浮点类型、1种字符类型和1种表示真值的boolean类型。
类型 | 存储需求 | 取值范围 |
---|---|---|
int | 4字节 | -2 147 483 648~2 147 483 647 |
short | 2字节 | -32 768~32 767 |
long | 8字节 | -9 223 372 036 854 775 808~9 223 372 036 854 775 807 |
Java是强类型的,整形的范围与运行Java代码的机器无关,所有数值类型占用的字节数是固定的
类型 | 存储需求 | 取值范围 |
---|---|---|
float | 4字节 | 大约 ± \pm ± 3.402 823 47E+38F(有效位数为6~7位) |
double | 8字节 | 大约 ± \pm ± 1.797 693 134 862 315 70E+308(有效位数为15位) |
所有浮点数值计算都遵循IEEE 754规范,溢出和出错情况表示为:正无穷大、负无穷大、NaN(不是一个数字)
注:浮点数不适用于无法接收舍入误差的计算。
在Java中,char类型描述了UTF-16中的一个代码单元。
char类型的字面值要用单引号括起来,如’A‘是编码值为65的字符常量,要注意与“A”的区分。
char类型的值可以表示为16进制值,范围从 \u0000到 \uFFFF
boolean(布尔)类型有两个值:false和true,用来判定逻辑条件。整型值和布尔值直接不能相互转换。
在Java中,每个变量都有一个类型type,在声明变量时,要先声明变量的类型,如:
double salary;
int vacationDays;
long earthPopulation;
boolean done;
变量声明后,必须用赋值语句对变量进行显示初始化。如:
int vacationDays1;
vacationDays1 = 12;
int vacationDays2 = 12;
在Java中可以将声明变量放在代码中任何地方。
注:
1.变量名对大小写敏感,且不能用Java保留字作变量名。
2.从Java10开始,对于局部变量,如果可以从变量的初始值推断出它的类型,就不需要声明类型。只需要使用关键字var,如:
var vacationDays = 12; // int
var greeting = "Hello"; // String
利用关键字final指示常量,如:
final double CM_PER_INCH = 2.54;
常量只能被赋值一次,且被赋值后不能更改,习惯上,常量名使用全大写。
在Java中,经常希望某个变量可以在一个类中的多个方法中使用,通常将这些变量称为类常量(class constant),使用关键词static final进行设置,如:
public static final double CM_PER_INCN = 2.54;
需要注意,类常量的定义位于main方法的外部。
有时候,变量的取值只在一个有限的集合内,可以自定义枚举类型,如:
enum Size{SMALL,MEDIUM,LARGE,EXTRA_LARGE};
Size s = Size.MEDIUM;
Java提供了一组丰富的算数和逻辑运算符以及数学函数
常见的算术运算符有+、-、*、/等,整数的求余操作用%表示。
注:整数被0整除会产生一个异常,而浮点数被0整除会得到无穷大或NaN结果。
Math类中,包含了各种各样的数学函数。在编写不同类别的程序时,可能需要的函数也不同。具体可以参考联机API文档
当用一个二元运算符连接两个值时,要先将连个操作数转换为同一类型,然后再进行计算:
①如果两个数有一个是double类型,另一操作数就会转换为double类型
②如果两个数有一个是float类型,另一操作数就会转换为float类型
③如果两个数有一个是long类型,另一操作数就会转换为long类型
④否则,两个操作数都转换为int类型
在Java中,允许进行数值之间的类型转换,可能会丢失一些信息。如:
double x = 9.997;
int nx = (int) x;
如果相对浮点数进行舍入运算,可以使用Math.round方法:
double x = 9.997;
int nx = (int) Math.round(x);
可以在赋值中使用二元运算符,如:
x += 4;
等价于:
x = x + 4;
注:如运算符得到一个值,其类型与左侧类型不同,则会发生强制类型转换。
与C语言的i++、i–相同,Java也引入了自增自减操作,但不建议使用
常用的关系运算符有:==、<、>、<=、>=、&&(与)、||(或)、!=(非)等。
此外还有三元运算符:condition ? expression1 : expression2
位运算符包括:&(”and“)、|(”or“)、^(”xor“)、~(”not“)
另外,还有<<和>>运算符表示位模式左移或右移。
最后,>>>运算符会用0填充高位,这与>>不同,它会用符号位填充高位。不存在<<<运算符。
从概念上讲,字符串就是Unicode字符序列。Java类库中提供了一个预定类String。
String类的substring方法可以从一个较大的字符串提取一个子串。如:
String greeting = "Hello";
String s = greeting.substring(0,3);
创建一个由字符”Hel“组成的字符串。
Java语言允许使用+连接(拼接)两个字符串:
String expletive = "Expletive";
String PG13 = "deleted";
String message = expletive + PG13;
当一个字符串与一个非字符串的值进行拼接时,后者会转换为字符串。
在Java11中,还提供了一个repeat方法:
String repeated = "Java".repeat(3); // repeated is "JavaJavaJava"
String没有提供修改字符串中某个字符的方法,可以通过以下操作实现:
String greeting = "Hello";
greeting = greeting.substring(0,3) + "p!";
可以用equals方法检测两个字符是否相等。如:
"Hello".equals(greeting)
想要检测两个字符串是否相等而不区分大小写,可以使用equalsIgnoreCase方法:
"Hello".equalsIgnoreCase("hello")
注:不要用 == 判断字符串是否相等
空串 “” 是长度为0的字符串,可以调用以下代码检查一个字符串是否为空:
if (str.length() == 0)
if (str.equals(""))
空串是一个Java对象,有自己的串长度(0)和内容(空)。不过,String变量还可以存放一个特殊的值null,表示目前没有任何对象与该变量关联,可以调用以下代码检查一个字符串是否为null:
if (str == null)
有时要检查一个字符串既不是空串也不是null,可以用如下条件:
if (str != null && str.length() !=0)
首先要检查str不为null。
码点(codepoint)是指与一个编码表中的某个字符对应的代码值。在Unicode标准中,码点采用十六进制书写,并加上前缀U+,例如U+0041就是拉丁字母A的码点。
Unicode的码点可以分为17个代码平面(code plane)。第一个代码平面称为基本多语言平面(basic multilingual plane),包括从U+0000到U+FFFF的“经典”Unicode代码;其余16个平面的码点为从U+10000到U+10FFFF,包括辅助字符(supplementary character)。
UTF-16编码采用不同长度的编码表示所有的Unicode码点。在基本多语言平面中,每个字符用16位表示,通常称为代码单元(code unit)。
Java字符串由char值序列组成,char数据类型是一个采用UTF-16编码表示Unicode码点的代码单元。最常用的Unicode字符使用一个代码单元就可以表示,辅助字符需要一对代码单元表示。
length方法将返回采用UTF-16编码表示给定字符串所需要的代码单元的数量:
String greeting = "Hello";
int n = greeting.length(); // is 5
想要得到实际长度,即码点数量,可以调用:
intcpCount = greeting.codePointCount(0,greeting.length());
调用s.charAt(n)将返回位置n的代码单元,n介于0~s.length()-1之间:
char first = greeting.charAt(0); // first is 'H'
char last = greeting.charAt(4); // last is 'o'
想要得到第i个码点,可以使用:
int index = greeting.offsetByCodePoints(0,i);
int cp = greeting.codePointAt(index);
如果想要遍历一个字符串,并且依次查看每一个码点,可以:
int cp = sentence.codePointAt(i);
if (Character.isSupplementaryCodePoint(cp))
i += 2;
else
i++;
可以使用下列语句实现反向编译:
i--;
if (Character.isSurrogate(sentence.charAt(i)))
i--;
int cp = sentence.codePointAt(i);
这么做很麻烦,可以使用codePoints方法,会生成一个int值的“流”,每个int值对应一个码点,可以将它转换为一个数组,再完成遍历:
int[] codePoints = str.codePoints().toArray();
反之,要把一个码点数组转换为一个字符串,可以使用构造器:
String str = new String(codePoints, 0, codePoints.length);
更多信息可以查看联机API
如果需要用许多小段的字符串来构建一个字符串,那么应该按下列步骤进行。首先,构建一个空的字符串构建器:
StringBuilder builder = new StringBuilder();
每次需要添加一部分内容时,就调用append方法:
builder.append(ch); // append a single character
builder.append(str); // appends a string
在字符串构建完成时调用toString方法,将可以得到一个String对象:
String completedString = builder.toString();
要想通过控制台进行输入,首先要构造一个与“标准输出流”System.in关联的Scanner对象
Scanner in = new Scanner(System.in)
现在,就可以使用Scanner类的各种方法读取输入了。例如,nextLine方法将读取一行输入:
System.out.print("What is your name?");
String name = in.nextLine();
这里使用nextLine方法是因为在输入行中可能包含空格。要想读取一个单词,可以使用:
String firstName = in.next();
要想读取一个整数,就调用nextInt方法:
int age = in.nextInt();
与此类似,想要读取一个浮点数,就调用nextDouble方法:
Scanner类定义在java.util包中。
可以使用语句 System.out.print(x) 将数值输出到控制台。同时,Java5沿用了C语言函数库的printf方法。
还可以使用静态的String.format方法创建一个格式化的字符串,而不打印输出:
String message = String.format("Hello, %s. Next year, you'll be %d", name, age);
其他转换符这里不作详述。
想要读取一个文件,需要构造一个Scanner对象:
Scanner in = new Scanner(Path.of("myfile.txt"), StandardCharsets.UTF_8);
要想写入文件,就需要构造一个PrintWriter对象。在构造器(constructor)中,需要提供文件名和字符编码:
PrintWriter out = new PrintWriter("myfile.txt", StandardCharsets.UTF_8);
如果文件不存在,创建该文件。可以像输出到System.out一样使用print,println以及printf命令。
块(block)即复合语句,是指若干条Java语句组成的语句,用一对大括号括起来。一个块可以嵌套在另一个块中,但不能在嵌套的两个块中声明同名的变量。如:
public static void main(String[] args)
{
int n;
...
{
int k;
int n; // ERROR -- can't redefine n in inner block
}
}
在Java中,条件语句的形式为:
if (condition) statement
这里的条件必须用小括号括起来
此外还有 if … else , if … else if … else语句
当条件为true时,while循环执行:
while (condition) statement
此外还有 do … while 语句
for循环语句是支持迭代的一种通用结构:
for (int i = 1; i <= 10; i++)
System.out.println(i);
Java的switch语句与C语言类似:
switch (choice)
{
case 1:
...
break;
case 2:
...
break;
...
default:
// bad input
...
break;
}
case标签可以是:
①类型为char、byte、short或int的常量表达式
②枚举常量
③从Java7开始,case标签还可以是字符串字面量。
尽管Java的设计者将goto作为保留字,但实际上并没有打算在语言中使用它。
与C语言不同,Java还提供了一种带标签的break语句,用于跳出多重嵌套的循环语句。
标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号:
Scanner in = new Scanner(System.in);
int n;
read_data:
while(...)
{
...
for(...)
{
if(...)
break read_data;
}
}
...
break和continue语句的使用与C语言类似,不作阐述
如果基本的整数和浮点数精度不能够满足需求,可以使用java.math包中的两个类:BigInteger 和 BigDecimal。可以处理包含任意长度数字序列的数值。BigInteger 用于实现任意精度的整数运算,BigDecimal用于实现任意精度的浮点数运算。
使用静态的valueOf方法可以将普通的数转换为大数:
BigInteger a = BigInteger.valueOf(100);
对于更大的数,可以使用一个带字符串参数的构造器:
BigInteger reallyBig = new BigInteger("23231431152531251235113251241241513241321");
另外还有一些常量:BigInteger.ZERO、BigInteger.ONE和 BigInteger.TEN,Java9之后又添加了BigInteger.TWO
不能使用人们熟悉的算术运算符处理大数,而要使用大数类中的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 = new int[100]; // or var a = new int[100];
数组得长度不要求是常量,但一旦创建了数组,就不能再改变它得长度。若程序运行过程中经常需要扩展数组得大小,则应该使用另一种数据结构–数组列表(array list)。
在Java中,提供了一种创建数组对象并同时提供初始值得简写形式。如:
int[] smallPrimes = { 2, 3, 5, 7, 11, 13 };
该方法不需要使用new,也不用指定长度。且最后一个值后允许有逗号,可以方便不断为数组增加值。
还可以声明一个匿名数组:
smallPrimes = new int[] { 2, 3, 5, 7, 11, 13 };
这是下列语句得简写形式:
int[] anonymous = { 2, 3, 5, 7, 11, 13 };
smallPrimes = anonymous;
创建一个数字数组时,所有元素初始化为0;boolean数组初始化为false;对象数组初始化为null。
想要获得数组中得元素个数,可以使用 array.length
Java提供了一种很强得循环结构可以用来一次处理数组中每个元素。而不必考虑下标值:
for (variable : collection) statement
它定义了一个变量用于暂存集合中得每个元素,并执行相应得语句。collection这一集合表达式必须是一个数组或者是一个实现了Iterable接口的类对象(例如ArrayList)。如:
for (int element : a)
System.out.println(element);
打印每个数组元素,一个元素占一行。
或者使用传统的for循环:
for (int i = 0; i < a.length; a++)
System.out.println(a[i]);
Java中允许将一个数组变量拷贝到另一个数组变量,两个变量将引用同一个数组:
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12; // now smallPrimes[5] is also 12
若希望将一个数组的所有值拷贝到一个新的数组中去,就要使用Arrays类的copyOf方法:
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
第二个参数是新数组的长度,这个方法通常用于增加数组的大小:
luckyNumbers = Arrays.copyOf(luckyNumbers, 2 * luckyNumbers.length);
每一个应用程序都有一个带String arg[]参数的main方法,这个参数表明main方法将接收一个字符串数组。
对数组进行排序可以使用Arrays类中的sort方法:
int[] a = new int[10000];
...
Arrays.sort(a)
这个方法使用了优化的快速排序(QuickSort)方法
多维数组将使用多个下标访问数组元素,它适用于表示表格或更加复杂的排列形式。
声明一个二维数组:
double[][] balances;
对数组进行初始化前是不能使用的,可以通过如下代码进行初始化:
balances = new double[NYEARS][NYEARS]
另外,如果知道数组元素,就可以不调用new,如:
int[][] magicSquare = { {16, 3, 2, 13}, {5, 10, 11, 8}, {4, 15, 14, 1}};
一旦数组初始化,就可以利用两个中括号访问各个元素。如:balances[i][j]。
Java实际上没有多维数组,只有一维数组。多维数组被解释为“数组的数组”。
狂神说Java
Java核心技术 卷I(第11版)
下一章:Java从零开始系列02:对象与类