super()事项
- 子类的构造方法的第一行需要调用super()或者父类其它的有参构造方法,系统默认会在子类的构造方法第一行添加super(),如果父类无无参构造方法则会报错。
方法签名:
- 方法签名=方法名+形参列表
- 方法名相同,方法参数相同,但方法返回值不同,也是不同的方法。在Java程序中,出现这种情况,编译器会报错。
重载、覆写、多态:
- 重载:方法名相同,返回参数类型相同,形参列表不同的方法。
- 覆写:方法名相同,返回参数类型相同,形参列表相同的方法。
- 多态:多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。一般来说我们编写一个父类,让子类覆写父类的方法,那么我们只需要通过向上转型,通过父类调用被覆写的方法,这样就能通过父类调用方法的固定形式调用多个被子类覆写的方法。
- 可见,多态具有一个非常强大的功能,就是允许添加更多类型的子类实现功能扩展,却不需要修改基于父类的代码。
抽象类:
- 如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法。
- 因为抽象类本身被设计成只能用于被继承,无法实例化,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
- 抽象类可以说是被用来更好的使用多态功能而设计的。
面向抽象编程:
- 尽量引用高层类型,避免引用实际子类型的方式,称之为面向抽象编程。联系上文可理解为通过父类来调用子类方法,只管调用,不管具体实现。
- 面向抽象编程的本质就是:
-
- 上层代码只定义规范(例如:abstract class Person);
- 不需要子类就可以实现业务逻辑(正常编译);
- 具体的业务逻辑由不同的子类实现,调用者并不关心。
接口:
- 在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。
- 如果一个抽象类没有字段,所有方法全部都是抽象方法,就可以把该抽象类改写为接口。
- 所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为所有的字段只能是public static final类型,所以我们可以把这些修饰符都去掉,接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来(写不写效果都一样)。
- default方法(该功能出现在jdk1.8以及更高版本):
在接口中,可以定义default方法。例如,把Person接口的run()方法改为default方法:
interface Person {
String getName();
default void run() {
System.out.println(getName() + " run");
}
}
- 实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。
- default方法和抽象类的普通方法是有所不同的。因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。
静态字段与静态方法:
- 静态字段不属于实例,属于class
- 静态方法亦属于class而不属于实例,因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段。
- 通常情况下,通过实例变量访问静态字段和静态方法,会得到一个编译警告。
包:
- package可用来解决类名冲突的问题。
- Java定义了一种名字空间,称之为包:package。一个类总是属于某个包,类名(比如Person)只是一个简写,真正的完整类名是包名.类名。
- 位于同一个包的类,可以访问包作用域的字段和方法,即默认修饰符。
import static java.lang.System.*; //import static导入一个类的静态字段和静态方法
- Java编译器最终编译出的.class文件只使用完整类名,因此,在代码中,当编译器遇到一个class名称时:
- 如果是完整类名,就直接根据完整类名查找这个class;
- 如果是简单类名,按下面的顺序依次查找:
- 查找当前package是否存在这个class。
- 查找import的包是否包含这个class。
- 查找java.lang包是否包含这个class。
如果按照上面的规则还无法确定类名,则编译报错。
作用域:
- public:公共修饰符,对外开放访问。
- protected:保护修饰符,只对子类以及子类的子类开放访问。
- package:默认修饰符、没有public、private修饰的class,以及没有public、protected、private修饰的字段和方法。只对同一包内的类开放访问。
- private:私有修饰符,只对类内部开放。
- final:
- 用final修饰class可以阻止被继承。
- 用final修饰method可以阻止被子类覆写。
- 用final修饰field可以阻止被重新赋值:
注:一个.java文件只能包含一个public类,但可以包含多个非public类。
配置classpath的目的:
- 现JDK在默认情况下会到当前工作目录下(变量值用“.”表示)以及JDK的lib目录下寻找所需的class文件,因此如果Java程序放在这两个目录中,即使不设置CLASSPATH变量执行环境也可以找得到。但是如果Java程序放在其他目录下,运行时则需要设置CLASSPATH变量。
- JVM不依赖classpath加载核心库!例如:rt.jar
JAR包相关:
- jar包实际上就是一个zip格式的压缩文件,而jar包相当于目录。如果我们要执行一个jar包的class,就可以把jar包放到classpath中。
- 在资源管理器中,找到正确的目录,点击右键,在弹出的快捷菜单中选择“发送到”,“压缩(zipped)文件夹”,就制作了一个zip文件。然后,把后缀从.zip改为.jar,一个jar包就创建成功。注意:jar包里的第一层目录,不能是bin。
- jar包还可以包含一个特殊的/META-INF/MANIFEST.MF文件,MANIFEST.MF是纯文本,可以指定Main-Class和其它信息。JVM会自动读取这个MANIFEST.MF文件,如果存在Main-Class,我们就不必在命令行指定启动的类名,而是用更方便的命令:java -jar hello.jar。
- jar包还可以包含其它jar包,这个时候,就需要在MANIFEST.MF文件里配置classpath了。
编码相关:
- ASCII:早期为了给计算机系统字符编码,包含英文字母、数字和常用符号的编码,它占用一个字节,编码范围从0到127,最高位始终为0。
- GB2312:为中文编码设计,使用两个字节表示一个汉字,其中第一个字节的最高位始终为1,以便和ASCII编码区分开。
- Unicode:为了统一全球所有语言的编码,把世界上主要语言都纳入同一个编码,这样,中文、日文、韩文和其他语言就不会冲突。Unicode编码需要两个或者更多字节表示。
- UTF-8:英文字符的Unicode编码高字节总是00,包含大量英文的文本会浪费空间,因此出现了UTF-8编码,它是一种变长编码,用来把固定长度的Unicode编码变成1~4字节的变长编码。UTF-8编码依靠高字节位来确定一个字符究竟是几个字节,一个字符错,不影响后续字符,容错能力强,经常用来作为传输编码。
- char类型实际上就是两个字节的Unicode编码。
- 早期String依靠private final char[]保存,新版本依靠private final byte[]。
- 每次对字符串的操作都是返回新的字符串,并非修改字符串。
枚举类:
enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT;
} //定义枚举类,是类
//编译效果 编译器自动生成
//继承自Enum,标记为final class // 每个实例均为全局唯一:
public final class Color extends Enum {
public static final Color RED = new Color();
public static final Color GREEN = new Color();
public static final Color BLUE = new Color();
// private构造方法,确保外部无法调用new操作符:
private Color() {}
private final String name() {} //返回实例名
private final int ordinal() {} //返回定义顺序,从0开始
}
- enum常量本身带有类型信息,即Weekday.SUN的类型是Weekday.
- 引用类型比较只能用equals(),但enum类型可以例外,因为enum类型的每个常量在JVM中只有一个唯一实例,所以可以直接用==比较。
- 可自定义Enum类:
enum Weekday {
MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0);
//通过此方式给枚举绑定编号,使用时会比ordinal()靠谱些。
public final int dayValue;
private Weekday(int dayValue) { //构造方法要声明为
private this.dayValue = dayValue;
}
}
不变类:
- 定义class时使用final,无法派生子类;
- 每个字段使用final,保证创建实例后无法修改任何字段。
- 常见不变类,例如:Integer、String、BigInteger(任意大小整数)、BigDecimal(任意大小浮点数)。
记录类(JDK14及更高版本):
public record Point(int x) {} //也可以说是定义不变类
//编译器自动生成
public final class Point extends Record {
private final int x;
public Point(int x, int y) {
this.x = x;
}
//构造方法可覆写,可用来检查X
public int x() {
return this.x;
}
public String toString() {
return String.format("Point[x=%s]", x);
}
public boolean equals(Object o) { ... }
public int hashCode() { ... }
}
- 和enum类似,我们自己不能直接从Record派生,只能通过record关键字由编译器实现继承。
- 可添加静态方法
public record Point(int x, int y) {
public static Point of() {
return new Point(0, 0);
}
public static Point of(int x, int y) {
return new Point(x, y);
}
}
var z = Point.of();
var p = Point.of(123, 456);