java语言,声明类时格式为: abstract
class Db{} 说明Db类为抽象类。抽象方法是说没有方法的实现(方法体)此方法为抽象方法,只有抽象类和接口中才可以有抽象方法。简而言之,含有抽象方法的类一定是抽象类;关键字是abstract
抽象类本质
1.从类的组成上看其是抽象方法和非抽象方法的集合,还有属性(常量)。
2.从设计的角度来看,实际上抽象类定义了一套规范(抽象方法)。(规范)
使用规则
- 抽象类必须被继承,抽象方法必须被重写。
- 抽象类中的抽象方法只需声明,无需实现,没有方法体;
- 抽象类不能被实例化,抽象类不一定要包含抽象方法,而定义抽象方法的类必须是抽象类。
- 抽象类包含的抽象方法必须在其子类中被实现,否则该子类也必须是抽象类。
- 抽象类可以有构造方法供子类实例化对象
- 抽象类不能直接实例化使用,一般用的是抽象类的子类,
A a = new B();
A和B之间的关系,继承关系,接口实例关系。
下面逐条解释:
规则一
抽象类必须被继承,抽象方法必须被重写。
规则二
抽象类中的抽象方法只需声明,无需实现,没有方法体。
在Java中抽象类实际上是一种规范,一般在抽象类中声明方法不直接提供方法体(当然也可以提供),而是通过其子类去重写其抽象方法:
package day_12_01.abs;
/**
* @author soberw
*/
public abstract class A {
//报错,不能定义抽象属性
// abstract int a;
//可以声明属性
private int a;
//可以声明一个普通方法
public void a(){
}
//报错,因为抽象方法不能有方法体,即不能去实现
// public abstract void aa(){
//
// }
//抽象方法正确格式
public abstract void aa();
//抽象方法不能是私有的private
// private abstract void bb();
}
//没有重写父类的抽象方法aa(),报错
//class B extends A{
//
//}
注意
抽象方法不能是私有的private,因为一旦私有,子类就不能重写了,但这违背了抽象方法必须被重写的原则。
规则三
抽象类不能被实例化,抽象类不一定要包含抽象方法,而定义抽象方法的类必须是抽象类。
首先,抽象类不能被实例化,当一个类实例化对象后,这个对象就可以调用类中的属性或者方法了,但在抽象类有抽象方法(没有方法体),无法调用。自相矛盾,所以无法实例化。比如,我想实例化上例中的抽象类A:
class TestA{
public static void main(String[] args) {
//报错
// A a = new A();
}
}
抽象类不一定有抽象方法,这点显而易见,但是意义不大:
//一个空的抽象类
abstract class AA{
}
然后,定义抽象方法的类必须是抽象类,这点也很好理解,一个普通的类是可以被实例化的,如果这个普通类存在抽象方法,那我是不是就可以通过对象去调用呢?当然不能。
package day_12_01.abs;
/**
* @author soberw
*/
//报错,因为抽象方法必须声明在抽象类中
//public class B {
// public abstract void b();
//}
规则四
抽象类包含的抽象方法必须在其子类中被实现,否则该子类也必须是抽象类。
还拿上述代码做例子,如果我声明了一个类B,继承于A,那B就必须重写A中的抽象方法,否则报错(因为普通类中不能有抽象方法),解决方式一:重写父类抽象方法;解决方式二:将B声明为abstract:
//解决方式一:重写父类抽象方法
class B extends A{
@Override
public void aa() {
}
}
//解决方式二:将B声明为abstract
abstract class Bb extends A{
}
规则五
抽象类可以有构造方法供子类实例化对象。
这点很好理解,因为首先可以确定的是,Java中所有的类都有构造方法,即使你是抽象类,虽然我们没写,但其实系统已经默认给我们提供了一个无参的空构造器,例如下面我显示化的在抽象类中声明一个构造方法:
package day_12_01.abs;
/**
* @author soberw
*/
public abstract class Ab {
public Ab(){
System.out.println("Abs......");
}
}
class Abs extends Ab{
}
class Test{
public static void main(String[] args) {
Abs abs = new Abs();
}
}
运行结果:
证明我们在创建子类实例化对象时,父类的构造器也可实现(哪怕父类是抽象类)
规则六
抽象类不能直接实例化使用,一般用的是抽象类的子类。
抽象类不能去实例化对象,那如果我想用其中的一些非抽象方法呢,比如静态方法,比如普通方法呢或者是属性?
我们可以通过继承关系,去创建其子类的对象,形如:
A a = new B(); //其中A是父类,B是子类
package day_12_01.abs;
/**
* @author soberw
*/
public abstract class TT {
String some = "hello";
public static void talk() {
System.out.println("talk...");
}
public void say() {
System.out.println("say..." + some);
}
}
class FF extends TT{
}
class FFTest{
public static void main(String[] args) {
TT.talk();
TT f = new FF();
f.say();
}
}
运行结果:
如果子类重写了父类的非抽象方法,那实际调用的就是子类重写后的。通过子类去调用父类的方法,即通过父类去new一个子类的对象,这实际上也是多态性的一种体现。当然了,抽象类中的静态方法是可以直接调用的(除非是私有的),实际上对任何类都一样。