5.1 类,超类,子类
复用已存在的类的方法和域,关键字extends表继承。
public class Manager extends Employee
{
}
Java中所有继承都是公有继承,而C++中还有私有继承和保护继承。
通过超类扩展子类时,只需要在子类中表示出需要增加的域和方法。
子类的方法覆盖:如果继承的超类方法不适用与子类,则需要提供新的方法来覆盖(方法名相同)。在覆盖时子类不能直接访问超类中的私有域,需要借助于超类中的公有借口。因为覆盖的方法的名字相同,所以在子类中使用关键字super来调用超类中的方法。
覆盖一个方法时,子类方法不能低于超类方法的可见性。
public class Manager extends Employee
{
public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
}
*super与this的区别:super不是一个对象引用,不能赋给对象变量,只是一个指示编译器调用超类方法的关键字。
this具有两个用途:1.引用隐式参数;2.调用该类其他构造器。
super具有两个用途:1.调用超类方法;2.调用超类的构造器*
因为子类不能直接访问超类的私有域,故在子类的构造器中需要调用超类的构造器来初始化从超类继承的私有域,且必须是放在另一个构造器的第一句,接下来对子类新增的域进行初始化。
public Manager(....)
{
super(....);//superclass constructor
bonus = 0;
}
Java中不支持多继承(即一个子类有多个超类),而C++可以。在继承层次中,从某个特定类到其祖先的路径被称为该类的继承链。
多态
“is-a”规则:子类的每个对象都是超类的对象。
多态:一个对象变量可以指示多个实际类型。即一个超类变量既可以引用超类对象,也可以引用超类的任何子类的对象。
动态绑定:在运行时对象变量可以自动选择调用哪个方法的现象。
*动态绑定过程:
1.虚拟机提取对象变量的实际类型的方法表(列出了每一类所有方法的签名和实际调用方法)
2.根据方法表和实际类型,搜索与待方法签名相同的方法。调用的一定是与实例类型最匹配的方法,现在当前类中搜索,如不存在,再向其超类搜素,以此类推。
3.虚拟机调用方法*
final类、方法、域
final类:不允许扩展的类(即不能用其定义子类)->没有多态性
如String为final类,如果有String类的引用,那么它引用的一定是String类对象
public final class Executive extends Manager
{
...
}
final方法:子类不能覆盖这个方法(在返回类型前加上final),final类的所有方法自动成为final,但域不会。确保在子类中不会改变语意
类型转换
原始数据类型可相互进行类型转换,方法是在待转换数前加上 (待转换类型)
而对于对象变量而言,子类可以转换为超类而不进行类型转换,而超类转换为子类必须进行。
* 只能在继承层次内进行类型转换
* 将超类转换为子类之前,要用instanceof进行检查,看是否能成功转换
if(staff[i] instanceof Manager)//它的作用是判断其左边对象是否为其右边类的实例,返回boolean类型的数据
{
....
boss = (Manager) staff[i];
}
抽象类Abstract class
抽象类中放入了通用公共方法和域。如果其中的方法不好实现,则在方法前添加abstract,这样就不需要实现这个方法了,相当于占位,具体实现在子类中,且子类必须实现。
包含一个或多个抽象方法的类必须被声明为abstract。抽象类也可以包含具体域和具体方法。
抽象类的性质:不能被实例化,即不能创建抽象类的对象,但是可以创建抽象类的对象变量,用于引用非抽象类的子类的对象。
优势:抽象有利于多态性,从而方便对程序进行扩展而不需要改变现存代码。
四种访问修饰符
1.仅对本类可见——private
2.对所有类可见——public
3.对本包和所有子类可见——protected
3.对本包可见——默认,不需要修饰符
5.2 Object类
Java中每个类都是Object类扩展而来,从Object类继承的方法:
1.equals()
object.equals()是用来判断两个对象是否具有相同的引用,当子类继承此方法时,需要覆盖方法
a)判断两者是否指向同一对象
b)判断显示参数是否为null,是则返回false
c)判断两者是否为同一类(用getClass()),否则返回false
d)将显示参数对象强制类型转换
e)判断两者的需要比较的域是否相同(使用boolean Objects.equals(Object a,Object b)比较对象域,如果两个参数为null,则返回true;如果一个参数为null,返回false;否则返回a.equals(b),用==比较原始数据类型域,对于数组元素的域使用boolean Arrays.equals(type[] a,type[] b))
2.hashCode()
默认的hashCode()返回对象的地址
如果重新定义了equals(),也要重新定义hashCode(),两者保持一致,如果x.equals(y),则x.hashCode() == y.hashCode()
需要组合多个散列值时可用:int hash(Object…Object)
3.toString()
getClass().getName()可以获得类名的字符串
x.toString() 与 “”+ x相同
Object.toString()来打印输出对象所属类名和散列码,子类按需自己定义。
打印数组调用:Arrays.toString(type[] a)
打印多维数组:Arrays.deepToString(type[] a)
5.3 泛型数组列表ArrayList<>
是一个采用类型参数的泛型类,管理着对象引用的一个数组,尖括号中是类名(原始数据类型需转换为封装类型),构造时可省去右边尖括号中的内容,编译器会自行检查
ArrayList res = new ArrayList<>();
可动态根据输入调整大小,可以在指定位置插入/删除元素,具体方法见API(P183)
5.4 自动装箱
原始数据类型->封装类型
封装类型->原始数据类型
5.5 参数数量可变的方法
public static double max(double...values)//double...values等同于一个名为values的double[],编译器将new double[] {....(实参)}传递给max方法
{
...
}