继承
父类,也称为基类、超类。
语法:
修饰符 class 子类名 extends 父类名{
.......
}
方法重写,也叫方法覆盖,要求:
方法名相同、形参表相同,
子类方法的返回值类型要小于或等于父类方法的返回值类型,
子类方法抛出的异常类要小于或等于父类方法抛出的异常类,
子类方法的访问权限要大于或等于父类方法的访问权限,
要么都是类方法(static),要么都是实例方法。
在子类中访问父类中被覆盖的成员:
super.父类中被覆盖的方法名() //调用被覆盖的父类方法
super.父类中被覆盖的成员变量名 //使用父类中被覆盖的成员变量名
super(参数表) //调用父类中对应的构造函数
在子类的构造函数中,可以:
super(参数表); //显式调用父类的构造函数,若要使用,必须放在方法体的第一行
this(参数表); //显式调用当前类(子类)的其它构造函数,若要使用,必须放在方法体的第一行
若子类的构造函数中没有调用super(参数表)或this(参数表),则在执行当前类(子类)的构造函数之前,系统会隐式调用父类无参的构造函数。
super(); //调用父类无参的构造函数
this(); //调用当前类无参的构造函数
继承实现了复用,但破坏了类的封装性。
要调用另一个类中的public方法,可以new一个该类的对象,通过该对象来调用public方法。
也可以继承该类,直接调用该类的public方法。(除非必须,否则不要轻易继承,因为破坏了类的封装性)
一个.java文件中最多只能有一个public类,若有public类,该类名必须与.java文件同名。
再类外使用static成员时,可通过对象名或类名调用,最好通过类名调用,这样更规范。
static方法只能访问static成员,其它方法可以访问类的所有成员(包括static成员)。
多态
java引用型变量有2个类型:编译时类型、运行时类型。
编译时类型是声明该变量时的类型,运行时类型是实际赋给该变量的类型。
多态:运行时类型和编译时类型不一致。
比如定义了一个函数:
public void myFunc(Object obj){ //形参是父类对象
............
}
而调用时实际传入的是一个String类型的值。(子类对象)
判断某个引用型变量(注意要是引用型的,但可以是常量值)是否是某个类的实例:
String str="hello";
if( str instanceof String ){ //返回boolean值
.......
}
注意:
实例变量 instanceof 类/接口名 两者的类型必须一致,否则无法通过编译。
抽象类
抽象方法是一种特殊的成员方法,和成员变量、成员方法一个级别。
public abstract 返回值类型 方法名(形参表); //不带方法体
抽象类:加一个abstract修饰
访问权限 abstract class 类名{
......
}
抽象类中可以不含抽象方法,但如果类中有抽象方法,该类必须声明为抽象类。
抽象类不能被创建实例(实例化)
类是对具有相似特征的对象的抽象,抽象类是对一些相似的具体类的抽象,是更高层次的抽象。
抽象类一般作为子类的模板,由子类来实现(继承+重写),从而避免子类设计的随意性。
抽象类是一个模板,将多个子类的通过方法抽象为抽象方法,不关心具体实现,由子类继承下来重写方法来具体实现,不同的子类,具体实现不同。
初始化块
初始化块是和成员变量、成员函数一个级别的。一般用于类的初始化,也可执行其他java代码,作用和构造函数相同。
创建对象时,初始化块在构造函数之前执行。
初始化块分为普通初始化块、静态初始化块。
普通初始化块:
{
.........
}
创建对象时,在构造函数之前执行,没次创建对象时都会执行。
静态初始化块:
static{
........
}
执行优先级高于普通初始化块(在普通初始化块之前执行)。
和其它static成员一样,为类所有,只能访问static成员,但可以写其他java代码。
只在加载到内存时执行1次(只在创建第一个对象时执行),一般用于初始化类的成员(static)、类的公共资源。
一个类中可以有多个初始化块。对于多个普通的初始化块,先定义的优先级更高。
初始化块在javac编译时,原来的初始化块会消失,初始化块中的代码会被放在构造函数的函数体里的最前面。
创建对象时,会先初始化这个类的所有父类。
创建本类的第一个对象:
执行本类的初始化块,要先执行父类的初始化块,要先执行祖类的初始化块;
执行本类的构造函数,要先执行父类的构造函数,要先执行祖类的构造函数。
就是说最先调用祖类的静态初始化块,再调用父类的静态初始化块,再调用本身的静态初始化块;
再调用祖类的普通初始化块,再调用父类的普通初始化块,再调用自身的普通初始化块;
再调用祖类的构造函数,再调用父类的构造函数,再调用本身的构造函数。
package my_package; public class Test { //普通初始化块。初始化块是和成员变量、成员方法一个级别的。创建对象时,在构造函数之前执行。每次创建对象时都会执行。 { System.out.println("普通初始化块正在执行中"); } //静态初始化块。静态初始化块执行优先级高于普通初始化块,但属于类所有,只会执行一次(只在创建第一个对象时执行) static{ System.out.println("静态初始化块正在执行中"); } //成员变量 private String str="hello"; //构造函数 public Test(){ System.out.println("构造函数正在执行中"); } //成员方法 public void out(){ System.out.println("正在执行成员方法"); } public static void main(String[] args) { new Test(); new Test(); } }
单例类的实现
(待写)
不可变类
创建该类的实例后,该实例的实例变量是不能改变的。Java提供的8个包装类、String类都是不可变类。
实现不可变类:
使用private final修饰成员变量
为成员变量只提供getter()方法,不提供setter()方法
缓存类的实例
重复创建相同的对象没有太大的意义,反而加大了系统开销,某些情况下,可以缓存该类的实例,实现复用。
实现缓存实例:
定义一个private static成员变量存储类的实例(多个可用数组)
先检测上面的成员变量是否为null,为null就调用构造函数创建对象,否则直接返回已存在的对象。