JAVA
基本程序设计结构
-
源代码的文件名必须和公共类的名字相同
-
main 方法必须为 static,因为在调用 main 方法时,不需要创建对象
-
如果 main 方法正常退出,那么 Java 应用程序的退出码为 0, 表示成功地运行了程序
-
整数类型,与平台无关,有固定的长度
类型 字长 byte 8 short 16 int 32 long 64 -
浮点数类型:
类型 字长 float 32 double 64 -
char 类型的值可以表示为十六进制值,其范围从\u0000 至\uFFFF
-
Unicode 转义序列会在解析代码之前得到处理
-
整型值和布尔值之间不能互相转换
-
从 Java 10 开始,对于局部变量,如果可以从变量的初始值推断出它的类型,就不再需要声明类型。只需要使用关键字 var 而无须指定类型
-
在 Java 中,并不区分变量的声明和定义
-
在 Java 中,利用关键字 final 指示常量,表示这个变量只能被赋值一次。一旦被赋值之后,就不能够再更改了
-
希望某个常量可以在一个类的多个方法中使用,通常将这些常量称为类常量。可以使用关键字 public static final 设置一个类常量
-
二元运算符会统一类型,double > float > long > int, 其他的都会转化为 int
-
枚举
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE }; Size s = Size.MEDIUM; -
类型转换
y=(typename) x,采取截断的方法,实质上是让程序将一段 2 进制代码按照另一种类型解释 -
果想对浮点数进行舍入运算,以便得到最接近的整数(在很多情况下,这种操作更有 用),那就需要使用 Math.round(), 返回的是 long 类型
-
>>> 运算符会用 0 填充高位,这与 >> 不同,它会用符号位填充高位
-
子串
str2=str1.substring(a,b),从 a 开始到 b-1 -
由于不能修改 Java 字符串中的单个字符,所以在 Java 文档中将 String 类对象称为是不可变的(immutable),所以同样字面值的字符串指向同一个实例,除非使用 new
-
Java 字符串大致类似于 char* 指针
-
可以使用 equals 方法检测两个字符串是否相等。对于表达式:
s.equals(t) -
==一定不要使用
==运算符检测两个字符串是否相等!== 这个运算符只能够确定两个字符串是否存放在同一个位置上 -
有时要检查一个字符串既不是 null 也不是空串,这种情况下就需要使用以下条件:
if (str != null && str.length() != 0)
java.lang.String
-
int compareTo(String other)按照字典顺序,如果字符串位于 other 之前,返回一个负数;如果字符串位于 other 之后,返回一个正数;如果两个字符串相等,返回 0 -
new String(int[] codePoints, int offset, int count)用数组中从 offset 开始的 count 个码点构造一个字符串 -
append 方法
StringBuilder builder = new StringBuilder(); builder.append(ch);
输入输出
读取输入 import java.util.*;
-
首先需要构造一个与“标准输入流”System.in 关联的 Scanner 对象。
Scanner in = new Scanner(System.in); String name = in.nextLine(); -
要想读取一个单词 (以空白符作为分隔符),可以调用
String firstName = in.next(); -
要想读取一个整数,就调用 nextInt 方法。与此类似,要想读取下一个浮点数,就调用 nextDouble 方法。
-
boolean hasNext()检测输入中是否还有其他单词。
格式化输出
-
沿用 c 的 printf 函数与格式
-
可以使用静态的 String.format 方法创建一个格式化的字符串,而不打印输出:
String message = String.format("Hello, %s. Next year, you'll be %d", name, age);
文件 I/O
-
读取需构造 Scanner 对象
Scanner in = new Scanner(Path.of("myfile.txt"),StandardCharsets.UTF_8); -
如果文件名中包含”, 需要再添加”转义
-
输出需构造 PrintWriter 对象
PrintWriter out = new Printwriter("myfile.txt",StandardCharsets.UTF_8);
控制流程
- java 不能在嵌套的两个块中声明同名的变量,即不能重定义
- for 循环语句只不过是 while 循环的一种简化形式
- Java 有一个与 C/C++ 完全一样的 switch 语句
- 当在 switch 语句中使用枚举常量时,不必在每个标签中指明枚举名,可以由 switch 的表达式值推导得出
带标签的 break
-
标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号。执行带标签的 break 会跳转到带标签的语句块末尾
lable: while(condition){ ··· if(condition) break lable; }
for each 循环
for (variable : collection ) statement- collection 这一集合表达式必须是一个数组或者是一个实现了 Iterable 接口的类对象(例如 ArrayList)
数组
-
声明
typename[] name = new typename[length] -
一旦创建了数组,就不能再改变它的长度
-
可以使用这种语法重新初始化一个数组而无须创建新变量。例如:
smallPrines = new int[] { 17, 19, 23, 29, 31, 37 }; -
注意,长度为 0 的数组与 null 并不相同
-
for (int element : a) -
创建一个数字数组时,所有元素都初始化为 0。boolean 数组的元素会初始化为 false。对象数组的元素则初始化为一个特殊值 null, 表示这些元素(还)未存放任何对象。
-
要想获得数组中的元素个数. 可以使用
array.length -
打印数组中的所有值
System.out.printin(Arrays.toString(a)); -
数组间复制指引用同一个数组, 所以修改一个会影响另一个
-
拷贝独立新数组——
array2=array.copyOf(array1,array1.length) -
int[] a = new int[100]; // Java等同于int* a = new int [100]; // C++Java 中的 [] 运算符被预定义为会完成越界检查,而且没有指针运算,即不能通过 a 加 1 得到数组中的下一个元素。 -
数组排序,
Arrays.sort(a)
多维数组
-
java 多维数组实质上是一维数组
-
for each 循环语句不能自动处理二维数组的每一个元素。它会循环处理行,而这些行本身就是一维数组。要想访问二维数组 a 的所有元素,需要使用两个嵌套的循 环,如下所示:
for (double[] row : a) for (double value : row) do something with value -
由于可以单独地访问数组的某一行,所以可以让两行交换
-
还可以方便地构造一个 “不规则”数组,即数组的每一行有不同的长度
int[][] odds = new int[NMAX + 1][]; for (int n = 0; n <= NMAX; n++) odds[n] = new int[n + 1];
对象和类
对象
- 要认识到重要的一点:对象变量并没有实际包含一个对象,它只是引用一个对象。在 Java 中,任何对象变量的值都是对存储在另外一个地方的某个对象的引用。new 操作符的返回值也是一个引用。
- 可以显式地将对象变量设置为 null, 指示这个对象变量目前没有引用任何对象。
- 在 Java 中,必须使用 clone 方法获得对象的完整副本
- 静态工厂方法(factorymethod), 它会代表你调用构造器 构造函数?
- 更改器方法 (mutator method)
- 访问器方法 (accessor method)——只访问对象而不修改对象的方法
- 源文件名必须与 public 类的名字相匹配。在一个源文件中,只能有一个公共类,但可以有任意数目的非公共类。
构造器
- 构造器与类同名,构造器总是结合 new 运算符来调用。不能对一个已经存在的对象调用构造器来达到重新设置实例字段的目的
- 不要在构造器中定义与实例字段同名的局部变量
- 如果可以从变量的初始值推导出它们的类型,那么可以用 var 关键字声明局部变量,而无须指定类型,注意 var 关键字只能用于方法中的局部变量。参数和字段的类型必须声明
- 关键字 this 指示隐式参数(同 C++)
- 在 Java 中,所有的方法都必须在类的内部定义
- final 修饰符对于类型为基本类型或者不可变类的字段尤其有用。
静态字段与静态方法
- 如果将一个字段定义为 static, 每个类只有一个这样的字段,属于类,而不属于任何单个的对象
- 静态常量——可以通过类名类访问,不需要对象
- 静态方法是不在对象上执行的方法
- 在下面两种情况下可以使用静态方法: • 方法不需要访问对象状态,因为它需要的所有参数都通过显式参数提供 • 方法只需要访问类的静态字段
方法参数
- Java 程序设计语言总是采用按值调用, 方法不能修改传递给它的任何参数变量的内容。
- 对于对象,方法得到的是对象引用的副本,原来的对象引用和这个副本都引用同一个对象。
- 对象引用是也是按值传递的
- 如果类中提供了至少一个构造器,但是没有提供无参数的构造器,那么构造对象时如果不提供参数就是不合法的。
- 如果构造器的第一个语句形如 this(), 这个构造器将调用同一个类的另一个构造器。
- 初始化块 :只用大括号包起来
包
- 需要注意的是,只能使用星号 (*) 导入一个包
- 不同包的同名类需要加上完整包名来引用
- 有一种 import 语句允许导入静态方法和静态字段,而不只是类。
例如,如果在源文件顶部,添加一条指令:
import static java.lang.System.*;就可以使用 System 类的静态方法和静态字段,而不必加类名前缀 - 要想将类放入包中,就必须将包的名字放在源文件的开头
package x.x.x将源文件放到与完整包名匹配的子目录中 - 前面已经接触过访问修饰符 public 和 private。标记为 public 的部分可以由任意类使用;标记为 private 的部分只能由定义它们的类使用。如果没有指定 public 或 private, 这个部分(类、方法或变量)可以被同一个包中的所有方法访问
类路径
- 类路径是所有包含类文件的路径的集合,类路径中的各项之间用以分号(;)分隔,用句点(.)表示当前目录
c:\classdir;.;c:\archives\archive.jar - 类注释必须放在 import 语句之后,类定义之前
注释
-
类注释,必须放在 import 后,类前
-
方法注释,放在方法前
/** * @throws 异常 * @return 返回值 * @param 参数列表 */
继承
子类
- 使用关键字 extends 表示继承
public class Manager extends Employee - 子类不能直接访问父类的私有字段,只能通过父类的公共方法来访问
- 如果在重载父类方法时希望调用父类方法,使用特殊关键字
super - 子类构造器
- 有一个简单规则可以用来判断是否应该将数据设计为继承关系,它指出子类的每个对象也是超类的对象
- 在 Java 程序设计语言中,对象变量是多态的,超类的变量既可以引用一个超类的对象,也可以引用任何一个子类的对象
- 在这个例子中,变量 staff [0] 与 boss 引用同一个对象。但编译器只将 staff [0] 看成是一个 Employee 对象。这意味着,可以这样调用 boss.setBonus(5000); // OK 但不能这样调用 staff [0].setBonus(5000); // ERROR 这是因为 staff [0] 声明的类型是 Employee, 而 setBonus 不是 Employee 类的方法。
- 不能将超类的引用赋给子类变量
- 所有数组都要牢记创建时的元素类型,并负责监督仅将类型兼容的引用存储到数组中
- 如果是 private 方法、static 方法、final 方法或者构造器,那么编译器将可以准确地知道应该调用哪个方法。这称为静态绑定(static binding)。与此对应的是,如果要调用的方法依赖于隐式参数的实际类型,那么必须在运行时使用动态绑定。
- 在覆盖一个方法的时候,子类方法不能低于超类方法的可见性.
阻止继承
- 不允许扩展的类被称为 final 类。
public fibal - 类中的某个特定方法也可以被声明为 final。如果这样做,子类就不能覆盖这个方法(final 类中的所有方法自动地成为 final 方法, 而不包括字段)
强制转换
-
在进行强制类型转换之前,先查看是否能够成功地转换。为此只需要使用 instanceof 操作符就可以实现。例如:
if (staff[1] instanceof Manager) { boss = (Manager) staff [1]; } -
只能在继承层次内进行强制类型转换。
抽象类
- 为了提高程序的清晰度,包含一个或多个抽象方法的类本身必须被声明为抽象的
- 使用 abstract 关键字,这样就完全不需要实现这个方法了
- 抽象类不能实例化,但需要注意,可以定义一个抽象类的对象 变量,但是这样一个变量只能引用非抽象子类的对象
- 通过在父类中声明抽象方法,可以确保所有的子类都必须提供对该方法的具体实现,以满足父类中定义的规范。这样可以保证在子类中都有某个特定行为或功能的实现,增加代码的一致性和可预测性。
protected
- 如果希望限制超类中的某个方法只允许子类访问,或者更少见地,可能希望允许子类的方法访问超类的某个字段。为此,需要将这些类方法或字段声明为受保护(protected)
- 在 Java 中,保护字段只能由同一个包中的类访问
Object: 所有类的超类
- 所有的数组类型,不管是对象数组还是基本类型的数组都扩展了 Object 类。
equal
- Object 类中的 equals 方法用于检测一个对象是否等于另外一个对象。Object 类中实现的 equals 方法将确定两个对象引用是否相等。这是一个合理的默认行为:如果两个对象引用相等,这两个对象肯定就相等。
- 在子类中定义 equals 方法时,首先调用超类的 equals。如果检测失败,对象就不可能相等。如果超类中的字段都相等,就需要比较子类中的实例字段
getClass返回一个对象所属的类- 可以使用 Override 标记要覆盖超类方法的那些子类方法
hash
-
基础变量和 string 类有默认的根据内容编码的
hashCode方法,Object 类的默认hashCode方法由对象的存储地址来得出 hash -
需要组合多个散列值时,可以调用 Objects.hash 并提供所有这些参数
public int hashCode() { return Objects.hash(a,b,c); } -
提示:如果存在数组类型的字段,那么可以使用静态的 Arrays.hashCode 方法计算一个散列码,这个散列码由数组元素的散列码组成。