一、抽象类的定义语法:
1.普通类可以直接产生实例化对象,并且在普通类之中可以包含有构
造方法、普通方法、static方法、常量、变量等内容,而所谓的抽象
类就是指在普通类的结构里面增加抽象方法的组成部分。
所有的普通方法都会有个“{}”,表示方法体,有方法体的方法一定可
以被对象直接使用,而抽象方法指的是没有方法体的方法,同时抽象
方法还必须使用abstract关键字进行定义。
拥有抽象方法的类一定属于抽象类,抽象类要使用abstract声明。
范例:定义抽象类:
abstract class A{//定义一个抽象类
public void fun(){//抽象方法
System.out.println(“存在有方法体的方法!”);
}
//此方法并没有方法体的声明,并且存在有abstract关键字,表示抽象方法
public abstract void print();
}
public class A{//
public static void main(String args[]){
A a = new A();//A是抽象的;无法实例化
a.fun();
a.print();
}
}
运行结果错误,不能直接对A类对象实例化。之所以不能够实例化对象原因很简单:当一个类的对象实例化之后就意味着这个对象可以调用类中的属性或方法,但是在抽象类里面存在有抽象方法,抽象方法没有方法体,既然没有方法体,怎么可能去调用?既然不能调用,怎么产生实例化对象?
抽象类的使用原则:
1.抽象类必须有子类,即:每一个抽象类一定要被子类所继承
2.抽象类的子类(子类不是抽象类)必须要覆写抽象类之中的全部抽象方法(强制子类覆写)
3.抽象类的对象实例化需要依靠子类完成,采用向上转型的方式处理
范例:正确使用抽象类:
abstract class A{//定义一个抽象类
public void fun(){//抽象方法
System.out.println(“存在有方法体的方法!”);
}
//此方法并没有方法体的声明,并且存在有abstract关键字,表示抽象方法
public abstract void print();
}
//一个子类只能够继承一个抽象类,属于单继承局限
class B extends A{//B类是抽象类的子类,并且是一个抽象类的子类,并且是一个普通类
public void print(){//强制要求覆写的方法
System.out.println(“Hello World !”);
}
}
public class TestDemo{//
public static void main(String args[]){
A a = new B();//向上转型
a.print(); //被子类所覆写过的方法
}
}
总结:
1.抽象类继承子类里面会有明确的方法覆写要求,而普通类并没有;2.抽象类只比普通类多了一些抽象方法的定义,其他的组成部分与普通类完全一样;
3.普通类对象可以直接实例化,但是抽象类的对象必须经过向上转型之后才可以得到实例化对象。
虽然一个子类可以去继承任意的一个普通类,可是从开发的实际要求来讲,普通类最多不要去继承另外一个普通类,而只能继承抽象类。
二、抽象类的使用限制
1.抽象类里面由于会存在一些属性,那么在抽象类之中一定会存在构造方法,目的:为属性初始化,并且子类对象实例化的时候依然满足于先执行父类构造,再调用子类构造的情况。
2.抽象类能不用使用final:因为抽象类必须有子类,而final定义的类不能够有子类;
3.抽象类不允许使用static声明,而内部的抽象类允许使用static声明,使用static声明的内部抽象类就相当于是一个外部抽象类,继承的时候使用”外部类.内部类”的形式表示类名称。
eg:
abstract class A {//定义一个抽象类
//static定义的内部类属于外部类
static abstract class B {
public abstract void print();
}
}
class X extends A.B {
public void print(){
System.out.println(“***********”);
}
}
public class TestDemo{
public static void main(String args []){
A.B ab = new X();//向上转型
ab.print();
}
}
4.任何情况下,如果要执行类中的static方法的时候,都可以在没有对象的时候,直接调用,对于抽象类也是一样。
eg:
abstract class A {
public static void print(){
System.out.println(“Hello World!”);
}
}
public class TestDemo{
public static void main(String args[]){
A.print();
}
}
5.有些时候,由于抽象类只需要一个特定的系统子类操作,所以可以忽略掉外部子类。
eg:
abstract class A {//定义一个抽象类
public abstract void print();
private static class B extends A {//内部抽象类子类
public void print(){//覆写抽象类的方法
System.out.println(“Hello World!”);
}
}
//这个方法不受实例化对象的控制
public static A getInstance(){
return new B();
}
}
public class TestDemo{
public static void main(String args[]){
//此时取得抽象类对象的时候完全不需要知道A有一个子类B
A a = A.getInstance();
a.print();
}
}
这样的设计在系统类库之中会比较常见,目的:为用户隐藏不需要知道的子类。
遗留问题:
首先看一段代码:
abstract class A {
public A(){//2.父类构造方法
this.print();//3.调用print()方法
}
public abstract void print();
}
class B extends A{
private int num = 100;
public B(int num){
this.num = num;
}
public void print(){//4.调用覆写后的方法
System.out.println(“num = “+num);//num还没初始化,内容是其对应数据类型的默认值
}
}
public class TestDemo{
public static void main(String args[]){
new B(30);//1、执行构造
}
}
输出结果是num = 0;
解决思路:在任何一个类的构造执行完之前,所有属性的内容都是其对应数据类型的默认值,而子类构造执行之前一定先执行父类构造,那么此时子类构造由于没有执行,所以num就是0.
三、抽象类应用–模版设计(理解)
例如:现在有三类事物:
机器人:充电、工作
人:吃饭、工作、睡觉
猪:吃饭、睡觉
要求可以实现以上的操作控制,即可以任意的控制人、机器人、猪的操作行为(吃、工作、睡觉)
eg:
定义行为类:
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(){
}
}
1.普通类可以直接产生实例化对象,并且在普通类之中可以包含有构
造方法、普通方法、static方法、常量、变量等内容,而所谓的抽象
类就是指在普通类的结构里面增加抽象方法的组成部分。
所有的普通方法都会有个“{}”,表示方法体,有方法体的方法一定可
以被对象直接使用,而抽象方法指的是没有方法体的方法,同时抽象
方法还必须使用abstract关键字进行定义。
拥有抽象方法的类一定属于抽象类,抽象类要使用abstract声明。
范例:定义抽象类:
abstract class A{//定义一个抽象类
public void fun(){//抽象方法
System.out.println(“存在有方法体的方法!”);
}
//此方法并没有方法体的声明,并且存在有abstract关键字,表示抽象方法
public abstract void print();
}
public class A{//
public static void main(String args[]){
A a = new A();//A是抽象的;无法实例化
a.fun();
a.print();
}
}
运行结果错误,不能直接对A类对象实例化。之所以不能够实例化对象原因很简单:当一个类的对象实例化之后就意味着这个对象可以调用类中的属性或方法,但是在抽象类里面存在有抽象方法,抽象方法没有方法体,既然没有方法体,怎么可能去调用?既然不能调用,怎么产生实例化对象?
抽象类的使用原则:
1.抽象类必须有子类,即:每一个抽象类一定要被子类所继承
2.抽象类的子类(子类不是抽象类)必须要覆写抽象类之中的全部抽象方法(强制子类覆写)
3.抽象类的对象实例化需要依靠子类完成,采用向上转型的方式处理
范例:正确使用抽象类:
abstract class A{//定义一个抽象类
public void fun(){//抽象方法
System.out.println(“存在有方法体的方法!”);
}
//此方法并没有方法体的声明,并且存在有abstract关键字,表示抽象方法
public abstract void print();
}
//一个子类只能够继承一个抽象类,属于单继承局限
class B extends A{//B类是抽象类的子类,并且是一个抽象类的子类,并且是一个普通类
public void print(){//强制要求覆写的方法
System.out.println(“Hello World !”);
}
}
public class TestDemo{//
public static void main(String args[]){
A a = new B();//向上转型
a.print(); //被子类所覆写过的方法
}
}
总结:
1.抽象类继承子类里面会有明确的方法覆写要求,而普通类并没有;2.抽象类只比普通类多了一些抽象方法的定义,其他的组成部分与普通类完全一样;
3.普通类对象可以直接实例化,但是抽象类的对象必须经过向上转型之后才可以得到实例化对象。
虽然一个子类可以去继承任意的一个普通类,可是从开发的实际要求来讲,普通类最多不要去继承另外一个普通类,而只能继承抽象类。
二、抽象类的使用限制
1.抽象类里面由于会存在一些属性,那么在抽象类之中一定会存在构造方法,目的:为属性初始化,并且子类对象实例化的时候依然满足于先执行父类构造,再调用子类构造的情况。
2.抽象类能不用使用final:因为抽象类必须有子类,而final定义的类不能够有子类;
3.抽象类不允许使用static声明,而内部的抽象类允许使用static声明,使用static声明的内部抽象类就相当于是一个外部抽象类,继承的时候使用”外部类.内部类”的形式表示类名称。
eg:
abstract class A {//定义一个抽象类
//static定义的内部类属于外部类
static abstract class B {
public abstract void print();
}
}
class X extends A.B {
public void print(){
System.out.println(“***********”);
}
}
public class TestDemo{
public static void main(String args []){
A.B ab = new X();//向上转型
ab.print();
}
}
4.任何情况下,如果要执行类中的static方法的时候,都可以在没有对象的时候,直接调用,对于抽象类也是一样。
eg:
abstract class A {
public static void print(){
System.out.println(“Hello World!”);
}
}
public class TestDemo{
public static void main(String args[]){
A.print();
}
}
5.有些时候,由于抽象类只需要一个特定的系统子类操作,所以可以忽略掉外部子类。
eg:
abstract class A {//定义一个抽象类
public abstract void print();
private static class B extends A {//内部抽象类子类
public void print(){//覆写抽象类的方法
System.out.println(“Hello World!”);
}
}
//这个方法不受实例化对象的控制
public static A getInstance(){
return new B();
}
}
public class TestDemo{
public static void main(String args[]){
//此时取得抽象类对象的时候完全不需要知道A有一个子类B
A a = A.getInstance();
a.print();
}
}
这样的设计在系统类库之中会比较常见,目的:为用户隐藏不需要知道的子类。
遗留问题:
首先看一段代码:
abstract class A {
public A(){//2.父类构造方法
this.print();//3.调用print()方法
}
public abstract void print();
}
class B extends A{
private int num = 100;
public B(int num){
this.num = num;
}
public void print(){//4.调用覆写后的方法
System.out.println(“num = “+num);//num还没初始化,内容是其对应数据类型的默认值
}
}
public class TestDemo{
public static void main(String args[]){
new B(30);//1、执行构造
}
}
输出结果是num = 0;
解决思路:在任何一个类的构造执行完之前,所有属性的内容都是其对应数据类型的默认值,而子类构造执行之前一定先执行父类构造,那么此时子类构造由于没有执行,所以num就是0.
三、抽象类应用–模版设计(理解)
例如:现在有三类事物:
机器人:充电、工作
人:吃饭、工作、睡觉
猪:吃饭、睡觉
要求可以实现以上的操作控制,即可以任意的控制人、机器人、猪的操作行为(吃、工作、睡觉)
eg:
定义行为类:
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 TestDemo{
public static void main(String args[]){
//执行fun()方法
fun(new Robot());
fun(new Human());
fun(new Pig());
}
public static void fun(Action act){//创建Action类的对象act,可以使用Action的方法command。
act.command(Action.EAT);//传入Action类的常量
act.command(Action.SLEEP);
act.command(Action.work);
}
}
这三个都属于行为的子类,所以都可以通过行为来控制,这些不同的类型最终都在行为上成功的进行了抽象,即:如果要想使用行为操作,那么就必须按照Action类的标准来实现子类。
总结:
1.如果你真的要使用类继承的话,那么就使用抽象类(20%的情况下可能这样使用)。
2.抽象类强制规定了子类必须要做的事情,而且可以与抽象类的普通方法相配合
3.不管抽象类如何努力都有一个天生最大的问题:单继承局限。
版权声明:本文为mxd147258369原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。