零基础java自学流程-Java语言进阶41

Java 抽象类

一、抽象类的定义

  被关键字“abstract”修饰的类,为抽象类。(而且,abxtract只能修饰类和方法)

  下面显示了一个最简单的空抽象类

public abstract class AbstractClass {
    public static void main(String[] args) {
        AbstractClass abstractClass=new AbstractClass();
    }
}

当对这个空的抽象类进行实例化时,编译器会报错:

  'AbstractClass' is abstract; cannot be instantiated'

   现在对这个抽象类进行扩展,添加属性和方法:

public abstract class AbstractClass {
    public int constInt = 5;

    /*重载method()*/
    public void method() { }

    //没有编译错误
    public abstract void method(int a);

    public static void main(String[] args) {
        AbstractClass abstractClass=new AbstractClass() {
            @Override
            public void method(int a) {
                System.out.println("实例化抽象类");
            }
        };
        System.out.println(abstractClass.constInt);
        abstractClass.method(5);
    }
}

//运行结果
/*
  5
  实例化抽象类
*/

在这个抽象类中,我添加了一个实例属性、一个抽象方法和该抽象方法的重载实例方法,所有这些都是合法的。

在main方法中,使用new操作符直接实例化抽象类,IDE会意外地直接提示该操作符——生成一个Anonymous Inner类。

下面是关于匿名内部类需要了解的一些事情:

一个特殊的局部内部类,没有类名,没有类关键字,也没有extends和implements关键字的修改。

匿名内部类不能是抽象的(也就是说,不能有抽象方法),必须实现其抽象超类或接口的所有抽象方法。

因为没有类名,匿名内部类只能使用一次,通常是为了简化代码编写。

使用匿名内部类的先决条件是继承父类或实现接口。

new操作符用于指定继承哪个父类或实现哪个接口。(事实上,new直接调用构造函数。New是一个非常酷的操作符),然后通过直接定义类主体(实现某些方法)来构建新类的实例。

因此,在上面的代码中,我生成了一个新的匿名内部类的实例,它继承了AbstractClass,实现了父类的抽象方法方法,将实例赋值给AbstractClass,并从实例调用新方法(int 5)方法。

二、抽象类与抽象方法

  抽象方法只有方法声明,没有方法体的方法。它将由子类(可能是抽象类,也可能是非抽象类)进行实现。

  通过上面空的抽象类的方法可知,拥有一个抽象方法并不是构建一个抽象类充分必要条件。

  那么,一个有抽象方法的普通类是合法的吗?大概率是不合法的,因为如果这样的设计是合法的又有什么意义呢?

  实际上,如果我们在一个非抽象类中定义一个抽象方法,IDE会提示:

  “Abstract method in non-abstract class”

  而如果我们一定要运行如下所示的一段错误代码: 

public class AbstractTest {

    public abstract void test();

    public static void main(String[] args) {
        
    }
}

编译器的错误信息是:

错误:Java: AbstractTest不是抽象的,并且没有覆盖biguo classConstruct。abstract test()中的抽象方法

所以抽象方法只能存在于抽象类中。

抽象方法可以是静态的吗?

在接下来的测试中,我想到了一个有趣的问题。抽象类中的抽象方法可以是静态的吗?

错误:Java:无效的修饰符组合:抽象和静态。错误:Java:无效的修饰符组合:abstract和static

public abstract class AbstractTest {
 //非法的修饰符组合
    public static abstract void test();

    public static void main(String[] args) {
        
    }
}

静态成员方法意味着可以(在类内部或通过类)使用它们,而不需要实例化。但是,也可以从实例中访问它,并且没有错误,但是IDE会发出警告,因为它违反了静态的设计语义;

抽象方法意味着没有方法主体,也就是说,只有一个需要由子类实现的方法声明。

我们需要意识到我们可以在抽象类中拥有静态方法。例如,如果我们把main方法放在一个抽象类中,我们的程序就可以从它运行。

在这种情况下,静态抽象方法的组合对这个抽象类没有任何意义。因为它没有方法主体,所以不能被类使用。

允许这样一个“静态抽象”方法是完全可以接受的,因为在一个非抽象子类中,实现抽象方法的子方法仍然是静态的,即子类的类方法。

这个语句有一点意义,但它仍然没有解决的是“静态抽象”方法对父类的“静态”语义的违背

静态方法可以被子类覆盖吗?

答案是:静态方法不能被子类覆盖。(包括重写定义)

但是!实际上,我们可以在子类中重新定义与它的静态父方法test()完全相同的方法。

package biguo.classConstruct;

public class AbstractTest {

    public static  void test(){
        System.out.println("This is AbstractTest's static test!");
    }

    public static  void print(){
        System.out.println("This is AbstractTest's static print!");
    }

    public static void main(String[] args) {
        AbstractTest.test();
        AbstractTestSon.test();
        AbstractTestSon.print();
        System.out.println();

        AbstractTestSon abstractTestSon=new AbstractTestSon();
        abstractTestSon.print();
        abstractTestSon.test();
    }
}

class AbstractTestSon extends AbstractTest{
    public static void test(){
        System.out.println("This is AbstractTest-Son's static test!");
    }
}


//输出
/*
This is AbstractTest's static test!
This is AbstractTest-Son's static test!
This is AbstractTest's static print!

This is AbstractTest's static print!
This is AbstractTest-Son's static test!
*/

通过输出结果可以看到:父类中未被子类重写的static方法是可以被子类及其对象访问到的,但是被子类重写过的方法,则子类及其对象只能调用自己的方法了。

  为什么这种情况不能叫做子类“重写”了父类的方法呢,而是叫”方法隐藏(method hidding)“?

因为,方法重写(Overriding)是OOP语言的一种特性,在Java中,它是实现“运行时多态”一种方式!!而父类子类的相同签名的同名方法的情况,there won’t be any run-time polymorphism。

4. 抽象类的继承

如果抽象父类不能实现所有的抽象方法,则派生自抽象父类的子类也必须声明为抽象。

抽象类可以定义可以被构造函数中的子类调用的构造函数。

可声明为抽象的非抽象类的子类。

五、定与抽象的矛盾

最后一个关键字可以修改类、方法和变量。

最终修改的类不能派生;最后一个修饰符方法禁止重写子类。

由此可见,定义性和抽象性是不相容的


想要系统学习JAVA推荐JAVA300集

Java300集零基础适合初学者视频教程

上一篇:41-微信小程序实现一个页面左右两个滚动条且相互独立


下一篇:Tomcat源码分析环境搭建