Java抽象类详解
在中,介绍了抽象⽅法与接⼝,以及做了简单的⽐较。
这⾥我想详细探讨下抽象类。
⼀、抽象类的定义
被关键字“abstract”修饰的类,为抽象类。(⽽且,abxtract只能修饰类和⽅法)
下⾯显⽰了⼀个最简单的空抽象类
publicabstractclassAbstractClass{
publicstaticvoidmain(String[]args){
AbstractClassabstractClass=newAbstractClass();
}
}
当对这个空的抽象类进⾏实例化时,编译器会报错:
'AbstractClass'isabstract;cannotbeinstantiated'
现在对这个抽象类进⾏扩展,添加属性和⽅法:
publicabstractclassAbstractClass{
publicintconstInt=5;
/*重载method()*/
publicvoidmethod(){}
//没有编译错误
publicabstractvoidmethod(inta);
publicstaticvoidmain(String[]args){
AbstractClassabstractClass=newAbstractClass(){
@Override
publicvoidmethod(inta){
n("实例化抽象类");
}
};
n(nt);
(5);
}
}
//运⾏结果
/*
5
实例化抽象类
*/
在这个抽象类中我添加了⼀个实例属性,⼀个抽象⽅法,以及该抽象⽅法的重载实例⽅法,这些都是合法的。
在main⽅法中,直接对抽象类通过new操作符进⾏实例化,出乎意料的是,IDE直接提⽰了这种操作——这⾥⽣成了⼀个(Anonymous
Inner)。
下⾯是关于匿名内部类的知识点:
⼀种特殊的局部内部类,没有类名,没有class关键字,也不能使⽤extends和implements等关键字修饰。
匿名内部类不能是抽象类(即不能拥有抽象⽅法),必须实现它的抽象⽗类或者接⼝的所有抽象⽅法。
因为没有类名,所以匿名内部类只能被使⽤⼀次,通常⽤来简化代码编写。
使⽤匿名内部类的前提条件:继承⼀个⽗类或者实现⼀个接⼝。
第四点和第⼀点略有⽭盾,其实就是使⽤的时候通过new操作符指定要继承的⽗类或要实现的接⼝(事实上,new是直接调⽤某个构造
函数。new真的是个⽜逼的操作符啊),然后再通过直接定义类体(类体中实现某些⽅法),构建新类的实例。
所以,在我上⾯的代码中,⽣成了⼀个继承AbstractClass的新匿名内部类的实例,这个类中实现了⽗类的抽象method⽅法,获得的实
例我们赋给了abstractClass,并通过实例调⽤了新的method(int5)⽅法。
⼆、抽象类与抽象⽅法
抽象⽅法只有⽅法声明,没有⽅法体的⽅法。它将由⼦类(可能是抽象类,也可能是⾮抽象类)进⾏实现。
通过上⾯空的抽象类的⽅法可知,拥有⼀个抽象⽅法并不是构建⼀个抽象类充分必要条件。
那么,⼀个有抽象⽅法的普通类是合法的吗?⼤概率是不合法的,因为如果这样的设计是合法的⼜有什么意义呢?
实际上,如果我们在⼀个⾮抽象类中定义⼀个抽象⽅法,IDE会提⽰:
“Abstractmethodinnon-abstractclass”
⽽如果我们⼀定要运⾏如下所⽰的⼀段错误代码:
publicclassAbstractTest{
publicabstractvoidtest();
publicstaticvoidmain(String[]args){
}
}
编译器的报错信息为:
Error:java:AbstractTest不是抽象的,并且未覆盖ctTest中的抽象⽅法test()
所以抽象⽅法只能存在于抽象类中。
三、抽象⽅法可以是static的吗?
在进⾏下⾯的测试时,突然想到⼀个很有意思的问题,抽象类中的抽象⽅法可以是静态的吗?
先下结论:NO,这是的修饰符组合是不合法的——Error:java:⾮法的修饰符组合:abstract和static
publicabstractclassAbstractTest{
//⾮法的修饰符组合
publicstaticabstractvoidtest();
publicstaticvoidmain(String[]args){
}
}
static成员⽅法意味着,不需要实例化可以使⽤(在类的内部或者通过类访问)。但是呢,也可以通过实例进⾏访问,这样做不会报
错,但会得到IDE的警告,因为违反了static的设计语义;
abstract⽅法意味着没有⽅法体(区别下“有⽅法体,但⽅法体为空”),即只是⼀个⽅法声明,需要被⼦类去实现。
我们先要清楚,抽象类中是可以拥有static⽅法的,⽐如,我们把main⽅法放在⼀个抽象类中,程序是可以由此运⾏的。
既然这样,⼀个“staticabstract”组合的⽅法,对这个抽象类完全没有存在的意义了!!因为它没有⽅法体,⽆法通过类来使⽤。
在StackOverFlow上有探讨,说完全可以允许这样的“staticabstract”⽅法,因为在⾮抽象⼦类中,实现这个抽象⽅法后的⼦⽅法仍然是
static,是⼦类的类⽅法。
这样的说法有⼀点点意义,但是它仍然⽆法解决的是,“staticabstract”⽅法对⽗类中“static”语义的违背
static⽅法可以被⼦类重写吗?
答案是:static⽅法不能被⼦类重写。(涉及到重写的定义)
但是!我们确实⼜可以在⼦类中重新定义⼀个与⽗类static⽅法⼀模⼀样的⽅法,如下的test()⽅法。
onstruct;
publicclassAbstractTest{
publicstaticvoidtest(){
n("ThisisAbstractTest'sstatictest!");
}
publicstaticvoidprint(){
n("ThisisAbstractTest'sstaticprint!");
}
publicstaticvoidmain(String[]args){
();
();
();
n();
AbstractTestSonabstractTestSon=newAbstractTestSon();
();
();
}
}
classAbstractTestSonextendsAbstractTest{
publicstaticvoidtest(){
n("ThisisAbstractTest-Son'sstatictest!");
}
}
//输出
/*
ThisisAbstractTest'sstatictest!
ThisisAbstractTest-Son'sstatictest!
ThisisAbstractTest'sstaticprint!
ThisisAbstractTest'sstaticprint!
ThisisAbstractTest-Son'sstatictest!
*/
通过输出结果可以看到:⽗类中未被⼦类重写的static⽅法是可以被⼦类及其对象访问到的,但是被⼦类重写过的⽅法,则⼦类及其对
象只能调⽤⾃⼰的⽅法了。
为什么这种情况不能叫做⼦类“重写”了⽗类的⽅法呢,⽽是叫”⽅法隐藏(methodhidding)“?
在的这篇⽂章中,对此做了解释:
因为,⽅法重写(Overriding)是OOP语⾔的⼀种特性,在Java中,它是实现“运⾏时多态”⼀种⽅式!!⽽⽗类⼦类的相同签名的同名
⽅法的情况,therewon’tbeanyrun-timepolymorphism。
还篇⽂章(),解释了这些概念的差别,但是却没有提到上述的methodhidding情况。(所以我以为隐藏只是继承关系的类中变量之间
的⾏为)。
四、抽象类的继承
从抽象⽗类派⽣的⼦类如果不能实现所有的抽象⽅法,它也必须声明为抽象的。
抽象类可以定义构造⽅法,且能被⼦类在构造⽅法中调⽤。
⼀个⾮抽象类的⼦类,可以声明为抽象类。
五、final与abstract的⽭盾
final关键字可以修饰类、⽅法、变量。
final修饰的类不能被派⽣;final修饰的⽅法,禁⽌⼦类重写。
所以我们可以看出,final和abstract就是冰⽕不容的~
本文发布于:2022-11-24 23:04:16,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/14813.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |