1、抽象类是含有抽象方法的类。抽象方法没有方法体,必须用abstract
定义。
abstract class A { // 抽象类
public void fun(){方法体;} // 普通方法
public abstract void print(); // 抽象方法
}
public class Demo {
public static void main(String[] args) {
A a = new A(); // 报错,A是抽象类,无法实例化
}
}
结果显示,无法直接实例化抽象类对象.普通类的对象实例化后,该对象可以调用类中的属性和方法.而抽象类中存在抽象方法,抽象方法没有方法体无法调用,因此无法产生实例化对象.
2、抽象类使用原则:
(1)抽象类必须有子类;
(2)抽象类的子类(非抽象类时)必须覆写抽象类中所有的抽象方法(强制子类进行方法覆写)
(3)抽象类对象的实例化依靠子类完成,采用向上转型方式。
范例:使用抽象类
abstract class A { // 抽象类
public void fun() { // 普通方法
System.out.println("普通方法");
}
public abstract void print(); // 抽象方法
}
class B extends A {
// 强制要求对抽象方法进行覆写,否则会报错
public void print() {
System.out.println("覆写后的抽象方法");
}
}
public class Demo {
public static void main(String[] args) {
A a = new B(); // 向上转型
a.fun();
a.print();
}
}
由上述代码,可知:
(1)抽象类的子类明确要求方法覆写,而普通类没有;
(2)抽象类只比普通类多了抽象方法,其他部分相同;
(3)抽象类对象必须经过向上转型才能实例化;
(4)虽然子类可以继承任何类,但开发中,普通类最好继承抽象类。
1、抽象类由于存在属性,因此会有构造方法来初始化属性。子类对象实例化时依然先执行父类构造方法,再调用子类构造方法。
2、抽象类不能使用final定义,因为抽象类必须有子类。
3、抽象外部类不允许使用static
定义,而抽象内部类可以使用static
声明。使用static
定义的抽象内部类相当于抽象外部类,继承时使用外部类.内部类
的形式表示类名。
abstract class A { // 抽象类
static abstract class B {
public abstract void print();
}
}
class X extends A.B {
public void print() {
System.out.println("*****");
}
}
public class Demo {
public static void main(String[] args) {
A.B ab = new X(); // 向上转型
ab.print();
}
}
4、static
定义的方法可以没有实例化对象的情况下直接调用,即使是抽象类中的static方法。
abstract class A { // 抽象类
public static void print() {
System.out.println("static方法");
}
}
public class Demo {
public static void main(String[] args) {
A.print(); // static方法
A a = new A() ; // 报错
}
}
5、有时抽象类只需要一个特定的子类操作,因此可以将该子类定义为该抽象类的内部类。
abstract class A { // 抽象类
public abstract void print();
private static class B extends A { // 内部抽象类子类
public void print() {
System.out.println("Hello");
}
}
public static A getInstance() { // 获取B的实例化对象
return new B();
}
}
public class Demo {
public static void main(String[] args) {
// 客户端得到抽象类对象时,B对其不可见
A a = A.getInstance();
a.print();
}
}
上述设计在系统类库中较为常见,目的是:为用户隐藏不需要知道的子类。
6、观察下述代码:
abstract class A { // 抽象类
// 1. 先调用父类构造
public A() {
this.print();
}
public abstract void print();
}
class B extends A {
private int num = 100;
// 3.调用子类构造,并初始化num = 30.运行结束,未输出初始化后的num
public B(int num) {
this.num = num;
}
// 2. 父类构造调用子类的print,此时num = 0,打印输出。
public void print() {
System.out.println("num = " + num);
}
}
public class Demo {
public static void main(String[] args) {
new B(30); // 4. 结果为0
}
}
在构造方法执行完之前,属性的内容均为其对应的数据类型的默认值。子类在执行构造方法前必先执行父类的构造方法,因为此时子类构造方法还没执行,就调用print()
输出了num的值,所以num为0
.
要求:设计三个类,通过类描述如下行为:
(1)机器人:充电、工作;
(2)人:吃饭、工作、睡觉;
(3)猪:吃饭、睡觉
思路:定义一个抽象类,具有吃饭、睡觉、工作的抽象方法。根据子类的不同,具体实现抽象方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Oy51FpX-1570848167779)(/18-2.png “思路图”)]
abstract class Action {
public static final int EAT = 1;
public static final int SLEEP = 5;
public static final int WORK = 7;
public void command(int flag) {
switch (flag) {
case EAT:
this.eat();
break;
case SLEEP:
this.sleep();
break;
case WORK:
this.work();
break;
case EAT + WORK:
this.eat();
this.work();
break;
}
}
// 不确定方法中的具体行为,定义为抽象类
public abstract void eat();
public abstract void sleep();
public abstract void work();
}
定义子类:
class Robot extends Action {
public void eat() {
System.out.println("机器人正在补充能量");
}
public void sleep() {
}
public void work() {
System.out.println("机器人正在工作");
}
}
class Human extends Action {
public void eat() {
System.out.println("人正在吃饭");
}
public void sleep() {
System.out.println("人正在睡觉");
}
public void work() {
System.out.println("人正在工作");
}
}
class Pig extends Action {
public void eat() {
System.out.println("猪正在吃饭");
}
public void sleep() {
System.out.println("猪正在睡觉");
}
public void work() {
}
}
范例:测试程序
public class Demo {
public static void main(String[] args) {
fun(new Robot());
fun(new Human());
fun(new Pig());
}
public static void fun(Action act) {
act.command(Action.EAT);
act.command(Action.SLEEP);
act.command(Action.WORK);
}
}
结果显示:子类要实现操作,必须按照Action类的标准。