Java 抽象类详解
在《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)。
下面是关于匿名内部类的知识点:
- 一种特殊的局部内部类,没有类名,没有class关键字,也不能使用extends和implements等关键字修饰。
- 匿名内部类不能是抽象类(即不能拥有抽象方法),必须实现它的抽象父类或者接口的所有抽象方法。
- 因为没有类名,所以匿名内部类只能被使用一次,通常用来简化代码编写。
- 使用匿名内部类的前提条件:继承一个父类或者实现一个接口。
第四点和第一点略有矛盾,其实就是使用的时候通过new操作符指定要继承的父类或要实现的接口(事实上,new是直接调用某个构造函数。new真的是个牛逼的操作符啊),然后再通过直接定义类体(类体中实现某些方法),构建新类的实例。
所以,在我上面的代码中,生成了一个继承AbstractClass的新匿名内部类的实例,这个类中实现了父类的抽象method方法,获得的实例我们赋给了abstractClass,并通过实例调用了新的method(int 5)方法。
二、抽象类与抽象方法
抽象方法只有方法声明,没有方法体的方法。它将由子类(可能是抽象类,也可能是非抽象类)进行实现。
通过上面空的抽象类的方法可知,拥有一个抽象方法并不是构建一个抽象类充分必要条件。
那么,一个有抽象方法的普通类是合法的吗?大概率是不合法的,因为如果这样的设计是合法的又有什么意义呢?
实际上,如果我们在一个非抽象类中定义一个抽象方法,IDE会提示:
“Abstract method in non-abstract class”
而如果我们一定要运行如下所示的一段错误代码:
public class AbstractTest { public abstract void test(); public static void main(String[] args) { }
}
编译器的报错信息为:
Error:java: AbstractTest不是抽象的, 并且未覆盖biguo.classConstruct.AbstractTest中的抽象方法test()
所以抽象方法只能存在于抽象类中。
三、抽象方法可以是static的吗?
在进行下面的测试时,突然想到一个很有意思的问题,抽象类中的抽象方法可以是静态的吗?
先下结论:NO,这是的修饰符组合是不合法的——Error: java: 非法的修饰符组合: abstract和static
public abstract class AbstractTest {
//非法的修饰符组合
public static abstract void test(); public static void main(String[] args) { }
}
static成员方法意味着,不需要实例化可以使用(在类的内部或者通过类访问)。但是呢,也可以通过实例进行访问,这样做不会报错,但会得到IDE的警告,因为违反了static的设计语义;
abstract方法意味着没有方法体(区别下“有方法体,但方法体为空”),即只是一个方法声明,需要被子类去实现。
我们先要清楚,抽象类中是可以拥有static方法的,比如,我们把main方法放在一个抽象类中,程序是可以由此运行的。
既然这样,一个“static abstract”组合的方法,对这个抽象类完全没有存在的意义了!!因为它没有方法体,无法通过类来使用。
在StackOverFlow上有探讨,说完全可以允许这样的“static abstract”方法,因为在非抽象子类中,实现这个抽象方法后的子方法仍然是static,是子类的类方法。
这样的说法有一点点意义,但是它仍然无法解决的是,“static abstract”方法对父类中“static”语义的违背
static方法可以被子类重写吗?
答案是:static方法不能被子类重写。(涉及到重写的定义)
但是!我们确实又可以在子类中重新定义一个与父类static方法一模一样的方法,如下的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)“?
在www.geeksforgeeks.org的这篇文章中,对此做了解释:
因为,方法重写(Overriding)是OOP语言的一种特性,在Java中,它是实现“运行时多态”一种方式!!而父类子类的相同签名的同名方法的情况,there won’t be any run-time polymorphism。
还篇文章(”5 Java concepts explained: Overloading, overriding, shadowing, hiding, and obscuring“),解释了这些概念的差别,但是却没有提到上述的method hidding情况。(所以我以为隐藏只是继承关系的类中变量之间的行为)。
四、抽象类的继承
从抽象父类派生的子类如果不能实现所有的抽象方法,它也必须声明为抽象的。
抽象类可以定义构造方法,且能被子类在构造方法中调用。
一个非抽象类的子类,可以声明为抽象类。
五、final与abstract的矛盾
final关键字可以修饰类、方法、变量。
final修饰的类不能被派生;final修饰的方法,禁止子类重写。
所以我们可以看出,final和abstract就是冰火不容的~
Java 抽象类详解的更多相关文章
- Java抽象类 详解
一.抽象类的基本概念 普通类是一个完善的功能类,可以直接产生实例化对象,并且在普通类中可以包含有构造方法.普通方法.static方法.常量和变量等内容.而抽象类是指在普通类的结构里面增加抽象方法的组成 ...
- java抽象类详解
前言 在没讲抽象类之前 我们先来看看 final关键字 final 修饰符 可以修饰 类.属性.方法 修饰类时 表示该类不能被继承 其他特征 跟普通的类一样 修饰 属性时 表示 改属性不能改变 ...
- java关键字(详解)
目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...
- android java 设计模式详解 Demo
android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...
- Java接口 详解(二)
上一篇Java接口 详解(一)讲到了接口的基本概念.接口的使用和接口的实际应用(标准定义).我们接着来讲. 一.接口的应用—工厂设计模式(Factory) 我们先看一个范例: package com. ...
- Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理
本文非常详尽地介绍了Java中的三个集合类 ArrayList,Vector与Stack <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整 ...
- 「万字图文」史上最姨母级Java继承详解
摘要:继承是面向对象软件技术中的一个概念.它使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用. 本文分享自华为云社区<「万字图文」史上最姨母级Java继承详解丨[奔跑吧!JAVA] ...
- Java 集合详解 | 一篇文章解决Java 三大集合
更好阅读体验:Java 集合详解 | 一篇文章搞定Java 三大集合 好看的皮囊像是一个个容器,有趣的灵魂像是容器里的数据.接下来讲解Java集合数据容器. 文章篇幅有点长,还请耐心阅读.如只是为了解 ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
随机推荐
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- 【locust】使用locust + boomer实现对接口的压测
背景 很早之前,考虑单机执行能力,使用locust做过公司短信网关的压测工作,后来发现了一个golang版本的locust,性能是python版本的5到10倍以上,但是一直没有机会使用. 最近公司想做 ...
- recyclerView 嵌套 recyclerView 点击被拦截
上层recyclerView.setLayoutFrozen(true);下层可以接收到点击事件.
- Hexo博客skapp主题部署填坑指南
相信大家都很喜欢 hexo skapp 的主题,由于作者采用结巴分词,加上需要依赖各种各样的环境 所以可能大家踩过很多坑,也许每个人踩得坑不一样,这里使用 Docker 容器 centos 来部署, ...
- 生命周期和Zend引擎
一切的开始:SAPI接口 SAPI(Server Application Programming Interface)指的是具体应用的编程接口.PHP脚本要执行有很多种方式,通过web服务器,或者直接 ...
- 大话编程:非常有趣的循环(Python语言可视化海龟画图演示)
在日常工作和生活中,我们经常会遇到一件事情要重复做很多次的这种情况发生.在编程中,我们也会遇到这种情况,循环这种机制,就是专门用来处理这种需要不断重复做的事情的方法.通过几分钟的阅读,你将会掌握这种机 ...
- 强化学习——Q-learning算法
假设有这样的房间 如果将房间表示成点,然后用房间之间的连通关系表示成线,如下图所示: 这就是房间对应的图.我们首先将agent(机器人)处于任何一个位置,让他自己走动,直到走到5房 ...
- redis常用命令及操作
说明 连接哨兵模式的redis时,我们连接的哨兵进程的ip和端口,这时很多命令不可用:此时,需要直接连接redis真实的服务器ip和端口:Sentinel模式下,连接真实的ip才可以使用config/ ...
- 怎么理解linux作业(job),与进程(process)的关系
1.相关概念: shell :命令解释器,其实就是一个脚本语言解释器,有很多种(bash,ash,tcsh等),最常用的是bash. job(作业): 是相对shell 来说的,在shell中执行一条 ...
- 6种php加密解密方法
<?php function encryptDecrypt($key, $string, $decrypt){ if($decrypt){ $decrypted = rtrim(mcrypt_d ...