java 详解接口、继承和多态
接口、继承和多态
继承和多态是面向对象开发语言中非常重要的一个环节,如若使用得当,可以将整个程序的架构变得非常有弹性,同时可以减少代码的冗余性。继承机制的使用可以复用一些定义好的类,减少重复代码的编写。多态机制的使用可以动态调整对象的调用,降低对象之间的依存关系。同时为了优化继承与多态,除了使用继承还使用了接口的形式。
java语言中的类可以同时实现多个接口,接口被用来建立类与类之间的关联的标准,因为这些 机制,java于洋更具有生命力。
1.接口的定义
使用interface来定义一个接口,接口定义与类的定义类似,也是分为声明和接口体,其中接口体由变量定义和方法定 义两部分组成。基本 语法格式如下:
[修饰符]interface 接口名[extends 父接口名列表]{
[public] [static][final]变量;
[public] [abstract]方法;
}
2.语法格式的参数说明
修饰符 可选参数,用于指定接库的访问权限。
接口名 必选参数,用于指定接口的名称,接口名必须是合法的java标识符,一般情况下要求首字母大写
【例】定义一个用于计算的接口,在该接口中定义一个常量PI和两个方法
public interface ICalculate{
final float PI=3.14159f; //定义用于表示圆周率的常量
float getArea(float r); //定义一个用于计算面积的方法getArea()
float getCircumference(float r); //定义一个用于计算周长的方法getCircumference()
}
3.接口的实现
接口定义后,就可以在类中实现接口,在类中实现接口可以使用implements关键字,基本语法格式如下:
[修饰符]class<类名>[extends 父类名][implements 接口列表]{
}
4.实现接口的语法格式的参数说明:
修饰符 可选参数,用于指定类的访问权限,可选值为public、abstract和final
类名 必选参数,用于指定类的名称,类名必须死合法的java标识符,一般情况下要求首字符大写
extends父类名 可选参数,用于指定要定义的类继承与那个父类,当使用extends关键字时,父类名为必选参数
接口列表 可选参数,用于指定该类实现的哪些接口,当使用implements关键字时,接口列表为必选参数,当 接口列表 中存在多个接口名时,各个接口之间使用逗号分隔。
在类中实现接口时,方法名、返回值类型、参数个数及类型必须与接口中的完全一致,并且必须实现接口中的所有方法。
【例】编写一个名称为Cire的类,该类实现定义的接口ICalculate
public class Cire implements ICalculate{
//定义一个计算圆面积的方法
public float getArea(float r){
float area=PI*r*r; //计算圆面积,并赋值给变量area
return area; //返回计算后的圆面积
}
public float getCircumference(float r){
float circumference=2*PI*r;//计算圆周长,并赋值给变量circumference
return circumference; //返回圆周长
}
}
5.注意点:
1.接口不可以被实例化
2.实现类必须实现接口的所有方法
3.实现类可以实现多个接口
4.接口中的变量都是静态常量
在java语言中继承通过extends关键字来实现。也就是用extends指明当前类是子类,并指明从哪一个类继承而来,即 在子类的声明过程中,通过使用extends关键字来显示指明其父类。基本的声明格式如下:
[修饰符] class 子类名 extends 父类名{
类体
}
1.参数说明
修饰符:可选参数,用于指定类的访问权限,可选值为:public、abstract、final
子类名:必选参数,用于指定子类的名称,类名必须是合法的java标识符,一般情况下要求首字母大写
extends父类名:必选参数,用于指定要定义的子类继承与那个父类。
【例】定义一个Pigeon类,继承于父类Bird
父类Bird的代码:
public class Bird{
String color="白色";
String skin="羽毛";
}
子类Pigeon代码:
public Pigeon extends Bird{
public static void main(String[] args){
Pigeon Pigeon = new Pigeon ();
System.out.println("颜色:"+pigeon.color+"皮肤:"+pigeon.skin);
}
}
2.继承中的重写
重写是指父子类之间的关系,当子类继承父类中的所有可能被继承的成员方法时,如果子类的方法名与父类的方法名相同时, 子类就不能继承父类的方法,此时,则称为子类的方法重写了父类的方法。
重写体现了子类补充或者改变父类方法的能力,通过重写,可以使一个方法在不同的子类中表现出不同的行为(重写也可以 称为覆盖)。
【例】定义一个动物类Animal及它的子类,并在子类中重写父类的相关方法
(1)创建一个名称为Animal的类,在该类中声明一个成员方法cry()。代码如下:
public class Animal{
public Animal(){
}
public void cry(){
System.out.println("动物发出叫声!")
}
}
(2)创建一个Animal类的子类Dog,在该类中重写了父类成员的方法cry()。代码如下:
public class Dog extends Animal {
public Dog(){
}
/**
* 重写父类Animal的成员方法
*/
public void cry(){
System.out.println("狗发出 “汪汪~~”的叫声!");
}
}
(3)创建一个Animal类的子类Cat,在该类中重写了父类成员的方法cry()。代码如下:
public class Dog extends Animal {
public Cat(){
}
/**
* 重写父类Animal的成员方法
*/
public void cry(){
System.out.println("猫发出“喵喵~~”的叫声!!");
}
}
(4)创建一个Animal类的子类Sheep,在该类中不定义任何方法。代码如下:
public Sheep(){ //不重写方法,调用父类中的成员方法
}
(5)创建一个类Zoo,在该类的main方法中分别创建子类Dog、Cat和Sheep的对象并为该对象分配内存,然后调用各对象的cry() 方法。代码如下:
package com.java.study.chapter15_01;
/**
*类名称:Zoo.java
*类描述:动物园类Zoo
*类说明:
*创建时间:2016年12月15日,下午6:55:20
*lenovo
*/
public class Zoo extends Animal {
public static void main(String[] args) {
/**
* 创建DOg类的对象,并为其分配内存
*/
Dog dog =new Dog();
System.out.println("执行dog.cry();语句时输出的结果:");
dog.cry();
/**
* 创建Cat类的对象,并为其分配内存
*/
Cat cat =new Cat();
System.out.println("执行cat.cry();语句时输出的结果:");
cat.cry();
/**
* 创建Cat类的对象,并为其分配内存
*/
Sheep sheep =new Sheep();
System.out.println("执行sheep.cry();语句时输出的结果:");
sheep.cry();
}
}
从上面的运行结果中可以看出,由于Dog类和Cat类都重写了父类的cry()方法,所以执行的是子类中的cry()方法,但是Sheep类没有重写父类中的方法,所以执行的是父类中的cry()方法。
3.使用super关键字
子类可以继承父类中的非私有成员变量和成员方法(不是以privare修饰的)作为自己的成员变量和成员方法。但是,如果子类中声明的成员变量和父类的成员变量同名,则子类不能继承父类的成员变量,则称子类的成员变量覆盖了父类的成员变量。同样的情况下,子类中的成员方法与父类的成员方法同名,并且方法的返回值及参数的个数和类型也相同,则子类不能继承父类的成员方法,此 时称子类的成员方法重写了父类的成员方法。这时,如果在子类中访问父类中被隐藏的成员方法或变量,就可以使用super关键字。super关键字主要有两种用途:
1.调用父类的构造方法
子类可以调用父类声明的方法,但是必须在子类的构造方法中使用super关键字来调用,语法格式:super([参数列表]);如果 父类的构造方法包括参数,则参数列表为必选项,用于指定丰富类的构造方法的入口参数。
【例】创建一个Beast类,在类中添加一个默认的构造方法和一个带参数的方法。
public class Beast{
String skin=""; //成员方法
public Beast(){ //默认构造方法
}
public Beast(String strSkin){ //带参数的构造方法
skin=sreSkin;
}
public void move(){
System.out.println("跑");
}
}
在子类Tiger中使用父类的带参数的构造方法,则需要在子类Tiger的构造方法中进行调用。代码如下:
public class Tiger extends Beast{
public Tiger (){ //带参数的构造方法
super("条纹");
}
}
2.操作被隐藏的成员变量和被重写的成员方法
super.成员变量名
super.成员方法名([参数列表])
【例】如果在子类Tiger的方法中改变父类Beast的成员变量skin的值,也可以使用如下的代码:
super.skin="条纹";
如果在子类Tiger的方法中改变父类Beast的成员方法move(),也可以使用如下的代码:
super.move();
三.多态
多态是面向对象程序设计的重要组成部分。在java语言中,通常使用方法的重载和多态实现类的多态性。
方法的重载是指在一个类中出现多个方法名相同,但参数个数和参数类型不同的方法,则称为方法的重载,在执行重载关系的方法时,将根据调用参数的个数和类型来区分具体执行的是哪个方法。
【例】定义一个名称为Calculate的类,在该类中定义两个名称为getArea()的方法(参数个数不同)和两个名称为getArea()的方法(参数个数不同)和两个名称为draw()的方法(参数类型不同)
public class Calculate {
final float PI=3.14159f;//定义一个表示圆周率的常量PI
/**
* 求圆形的面积
*/
public float getArea(float r){
float area=PI*r*r;
return area;
}
/**
* 求矩形的面积
* @return
*/
public float getArea(float l,float w){ //重载getArea
float area=l*w;
return area;
}
/**
* 画任意形状的图形
*/
public void draw(int a){ //定义一个用于画图的方法draw
System.out.println("画"+a+"个任意形状的图形");
}
/**
* 画指定形状的图形
* @param shape
*/
public void draw(String shape){//重载draw方法
System.out.println("画一个"+shape);
}
public static void main(String[] args) {
Calculate calculate =new Calculate();//创建Calculate类的对象并为其分配内存
float l=20;
float w=30;
float areaRectangle=calculate.getArea(l,w);//调用方法,求矩形的面积
System.out.println("长为"+l+"宽为"+w+"的矩形的面积是:"+areaRectangle);
float r=7;
float areaCirc=calculate.getArea(r);//调用方法,求圆的面积
System.out.println("半径为"+r+"的圆形的面积为:"+areaCirc);
int a=7;
calculate.draw(a);
calculate.draw("三角形");
}
}
Being away from home, we have nothing but a desire to make a figure