面向对象的三个重要特性之二(多态)

来源:互联网 发布:宁波淘宝外包 编辑:程序博客网 时间:2024/05/20 16:32

一、对象转型(casting)

(1)、一个基类的引用类型变量可以“指向”其子类的的对象。

(2)、一个基类的引用不可以访问其子类对象新增加的成员(属性和方法)。

(3)、可以使用变量instanceof类名来判断该引用型变量所“指向”的对象是否属于该类或该类的子类。

(4)、子类的对象可以当作基类的对象来使用称作向上转型(upcasting),反之称为向下转型(down)。

上转型对象:对象的上转型对象的实体是子类负责创建的,但上转型对象会失去原对象的一些属性和功能。

上转型对象的特点:

(1)、上转型对象不能操作子类声明定义的成员变量,不能使用子类声明定义的方法。

(2)、上转型对象可以代替子类对象去调用子类重写的实例方法。如果子类重写的方法是实例方法,那么上转型对象调用重写的方法时,就是通知对应的子类对象去调用这些方法。因此,如果子类重写父类的某个实例方法后,子类对象的上转型对象调用这个方法时,一定是调用了这个重写的方法。

(3)、上转型对象可以调用子类继承的成员变量和隐藏的成员变量和隐藏的成员变量。

注:可以将对象的上转型对象再强制转换到一个子类对象,这时子类对象又具备了子类的所有属性和功能;也可以简单地理解上转型对象,上转型对象不是父类创建的对象,而是子类对象的“简化”形态,它不关心子类新增的功能,只关心子类继承和重写的功能。

下面举个简单的例子说明上转型:

假设B是A的子类或间接子类,用子类B创建一个对象,并把这个对象的引用放到类A声明的对象中时,如;

A a;

B b=new B();

a=b;

那么,就称对象a是子类对象b的上转型对象(好比说“老虎是哺乳动物”)。

 

注:这两个test的不同之处在于第二个Test中父类对象引用子类对象,父类引用指向子类对象,可以写到一个方法里,可以减少代码的重写,可扩展性高 。相比之前第一个Test的可扩展性高很多,如果前面的要添加新方法的话,修改的代码会很多,这样就达不到程序的可修改性灵活的要求了。

一、多态

1、动态绑定和多态

动态绑定是指在“执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用其相应的方法。所谓的编译期间就是当你在调试程序时写的javac时为编译期间,而执行期间是一敲java程序开始运行了,main方法在整个程序中分配内存了,这就是执行期间。

2、多态:同一个引用类型,使用不同的实例而执行不同操作 (父类引用子类对象)。使用多态实现思路:
编写父类。
编写子类,子类重写父类方法。
运行时,使用父类的类型,子类的对象。

多态的三个必要条件:要有继承,要有重写,父类引用指向子类对象。

 

3、下面给大家介绍一下方法的重写:在子类中可以根据需要对从基类中继承来的方法进行重写;重写方法不能使用比被重写方法更严格的访问权限。

方法重写的规则:在继承关系的子类中;
重写的方法名、参数、返回值类型必须与父类相同;
私有方法不能继承因而也无法重写。

注:方法的重写因为方法名、参数、返回值类型必须与父类相同,所以容易写错,一般如果遇到方法的重写时最不容易出错的方法是复制原先的方法。

方法重写与方法重载的差别:

方法的重写在前一篇中说明的很详细,在这就简单的说这些。

4、incetanceof运算符

运算符instanceof是双目运算符,左面的操作元是一个对象,右面是一个类。当左面的对象是右面的类创建的对象时,该运算的结果是true,否则是false。该运算符用来判断一个对象是否属于一个类或实现了一个接口,结果为true或false。在强制类型转换之前通过instanceof运算符检查对象的真实类型,可以避免类型转换异常,从而提高代码健壮性

5、抽象类(abstract)

用abstract关键字来修饰一个类时,这个类叫做抽象类;用abstract 来修饰一个方法时,该方法 叫做抽象方法。

例:abstract class A{

}

抽象类有以下特点:

(1)、与普通的类相比,抽象类可以有抽象方法(abstrat方法),也可以有非抽象方法。对于抽象方法,只允许声明,不允许实现,而且不允许使用final和abstract同事修饰一个方法。

(2)、抽象类不能用new运算创建对象

对于抽象类不能用new运算符创建该类的对象。如果一个非抽象类是某个抽象类的子类,那么它必须重写父类的抽象方法,给出方法体,即在子类中将抽象方法重新声明,但必须去掉abstract修饰,同时保证声明的方法名字、返回类型、参数个数和类型与父类抽象方法完全相同,这也是为什么final 不能和abstrct修饰,同时修饰一个方法的原因。

(3、做上转型对象

尽管抽象类不能创建对象,但他的非抽象子类必须重写其中的全部抽象方法,这样一来,就可以让抽象类声明的对象成为其子类对象的上转型对象,并调用子类重写的方法。

注:含有抽象方法的类必须被声明为抽象类,抽象类必须被继承,抽象方法必须被重写;抽象类不能被实例化;抽象方法只需声明,而不需实现。

(4)、抽象方法的形式

public abstract void enjoy();

没有方法体,而且在子类中必须被重写,否则容易出问题;当一个类中有抽象方法时,这个类必须被声明为抽象类;


6、final类与final方法

final类不能被继承,即不能有子类;如果一个方法被修饰为final方法,则这个方法不能被重写,即不允许子类重写重写隐藏继承的final方法,final方法的行为不允许子类篡改。

 final的值不允许被改变(final的成员变量、final的局部变量)。

(1)、 例:public class TestFinal{

             public static void main(String[]args ){

               T  t=new T();

                //t.i=9;

      }


}

class T{

final  int i =8;

public void m(final int j){

   //  j=9;

}

}

 注:final的值不能被改变,//后面的内容是错误的,第一个错误//是说明被final修饰的值是不允许被改变的;第二个说明的是//错误说明的是不能把这个引用指向其他的变量,说白了就是final里边的变量不能改变被final修饰的值。

(2)、final方法不能被重写

public class TestFinal{

             public static void main(String[]args ){

               T  t=new T();

}

 class T{

final  int i =8;

public void final m(){

 }

}

 class  TT extends T{

    // public void  m(){

    }

}

 注://后面的方法是错误的,执行的错误的原因是TT中的m()无法覆盖T中的m();因为final的方法是不能被覆盖重写的,所以运行的时候就会出现这种提示错误的语句;

final  class T{

final  int i =8;

public void final m(){

 }

}

 //class  TT extends T{

}

 注://后面的方法的继承是错误的,执行的话会出现class TT extends无法从T中继承,这就说明了final的方法是无法被继承的。

以上就是final的基本说明。

7、接口(interface)

 Java 不支持多继承性,即一个类只能有一个父类,单继承性使得Java简单、易于管理程序。为了克服单继承的缺点,java使用了接口,一个类可以实现多个接口。关键字interface来定义一个接口。接口的定义和类的定义很相似,分为接口的声明和接口体。

(1)、 接口的声明与使用

接口的声明:我们曾用关键字class来声明类,接口通过使用关键字interface来声明,格式如下:

interface 接口的名字

接口体:接口体中包含常量定义和方法定义两部分,接口体进行方法的声明,不允许提供方法的实现,所以方法的定义没有方法体。例:

interface Printable{

     final int  MAX=100;

     void add();

float sum (float x ,float y);

}

 接口的使用:一个类通过使用关键字implements声明自己实现一个或多个接口。如果实现多个接口,用逗号隔开接口名,如:

class A implements Printable ,Addable

类A使用接口Pintable和接口Addable,而class Dog extendsAnimal implements Enable,Sleepable  

类Dog实现接口Enable和接口Sleepable。

注:如果一个类实现某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体。在类中实现接口的方法时,方法的名字、返回的类型、参数的个数及类型必须与接口中的完全一致;接口中的方法默认是public和abstract,接口在声明方法时可以省略方法前面的关键字 public和abstract,但是类在实现接口方法时,一定有用public来修饰。

总结以上接口的特点:多个无关的类可以实现同一个接口;一个类可以实现多个无关的接口;与继承关系类似,接口与实现类之间存在多态性。

一下给大家再详细说明接口的细节:接口声明时,如果关键字interface前面加上关键字public,就称这样的接口是一个public接口,public接口可以被任何一个类使用;如果一个接口不加public修饰,就称为友好接口,友好接口可以被同一包中的类使用;如果父类实现某个接口,那么子类也就自然实现了该接口,子类不必再显式地使用关键字implements声明自己实现这个接口;接口也可以被继承,即可以通过关键字extends声明一个接口是另一个接口的子接口。由于接口中的方法和常量都是public的,子接口将继承父接口中的全部方法和常量。

Java提供的接口都在相应的包中,通过引入包可以使用Java提供的接口,也可以自己定义接口,一个Java源文件就是由类和接口组成的。

 例:

package cn.edu.bzu.usb;

public interface UsbInterface {
 
  void service();

}
package cn.edu.bzu.usb;

public class UsbFan implements UsbInterface{
 public void service(){
  System.out.println("连接usb接口,风扇转动。");
 }

}
package cn.edu.bzu.usb;

public class UDisk implements UsbInterface {
 public  void service(){
  System.out.println("连接usb接口,开始传输数据。");
 }

}
package cn.edu.bzu.usb;

public class Test {
 public static void main(String[] args) {
  UsbInterface  udisk = new UDisk();
  udisk.service();
  
  UsbInterface  ufan=new UsbFan();
  ufan.service();
 }

}

 

8、接口的优点:可以被多继承,设计和实现完全分离,更自然的使用多态,接口是一种约定(规范)。

抽象类与接口的比较:

(1)、抽象类和接口都可以有抽象方法;

(2)、接口中只可以有常量,不能有变量;而抽象类中即可以有常量也可以有变量;

(3)、抽象类中也可以有非抽象方法,接口不可以。