Java---抽象类

抽象方法和抽象类

抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法。

抽象方法和抽象类的规则如下:

  • 抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。
  • 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例。
  • 抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)五种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
  • 含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。

注意:
归纳起来,抽象类可用“有得有失”4个字来描述。“得”指的是抽象类多了一个能力:抽象类可以包含抽象方法;“失”指的是抽象类失去了一个能力:抽象类不能用于创建实例。

定义抽象方法只需在普通方法上增加abstract修饰符,并把普通方法的方法体(也就是方法后花括号括起来的部分)全部去掉,并在方法后面增加分号即可。

注意:
抽象方法和空方法体的方法不是同一个概念。例如,public abstract void test();是一个抽象方法,它根本没有方法体,即方法后面没有一对花括号;但public void test(){}方法是一个普通方法,它已经定义了方法体,只是方法体为空,即它的方法体什么也不做,因此这个方法是不可使用abstract来修饰。

定义抽象类只需在普通类上增加abstract修饰符即可。甚至一个普通类(没有包含抽象方法的类)增加abstract修饰符后也将变成抽象类。

下面定义一个Shape抽象类。

public abstract class Shape {
    {
        System.out.println("执行Shape的初始化块。。。");
    }

    private String color;

    //定义一个计算周长的抽象方法
    public abstract double calPerimeter();
    //定义一个返回形状的抽象方法
    public abstract String getType();

    //定义Shape的构造器,该构造器并不是用于创建Shape对象
    //而是被子类调用
    public Shape(){
    }

    public Shape(String color){
        System.out.println("执行Shape的构造器。。。");
        this.color=color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

}

上面的Shape类里包含了两个抽象方法:calPerimeter()和getType(),所以这个Shape类只能被定义成抽象类。Shape类里既包含了初始化块,也包含了构造器,这些都不是在创建Shape对象时被调用的,而是在创建其子类的实例时被调用。

抽象类不能用于创建实例,只能当做父类被其他子类继承。
下面定义一个三角形类,三角形类被定义成普通类,因此必须实现Shape类里的所有抽象方法。

public class Triangle extends Shape {

    //定义三角形的三边
    private double a;
    private double b;
    private double c;

    public Triangle(String color,double a,double b,double c){
        super(color);
        this.setSides(a,b,c);
    }

    public void setSides(double a,double b,double c){
        if(a>=b+c||b>a+c||c>a+b){
            System.out.println("三角形的两边之和必须大于第三边");
            return;
        }
        this.a=a;
        this.b=b;
        this.c=c;
    }

    //重写Shape类的计算周长的抽象方法
    public double calPerimeter(){
        return a+b+c;
    }

    //重写Shape类的返回形状的抽象方法
    public String getType(){
        return "三角形";
    }
}

上面的Triangle类继承了Shape抽象类,并实现了Shape类中的两个抽象方法,是一个普通类,因此可以创建Triangle类的实例,可以让一个Shape类型的引用变量指向Triangle对象。

下面再定义一个Circle普通类,Circle类也是Shape的一个子类。

扫描二维码关注公众号,回复: 914749 查看本文章
public class Circle extends Shape {

    private double radius;
    public Circle(String color,double radius){
        super(color);
        this.radius=radius;
    }

    public void SetRadius(){
        this.radius=radius;
    }

    //重写Shape类的计算周长的抽象方法
    public double calPerimeter(){
        return 2*Math.PI*radius;
    }

    //重写Shape类的返回形状的抽象方法
    public String getType(){
        return getColor()+"圆形";
    }
    public static void main(String[] args) {

        Shape s1=new Triangle("黑色", 3, 4, 5);
        Shape s2=new Circle("黄色",3);
        System.out.println(s1.getType());
        System.out.println(s1.calPerimeter());
        System.out.println(s2.getType());
        System.out.println(s2.calPerimeter());
    }
}

上面的main()方法中定义了两个Shape类型的引用变量,它们分别指向Triangle对象和Circle对象。由于在Shape类中定义了calPerimeter()方法和getType()方法,所以程序可以直接调用s1变量和s2变量的calPerimeter()方法和getType()方法,无须强制类型转换为其子类类型。

利用抽象类和抽象方法的优势,可以更好的发挥多态的优势,使得程序更加灵活。

当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(即重写)。而final修饰的类不能被继承,final修饰的方法不能被重写。因此final和abstract永远不能同时使用。

注意:
abstract不能用于修饰成员变量,不能用于修饰局部变量,即没有抽象变量、没有抽象成员变量等说法;abstract也不能用于修饰构造器,没有抽象构造器,抽象类里定义的构造器只能是普通构造器。

除此之外,当使用static修饰一个方法时,表明这个方法属于该类本身,即通过类就可以调用该方法,如果过该方法被定义成抽象方法,则将导致通过该类来调用该方法时出现错误(调用了一个没有方法体的方法肯定会引起错误)。因此static和abstract不能同时修饰某个方法,即没有所谓的类抽象方法。

注意:
static和abstract并不是绝对互斥的,static和abstract虽然不能同时修饰某个方法,但他们可以同时修饰内部类。

abstract关键字修饰的方法必须被其子类重写才有意义,否则这个方法将永远不会有方法体,因此abstract方法不能被定义为private访问权限,即private和abstract不能同时修饰方法

猜你喜欢

转载自blog.csdn.net/wilson_m/article/details/79707475