一、继承
1.1 继承的定义:
继承,指基于父类定义出一个新的子类,子类具有父类的一般特性(一般特性包括,非私有的属性和行为),子类可以增加原来父类所没有的特性,定义新的属性和行为,或重写父类中的某些属性和方法,扩展类的功能。
1.2 继承的声明与应用
1.2.1 声明
extends关键字:子类使用extends关键字来对父类进行继承。
假设有父类名为Father,子类Child,则子类继承父类的语句如下:
public class Father{}//定义一个名为Father的父类
public class Child extends Father{}//定义一个继承自Father类的名为Child的子类
1.2.2 应用
父类的public成员可以直接在派生类中使用,private成员则不可以。private类仅限于在定义它的类之内进行存取,如果想要与父类的private成员沟通,就只能通过父类中继承下来的public方法成员。
//Father.java
package TestCome;
public class Father {
public int a;//公有数据,未初始化
private int x;//私有数据
private int y;
protected int c;//受保护数据
protected int d;//受保护数据
public Father(int x,int y){
this.x=x;//使用this关键字来指定调用当前父类对象x
this.y=y;//使用this关键字来指定调用当前父类对象y
}
public int getX(){return x;}
public int getY(){return y;}
public void Over(){System.out.println("Father");}
}
//Child.java
package TestCome;
public class Child extends Father{
private int z;//新增子类特有的私有数据或属性
public int a=1;//初始化父类公有数据a
public int getInt() {return c;}//直接使用父类的受保护成员c
//定义构造函数
Child(int x,int y,int z){
super(x,y);//使用super关键字来指定调用父类构造函数
this.z=z;//使用this关键字来指定调用当前子类对象z
}
//新增子类特有的方法
//public void setZ(int z) {this.z=z;}
public int getZ(){return z;}
}
//Test.java
package TestCome;
public class Test{
public static void main(String[] args){
Child a1=new Child(1,2,3);
System.out.printf("a1:(%d,%d,%d) \n",a1.getX(),a1.getY(),a1.getZ());
System.out.printf("a1:(%d,%d,%d) \n",a1.getX(),a1.getY(),a1.getInt());//子类中的父类受保护成员c
System.out.printf("父类的受保护对象c:");
System.out.print(a1.c);//直接使用父类的受保护对象
System.out.printf("\n");
System.out.printf("父类的公共对象a:");
System.out.print(a1.a);//直接使用父类的公共对象
}
}
保存编译运行:鼠标放在整个包上面进行编译所有类
成员如果被声明为protected,则扩展它的子类可以直接使用该数据成员,而不用通过public成员来调用。
一个子类只能继承自单个父类,即单继承。但一个父类可以有多个子类。
1.3 子类与父类的关系
(1)子类自动继承父类的属性和方法,但不能继承访问权限为私有的成员变量和成员。
(2)子类中可以定义特有的属性和方法。
(3)子类中方法的重写:
方法重写:指,子类定义的方法和父类的方法具有相同名称、参数列表、返回类型和访问修饰符。
方法重写会隐藏父类的同名方法,也就是说,在子类中调用方法accelerate(),将不再是调用父类的同名方法accelerate(),而是子类中被重写的accelerate()。
//Vehicle.java
public class Vehicle{
//本类为父类
String type;
String brand;
int engineNum;
String color;
//构造方法
public Vehicle(){
this("父类通用车","本田",2,"银灰色");
}
public Vehicle(String type,String brand,int engineNum,String color){
super();
this.type=type;
this.brand=brand;
this.engineNum=engineNum;
this.color=color;
}
public void start(){
System.out.println(type+brand+engineNum+"引擎"+color+"汽车发动");
}
public void accelerate(){
System.out.println(type+brand+engineNum+"引擎"+color+"加速");
}
}
//Bus.java
public class Bus extends Vehicle{
int maxLoad;
String busNo;
//构造方法
public Bus(){
this(40,"8路");
}
public Bus(String type,String brand,int engineNum,String color,int maxLoad,String busNo){
super(type,brand,engineNum,color);
this.maxLoad=maxLoad;
this.busNo=busNo;
}
public Bus(int maxLoad,String busNo){
super();
this.maxLoad=maxLoad;
this.busNo=busNo;
}
public void accelerate(){//方法重写
super.accelerate();
System.out.println("这是子类Bus中的方法重写");
}
//报站
public void announceBusStop(){
System.out.println(busNo+"公共汽车报站");
}
}
//Test.java
public class Test{
public static void main(String[] args){
Vehicle vehicle=new Vehicle(); //父类
//Vehiclie vehicle=new Vehicle("父类一般车","红旗",2,"黑色");
vehicle.start();
vehicle.accelerate();
//Bus bus=new Bus(); //子类
//Bus bus=new Bus(50);
Bus bus=new Bus("子类公共汽车","女神",2,"白色",50,"9路");
bus.start();
bus.accelerate();
bus.announceBusStop();//报站
}
}
(4)super关键字和this关键字
子类的属性和父类的属性相同时,会出现隐藏的现象。出现隐藏现象后,如果需要使用父类的成员属性和成员方法,可以通过super关键字来进行。
super.accelerate();//super指当前对象的父对象
如果用this关键字,则表示调用当前对象的accelerate()方法:
this.accelerate();//this指当前对象
通过使用super和this关键字,可以明显地区分调用的是当前对象的成员,还是父对象的成员。
另外,当方法体中定义的变量或方法的形式参数与对象的成员变量名一样时,也必须用this关键字来指定当前对象的成员变量。
(5)子类的构造方法
子类不能继承父类的构造方法,父类的构造方法是用来创建父类对象的,子类需要自己定义自己的构造方法,来创建子类对象。
子类的构造方法中,通过super关键字来调用父类的构造方法。由于子类创建对象的时候,首先创建父类对象,紧接着创建子类对象,所以“super([参数]);”必须是子类构造方法的第一条语句,若省略该语句,子类则会自动调用父类的无参构造方法,举例,
super();//调用父类的无参构造方法
super(type,brand,engineNum,color);//调用父类的带参构造方法
如果需要调用当前类中的构造方法,使用this关键字进行,举例
this(40,"8路");//调用当前类中的带参的构造方法
1.4 根类Object
在Java中,所以的类都是直接或间接地继承自java.lang.Object类而得到的。Object类是所有类的根类。
当定义类时,没有使用extends关键字时,默认表示所定义的类的父类为Object类。对于根类的方法,其子类都可以通过继承进行调用。
补充:
- private成员,即,私有成员。
只能在对象内部使用,不能直接通过参考名称加上.进行调用,即使扩展了该类的派生类也无法直接使用父类的私有成员,只能通过父类所提供的public方法成员来调用或设定私有成员。 - protected成员,即,受保护的成员。
将类的成员声明为受保护的成员之后,继承的类可以直接使用这些成员,但仅可以在对象内部或子对象中使用,不可被外部对象直接调用。 - public成员,即,公共成员。
二、多态
2.1 多态的定义
多态指,一个方法声明的多种实现状态,即在程序中同名的不同方法共存。调用者使用同一个方法名,,系统将根据具体情况的不同,调用相对于的方法,从而实现不同的功能状态。即,一个名字,多种方法。
多态是具有多种形态的能力的特征,有时可以利用该特征来提高程序的抽象度和简洁性,以及程序的可扩展性和可维护性。
多态的分类:
多态可分为静态多态和动态多态。
静态多态指,通过同一类中的方法重载实现的多态,是编译时多态,程序会根据参数的不同来调用相对应的方法,由编译器在编译阶段静态决定具体调用哪个被重载的方法。静态多态在程序运行时效率更高些。
动态多态指,类与类之间的方法重写状态实现的多态,是运行时多态,系统在运行时根据调用该方法的实例的类型来决定调用哪个重写方法。动态多态在程序运行时更具有灵活性。
多态的实现:
//伪代码:重在分析,不在是否成功运行
//父类
public class Father{
int drink(){
Ststem.out.println("Father");
return 0;
}
public clsss Child extends Father{
int drink(){
Ststem.out.println("Child重写的drink()方法");
return 0;
}
}
public static void main(String[] args){
Father father=new Child();/**系统将分析出该引用是子类的类型,
*因此将调用该引用的子类方法
*/
//调用子类Child重写的drink()方法
System.out.println(father.drink());
}
除了私有属性外,子类通过继承具备了父类的所有属性,故而凡是要求使用父类对象的地方都可以用子类对象来进行代替。
对子类的一个实例,运行时系统实际会调用哪个方法,有是否重写了父类决定,如果子类重写了父类的方法,子类的实例将调用子类与父类同名的被重写的方法,如果没重写父类的方法,则调用父类中的方法。也就是说,父类对象可以通过引用子类的实例来调用子类的方法。
三、最终类和抽象类
使用final关键字定义的类称为最终类,最终类不能被继承,没有子类。常用于完成某种便准功能的类,一经定义,不需要被生成子类,故称为最终版本的类。
声明格式:
final class 类名{
}
抽象类:
使用abstract关键字定义的类,称为抽象类。一个类中只要存在抽象方法,那么其类就需要定义为抽象类,但抽象类可以没有抽象方法。
抽象类的声明格式:
[public] abstract class 类名{
}
抽象类可以被继承,但不能创建实例。
抽象方法在不同子类中表现出多态性——抽象类提供了方法声明与方法实现相分离的机制,即,可以声明只有方法头但没有方法体的抽象方法,方法体在子类中实现。
//Computer.java
public abstract class Computer{
String brand;
abstract void showBrand();
}
//NoteBook.java
public class NoteBook extends Computer{
@Override
void showBrand(){
brand="Dell";
System.out.println("品牌:"+brand);
}
public static void main(String[] args){
Computer computer=new NoteBook();//子类的对象赋给抽象类的变量,
computer.showBrand();
}
}
参考文献:
1.《Java程序设计任务驱动式教程》出版社:北京航空航天大学出版社
2.《Java学习笔记》作者:良葛格