首页 > 其他 > 详细

继承和多态

时间:2015-11-28 15:06:25      阅读:259      评论:0      收藏:0      [点我收藏+]

一、继承

  定义:继承(inheritance):从已有的类派生出新的类。

  继承可以让你定义一个通用的类,该通用类包含一些不同类的公共特征和动作;以该通用类扩展别的特定的类。

1.1 父类和子类

  如果一个类c1继承于类c2,那么c1称为次类(subclass)或者子类(child class)扩展类(extended class)派生类(derived class);C2称为超类(superclass)或者父类(parent class)基类(base class)

  子类可以从其父类中继承可以访问的数据域和方法,还可以添加新的数据域和新方法。

 

继承的实例:先创建一个通用的几何类,由几何类派生出圆、和矩形类:

 

几何类(基类):

package demo;

/**
 * GeometricObject
* Created by luts on 2015/11/28.
*/ public class GeometricObject { private String color = "white"; private boolean filled; private java.util.Date dateCreadted; public GeometricObject(){ dateCreadted = new java.util.Date(); } public GeometricObject(String newColor, boolean newFilled){ dateCreadted = new java.util.Date(); this.color = newColor; this.filled = newFilled; } public String getColor(){ return color; } public void setColor(String newColor){ this.color = newColor; } public boolean isFilled(){ return filled; } public void setFilled(boolean newFilled){ this.filled = newFilled; } public java.util.Date getDateCreadted(){ return dateCreadted; } public String toString(){ return "creadted on " + dateCreadted + "\ncolor: " + color + " and filled: " + filled; } }

 

圆类(子类):

package demo;

/**
 * cricle 
 * Created by luts on 2015/11/28.
 */
public class Circle extends GeometricObject {
    private double radius;

    public Circle(){

    }

    public Circle(double newRadius){
        this.radius = newRadius;
    }

    public Circle(double newRadius, String newColor, boolean newFilled){
        this.radius = newRadius;
        setColor(newColor);
        setFilled(newFilled);
    }

    public double getRadius(){
        return radius;
    }

    public double getArea(){
        return radius * radius * Math.PI;
    }

    public double getDiameter(){
        return 2 * radius;
    }

    public double getPerimeter(){
        return 2* radius * Math.PI;
    }

    public void printCircle(){
        System.out.println("The circle is creadted " + getDateCreadted() + " and the raius is " + radius);
    }
}

矩形类(子类):

package demo;

/**
 * Rectangle  extends from GeometricObject
 * Created by luts on 2015/11/28.
 */
public class Rectangle extends GeometricObject{
    private double width;
    private double height;

    public Rectangle(){

    }

    public Rectangle(double newWidth, double newHeight){
        this.width = newWidth;
        this.height = newHeight;
    }

    public  Rectangle(double newWidth, double newHeight, String newColor, boolean newFilled){
        this.width = newWidth;
        this.height = newHeight;
        setColor(newColor);
        setFilled(newFilled);
    }

    public double getWidth(){
        return width;
    }

    public void setWidth(double newWidth){
        this.width = newWidth;
    }

    public double getHeight(){
        return height;
    }

    public void setHeight(double newHeight){
        this.height = newHeight;
    }

    public double getArea(){
        return width * height;
    }

    public double getPerimeter(){
        return 2 * (width + height);
    }
}

测试类:

package demo;

/**
 * test for circle and rectangle
 * Created by luts on 2015/11/28.
 */
public class TestCircleRectangle {
    public static void main(String[] args){

        //create a circle
        Circle circle = new Circle(1);
        System.out.println("A circle "+ circle.toString());
        System.out.println("The radius is: " + circle.getRadius() + "\nThe area is: " + circle.getArea());
        System.out.println("The diameter is: "+ circle.getPerimeter());


        //create a rectangle
        Rectangle rectangle = new Rectangle(2,4);
        System.out.println("\nA rectangle "+ rectangle.toString());
        System.out.println("The area is: " + circle.getArea());
        System.out.println("The diameter is: "+ rectangle.getPerimeter());
    }
}

输出结果:

A circle creadted on Sat Nov 28 10:27:04 CST 2015
color: white and filled: false
The radius is: 1.0
The area is: 3.141592653589793
The diameter is: 6.283185307179586

A rectangle creadted on Sat Nov 28 10:27:04 CST 2015
color: white and filled: false
The area is: 3.141592653589793
The diameter is: 12.0

 

   Circle和Rectangle类继承GeometricObject类中所有可以访问的数据域和方法,另外两个类都重新定义了属于自己的求面积和周长的方法。GeometricObject类中的color和filled数据域是私有的,只能在GeometricObject类中访问,所有在子类中,如果要修改这两个属性,需要通过set和get方法。如:子类中重载的构造函数。

 

小结:

    • 1)子类并不是父类的一个子集,子类包含的信息通常比父类还多
    • 2)父类中的私有数据域在父类之外是不可访问的。如果子类中要访问父类的私有数据域,需要在父类中定义其get、set方法,通过访问器和构造器来访问和修改。
    • 3)继承关系是is-a关系建模。一个父类和子类之间必须存在是关系。
    • 4)java中不允许多继承,一个java类只能继承一个父类 ,即单一继续。多继承可以通过接口实现。

1.2. 使用super关键字

  super关键字的作用:

  ·1)调用父类的构造方法

super();  //调用父类的无参构造方法
super(parameter); //调用父类的有参构造方法

 语句super()或super(参数)必须出现在子类构造方法的第一行,这是显示调用父类构造方法的唯一方法。

例如上例中的circle类中的一个含参构造方法可以替换为:

//原来的定义
public Circle(double newRadius, String newColor, boolean newFilled){
        this.radius = newRadius;
        setColor(newColor);
        setFilled(newFilled);
    }


//调用父类的构造方法
    public Circle(double newRadius, String newColor, boolean newFilled){
        super(newColor, newFilled);
        this.radius = newRadius;
    }

注意:  1. 要调用父类的构造方法必须使用super关键字,而且调用super语句必须是子类构造方法的第一条语句。在子类中调用父类的构造方法的名字会引起语法错误。

     2. 构造方法可以用来构造一个类的实例。父类的构造方法不能被子类继承,只能通过super关键字调用。

     3. 构造方法可以调用重载的构造方法或者其父类的构造方法。如果没有显示的调用,编译器会自动将super()作为构造方法的第一条语句:

public ClassName() {
}

等价于:

public ClassName() {
    super();      
}


public ClassName(double a) {
}

等价于:

public ClassName(double a) {
    super();      
}

    4. 构造一个类的实例的时候,将会调用沿着继承链的所有父类的构造方法。——构造方法链

  ·2)调用父类的方法

  super关键字不仅可以调用父类的构造方法,还可以调用父类的方法:

  super.方法名 (参数);

例如上例中的Circle类的一个方法:
public void printCircle(){
        System.out.println("The circle is creadted " + getDateCreadted() + " and the raius is " + radius);
    }


可以写出:
    public void printCircle(){
        System.out.println("The circle is creadted " + super.getDateCreadted() + " and the raius is " + radius);
    }

 

1.3. 覆盖方法

  方法覆盖(method overriding):当子类需要修改父类中的方法实现。

  例如上例中的GeometricObject中的toString方法返回的是几何对象的字符串,这个方法在Circle中可以被覆盖:

public String  toString(){
        return super.toString() + "\nradius is " + radius;
    }

 

  注意:· 1)仅当实例方法是可被访问的时候,它才能被覆盖。父类中的私有方法不能被子类覆盖。

     · 2)虽然静态方法也能被子类继承,但是不能被覆盖。如果父类中的静态方法被子类重新定义,那么父类中的静态方法会被隐藏。可以使用:父类名.静态方法名(SuperClassName.staticMethodName)来调用静态方法。

1.4 覆盖和重载

  重载(overload):对于类的方法(包括从父类中继承的方法),方法名相同参数列表不同的方法之间就构成了重载关系。

----参数列表又叫参数签名,包括:参数的类型参数的个数参数的顺序。这三者只要有一个不同就叫做参数列表不同。

 

  覆盖 (override):也叫重写,就是在当父类中的某些方法不能满足要求时,子类中改写父类的方法。当父类中的方法被覆盖了后,除非用super关键字,否则就无法再调用父类中的方法了。

  

发生覆盖的条件:

  · 1、子类和父类的方法名称参数列表返回类型必须完全相同,而且子类方法的访问修饰符的权限不能比父类

  · 2、子类方法不能抛出比父类方法更多的异常。即子类方法所抛出的异常必须和父类方法所抛出的异常一致,或者是其子类,或者什么也不抛出

  · 3、被覆盖的方法不能是final类型的。因为final修饰的方法是无法覆盖的。

  · 4、被覆盖的方法不能为private。否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

  · 5、被覆盖的方法不能为static。所以如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足覆盖条件,那么会发生编译错误。反之亦然。即使父类和子类中的方法都是静态的,并且满足覆盖条件,但是仍然不会发生覆盖,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。

 

  方法的覆盖和重载具有以下相同点:

   · 都要求方法同名

     · 都可以用于抽象方法和非抽象方法之间

 

  方法的覆盖和重载具有以下不同点:

    -- 方法覆盖要求参数列表(参数签名)必须一致,而方法重载要求参数列表必须不一致

    -- 方法覆盖要求返回类型必须一致,方法重载对此没有要求。

    -- 方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类中的所有方法(包括从父类中继承而来的方法)

    -- 方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。

    -- 父类的一个方法只能被子类覆盖一次,而一个方法可以在所有的类中可以被重载多次。

 

覆盖:

public class Test{
    
    public static void main(String[] args){
        A.a = new A();
        a.p(10);
        a.p(10.0);
    }
    
    class B{
        public void p(double i){
            System.out.println(i * 2);
        }
    }
    
    class A extends B(){
        public void p(double i){
            System.out.println(i);
        }
    }
}

上述程序运行输出都是10.0。因为调用的都是A中定义的p (double i)方法。

重载:

public class Test{
    
    public static void main(String[] args){
        A.a = new A();
        a.p(10);
        a.p(10.0);
    }
    
    class B{
        public void p(double i){
            System.out.println(i * 2);
        }
    }
    
    class A extends B(){
        public void p(int i){
            System.out.println(i);
        }
    }
}

输出:10    //调用A类中的p(int i)方法

   20.0    //调用B类中的p(double i)方法

 

1.5. 对象类Object和它的toString()方法

  java中的每个类都起源于java.lang.Object类。如果一个类没有指定继承性,那么其父类就是Object类。

  Object的toString()方法返回描述一个对象的字符串。

  上例中的GeometricObject类重新了toString()方法:

 

 public String toString(){
        return "creadted on " + dateCreadted + "\ncolor: " + color + " and filled: " + filled;
    }

 

 

二、多态(dynamic)

  多态:父类型的变量可以引用子类型的对象。

   先看两个概念:声明类型和实际类型。声明类型是变量被声明的某种类型,实例可以用声明类型或者其子类型的构造方法创建。实际类型是被变量引用的对象的实际类。

Object a = new GeometricObject();
System.out.println(a.toString());

  这里a声明的类型是Object,实际类型是GeometricObject,a指向使用new GeometricObject()创建的对象。a调用的是实际类型中的toString()方法。

  多态存在的三个必要条件
    1、要有继承;
    2、要有重写;
    3、父类引用指向子类对象。

package demo;

/**
 * Created by luts on 2015/11/28.
 */
public class DynamicBindingDemo {
    public static void main(String[] args) {
        m(new GraDuateStudent());
        m(new Student());
        m(new Person());
        m(new Object());
    }

    public static void m(Object x) {
        System.out.println(x.toString());
    }
}

    class GraDuateStudent extends Student{
    }

    class Student extends Person{
        public String toString(){
            return "Student";
        }
    }

    class Person extends Object{
        public String toString(){
            return "Person";
        }
    }

输出:

Student
Student
Person
java.lang.Object@1540e19d

 

 

三、对象转换与instanceof运算符

  语句 Object a = new Student() 是合法的,称为隐式转换。---(1)

     Student b = (Student) a; 称为显式转换。------(2)

  (1)将一个子类的实例转换为一个父类的变量,称为向上转换,是可行的,因为子类的实例也是父类的实例。

  (2)当把一个父类的实例转换成它的子类变量的时候(向下转换),必须使用“(子类名)”进行显示转换。

  进行类型转换是因为在编译时声明类型决定了匹配的方法。通常将变量定义为父类型,这样就可以接收任何子类型的值。

 

  instanceof运算符用于判断两个变量是不是同一类型。

  object 的equals方法:测试两个对象是否相等。

object中的equals方法的签名:
public boolean equals(Object obj){
       return (this == obj)
}

调用语法: object1.equals (object2)

这里的 == 比较运算符用来比较两个基本数据类型是否相等,或者判断两个对象是否具有相同的引用。

继承和多态

原文:http://www.cnblogs.com/luts/p/5002650.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!