抽象类就是在不同类的方法上扩充了一些抽象方法。
abstract
关键字来修饰,并且抽象方法所在的类也一定要使用abstract
关键字来定义。abstract class A {
private String msg = "colder thy kiss" ; // 属性
public void print() { // 普通方法
System.out.println(msg) ;
}
public abstract void method() ; // 声明一个抽象方法,注意观察:没有{}
// {}为方法体,所有的抽象方法都不包含方法体,只是声明一个方法
}
public class TestDemo {
public static void main(String args[]) {
A a = new A() ;
}
}
为什么?
所以,抽象类的使用原则:
public
;
范例:使用抽象类
abstract class A {
······
}
// 一个子类只能够利用extends来继承抽象类,所以依然有单继承局限
class B extends A { // 定义抽象类的子类
}
public class TestDemo {
public static void main(String args[]) {
}
}
abstract class A {
······
}
// 一个子类只能够利用extends来继承抽象类,所以依然有单继承局限
class B extends A { // 定义抽象类的子类
public void method() { // 覆写全部抽象方法
System.out.println("Hello World") ;
}
}
public class TestDemo {
public static void main(String args[]) {
A a = new B() ; // 实例化子类对象
a.method() ; // 调用被子类覆写过的抽象方法
}
}
下面讲解一种特殊使用方式:抽象类中的内部类
abstract class A {
private String msg = "colder thy kiss" ; // 属性
public void print() { // 普通方法
System.out.println(msg) ;
}
public static A getInstance() { // 定义一个方法:取得A类对象
class B extends A { // 定义抽象类的子类(内部类)
public void method() {
System.out.println("Hello World") ;
}
}
return new B() ;
}
public abstract void method() ; // 声明一个抽象方法,注意观察:没有{}
// {}为方法体,所有的抽象方法都不包含方法体,只是声明一个方法
}
public class TestDemo {
public static void main(String args[]) {
A a = A.getInstance() ; // 通过抽象类中的内部类取得实例化对象
a.method() ; // 调用被子类覆写过的抽象方法
}
}
这种用法属于非正常模式,但是对于程序的封装性有好处。现在暂时还不会用到,推荐正常格式:抽象类?子类?覆写所有抽象方法。
抽象类只是比普通类多了一些抽象方法的定义,所以在抽象类中依然允许提供构造方法,并且子类也会遵守子类对象的实例化流程:实例化子类对象前一定会先调用父类的构造方法。
abstract class Person {
private String name ;
private int age ;
public Person() {
System.out.println("【父类】***************") ;
}
public abstract String getInfo() ; // 声明一个抽象方法,注意观察:没有{}
}
class Student extends Person {
private String school ;
public Student() {
System.out.println("【子类】###############") ;
}
public String getInfo() {
return null ;
}
}
public class TestDemo {
public static void main(String args[]) {
new Student() ; // 子类实例化时先调用父类构造在调用本类构造
}
}
abstract class Person {
private String name ;
private int age ;
public Person(String name, int age) {
this.name = name ;
this.age = age ;
System.out.println("【父类】***************") ;
}
public String getName() {
return this.name ;
}
public int getAge() {
return this.age ;
}
public abstract String getInfo() ; // 声明一个抽象方法,注意观察:没有{}
}
class Student extends Person {
private String school ;
public Student(String name, int age, String school) {
super(name, age) ; // super()明确调用父类的属性
this.school = school ;
System.out.println("【子类】###############") ;
}
public String getInfo() {
return "【Student】name = " + super.getName() + ",age = " + super.getAge() + ",school = " + this.school ;
}
}
public class TestDemo {
public static void main(String args[]) {
Person per = new Student("Dexter",20,"hfut") ;
System.out.println(per.getInfo()) ;
}
}
请结合《阿里云【名师课堂】Java面向对象开发3 ~ 6:类与对象》
范例:观察对象初始化操作
abstract class A {
public A() { // 3、调用父类构造
this.print() ; // 4、调用被子类覆写过的方法
}
public abstract void print() ;
}
class B extends A {
private int num = 100 ; // 实际上super之后子类构造没有执行,就不会给num初始化,这条语句只是开辟空间
public B(int num) { // 2、调用子类构造实例化对象
super() ; // 3、这时一条隐含语句,实际目的:调用父类构造
this.num = num ; // 7、这条传入数据赋值来给num赋值在第6步结束之后才执行
}
public void print() { // 5、子类覆写的方法,而此时对象属性(num)还没有被初始化
System.out.println(this.num) ; // 6、输出,这时num还是其数据类型的默认值
}
}
public class TestDemo {
public static void main(String args[]) {
B b = new B(200) ; // 1、实例化子类对象
b.print() ; // 8、这时num值初始化为传入的200
}
}
结论:如果构造方法没有执行,那么对象中的属性一定都是其对应数据类型的默认值
抽象类中允许不定义任何的抽象方法,但是此时抽象类对象依然无法进行直接实例化处理。
abstract class A {
public void print() {}
}
public class TestDemo {
public static void main(String args[]) {
A a = new A() ;
}
}
说白了,允许是允许,但是这么做肯定有问题,所以不要这么做。
抽象类也分内部抽象类和外部抽象类,内部抽象类中可以使用static进行定义,描述为外部抽象类。
范例:观察内部抽象类
abstract class A {
public abstract void printA() ;
abstract class B { // 这种内部抽象类出现概率较小
public abstract void printB() ;
}
}
class X extends A {
public void printA() {}
class Y { // 相当于class Y extends B
public void printB() {}
}
}
public class TestDemo {
public static void main(String args[]) {
}
}
那么现在,如果外部抽象类上使用了static
,是语法错误;而如果内部抽象类上使用static
,描述为外部抽象类。
abstract class A {
public abstract void printA() ;
static abstract class B { // 这种内部抽象类出现概率较小
public abstract void printB() ;
}
}
class X extends A.B {
public void printB() {} // 这时只需要覆写B
}
抽象类的最大特点:强制规定了子类的实现结构。然而除了这一特点,抽象类还可以起到模板的作用,下面做一个分析:
现在假设有一个控制按钮,一旦向其下达了某些指令之后就可以进行相应的处理。比如:传入了工作指令,人和??就开始工作。
abstract class Action { // 描述的是一个对象的行为
// 传入的指令,对应行为
public static final int EAT = 1 ; // 注意:常量不要出现二者之和是另一个指令的情况
public static final int SLEEP = 5 ;
public static final int WORK = 10 ;
public void command(int cmd) { // 通过指令控制行为,就是题目中定义的按钮
switch (cmd) {
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 Human extends Action {
public void eat() {
System.out.println("蒸羊羔、蒸熊掌、蒸鹿尾儿、烧花鸭、烧雏鸡、烧子鹅、卤猪、卤鸭、酱鸡、腊肉、松花小肚儿、晾肉、香肠") ;
}
public void sleep() {
System.out.println("晚安") ;
}
public void work() {
System.out.println("996是福报") ;
}
}
class Pig extends Action {
public void eat() {
System.out.println("吃饲料") ;
}
public void sleep() {
System.out.println("吃完就睡多多长肉") ;
}
public void work() {} // 虽然??的功能中没有工作,但是抽象类的抽象方法必须被覆写
}
class Android extends Action {
public void eat() {
System.out.println("充电") ;
}
public void sleep() {} // 虽然??的功能中没有睡觉,但是抽象类的抽象方法必须被覆写
public void work() {
System.out.println("724全年无休") ;
}
}
public class TestDemo {
public static void main(String args[]) {
method(new Human()) ;
method(new Pig()) ;
method(new Android()) ;
}
public static void method(Action action) {
action.command(Action.EAT + Action.SLEEP + Action.WORK) ; // 按要求传入参数,比如需要吃饭就传Action.EAT
}
}
通过这个结构是为了体现:
command
);注意:
在后面学习Servlet时会对抽象类有更深的理解。
阿里云【名师课堂】Java面向对象开发65 ~ 67:抽象类的定义和使用
原文:https://www.cnblogs.com/playerone/p/13156585.html