深入Java 面向对象编程 (二)继承与多态
回顾
如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象
static成员的最常见的例子是main(),因为在程序开始执行时必须调用main(),所以它被声明为static
声明为static的方法有以下几条限制:
它们仅能调用其他的static方法。
它们只能访问static数据。
1、继承
l
l 继承是面向对象非常重要的特点之一,用好继承能够使程序具有更好的可扩充性,减少程序的代码量
l 先来看看什么是继承
2.什么是继承
l 继承是一种由已有的类创建新类的机制。利用继承,我们可以先创建一个共有属性的一般类,根据该一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为
3.为什么要继承
l 代码冗余
l 程序难以更新
l 难以扩展
//卡车
public class Truck {
String engine; //引擎
String Wheel; //车轮
String carport; //货舱
public void run() {
//定义车跑动的行为
}
}
//轿车
public class Saloon_car {
String engine; //引擎
String Wheel; //车轮
String airbag; //安全气囊
public void run() {
//定义车跑动的行为
}
}
4.使用继承
l 继承使用的关键字是extends
//基类 :汽车
public class Car {
String engine;//引擎
String Wheel;//车轮
//……其他属性
public void run() {
// 定义车跑动的行为
System.out.println("汽车在奔跑!");
}
}
//轿车
public class Saloon_car extends Car{
安全气囊
}
//卡车
public class Truck extends Car {
String carport; //货舱
}
5、方法覆盖1
l 不管是普通汽车,还是卡车和轿车,他们的运转都是一样的,结果均输出“汽车在奔跑”,这是不恰当的
l 卡车和轿车的运转应该是有自己的独立方式的,不应当和普通汽车保持一致
l 也就是说,子类需要对父类的run方法加以改进,变成子类自己的run方法,这就需要在子类中重新编写run方法,覆盖父类的run方法,这种做法在Java中叫做方法的覆盖(Override,又称方法重写)
6、方法覆盖2
//汽车
public class Car {
String engine;//引擎
String Wheel;//车轮
//……其他属性
public void run() {
定义车跑动的行为
汽车在奔跑!");
}
}
//轿车
public class Saloon_car extends Car{
String airbag; //安全气囊
public void run() {
定义轿车
轿车在高速路上奔驰!");
}
}
//卡车
public class Truck extends Car {
String carport; //货舱
public void run() {
// 定义卡车
卡车在工地上忙碌!");
}
}
7、方法覆盖与方法重载
l 要注意重载和重写的区别,重载既可以发生于一个类,也可以发生于子类与父类之间(子类继承父类方法,同时完成方法重载),而重写,则只能是子类重写父类方法
8、多态
l 多态指的就是多种形态,例如,同样是水的成份,但有液态水及冰的多种形态,同样是二氧化碳,就存在气态及液态等多种形态,同样是猫科动物,就有猫和老虎之别
l 继承的表现就是多态
/*对汽车及其子类进行测试,接收汽车对象*/
public void test(Car car){
car.run();
}
…………
public static void main(String[] args) {
CarTest1 ct = new CarTest1();
Car car ;
car = new Car(); //产生普通汽车
ct.test(car);
car = new Saloon_car(); //产生轿车
ct.test(car);
car = new Truck(); //产生卡车
ct.test(car);
}
注意
l 可以看到,同样是Car类的对象,既可以是汽车,也可以是卡车,还可以是轿车,父类句柄可以接收子类对象。在调用test方法时,传递的都是Car类的对象,但是输出什么样的结果取决于该父类句柄所绑定(指向)的到底是什么对象。这在Java中通常叫做run-time binding(运行时绑定)
l 由父类引用创建的对象,只能调用子类从父类继承的方法(当然包含重写的方法),不能调用自己扩展的方法。就像我们说:豹子是动物(向上转型),也可说:豹子会奔跑(调用从父类继承的方法),而不能说:动物是豹子(向下转型),也不能说:动物会爬树(向上转型的对象不能调用子类对象扩展的方法)。
9、Super关键字
l 在讲解构造方法的章节,我们提到了this关键字,this关键字用于表示类的对象自身,在使用中的所有未指明调用者的属性和方法,其前面均由JVM自动加上this,表示调用者自身
l 在某些时候,子类需要调用父类的某些方法
l 除了调用父类同名方法外,super还广泛的运用于构造方法内
public class Employee {
String name;
public Employee(String name) {
this.name = name;
}
}
public class Manager extends Employee {
String department;
public Manager(String name, String department) {
super(name);
this.department = department;
}
}
10、Object类
l Java世界中,任意一个类均直接或间接由一个类演绎而来,这个类就是Object类,Object 是类层次结构的根类,每个类都使用 Object 作为超类。所以,每个类都具有Object类所定义的特征
方法 | 描述 |
toString(): | 返回一个“以文本方式表示”此对象的字符串 |
hashCode() | 返回该对象的哈希码值 |
equals() | 指示某个其他对象是否与此对象“相等” |
11、final关键字
l 通常情况下,为了扩充类的功能,我们允许类的继承
l 但在某些情况下,例如,Sun公司提供的某些功能类,如进行数学运算的类、对字符串处理的类等,由于已经比较完美,不需要再修订;当然,也可能出于安全方面的理由,我们不希望进行子类化,或者考虑到执行效率问题,希望确保涉及这个类各对象的所有行动都要尽可能地有效。这个时候就有必要禁止客户继承。那么如何实现禁止继承的功能呢?这就要靠final关键字来完成了
12、final修饰类
/**
* 四则运算类,是最终类
* @author svse
*
*/
public final class MathProcess {…………}
final修饰方法
/**
* 四则运算类,是最终类
* @author svse
*/
public class MathProcess {
public final int add(int i,int j){
return i+j;
}…………
final修饰属性和变量
l final修饰类,则类不能被继承,修饰方法,则方法不能被重写,如果修饰属性的话,那么这个属性的值是不能被修改的
public class Dog {
//属性
final String shout = "汪汪";
public static void main(String[] args) {
Dog dog = new Dog();
dog. shout="喵喵";
//普通变量
final int age ;
age = 0;
age = 1;
}
}
final修饰对象引用
public class CatDemo {
final Cat cat = new Cat();
public static void main(String[] args) {
//更改cat的属性值
CatDemo cd = new CatDemo();
cd.cat.name = "小花";
cd.cat.name = "小花花";
//更改cat
cd.cat = new Cat();
}
}
final修饰对象引用
l 可以看到,对cat用final修饰后,可以修改cat的属性值,但是不能再修改cat对象的引用。这和之前的讲述并无冲突,修改了cat的属性值,但cat本身地址并未变化
总结
l Object是Java中所有其他类的父类
l 使用extends关键字可继承父类产生一个新的子类
l 子类可以拥有与父类同名,但功能不同的方法,即覆盖父类方法
l 子类可通过super关键字获得父类的方法
l Final关键字可以限定对象、变量、方法、类,使他们不能被修改