Fork me on GitHub

Java从零开始学十八(抽象类和接口)

一、什么是抽象类和接口

抽象类、接口与类是一个层次的概念,是java中极其重要的概念。

抽象类是从多个类中抽象出来的公共模板,提供子类均具有的功能。

接口是从多个类中抽象出来的规范,体现的是规范和实现分离的原则,同时也有效的解决了java单重继承的缺陷

 二、抽象类

2.1、抽象类与普通类的区别

  • 抽象类的class前面有abstract关键字,而普通类没有
/*
 * 抽象类
 */
public abstract class Person1 {}

/*
 * 普通类
 */
public class Person {}
  • 抽象类中可以有抽象方法和普通方法,而普通类中只能有普通方法
  • 普通类可以实例化使用new,而抽象类不能实例化

2.2、抽象方法与普通方法区别

  • 抽象方法的前面有abstract关键字,而普通方法没有
  • 抽象方法没有方法体,而普通方法有方法体
    /*
     * 抽象方法
     */
    public abstract void show();
    //没有方法体

/*
     * 普通方法
     */
    public  void show(){
        System.out.println("这是个普通方法");
    }
   /*
    * 普通类中不能有抽象方法
    */

2.3、完整对比2个类

package com.pb.demo3;
/*
 * 普通类
 */
public class Person {
    private String name;  //名称
    private int age ;  //年龄
  
    
    /*
     * 普通方法
     */
    public  void show(){
        System.out.println("这是个普通方法");
    }
   /*
    * 普通类中不能有抽象方法
    */
    
    
    //setter/getter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    
}
package com.pb.demo3;
/*
 * 抽象类
 */
public abstract class Person1 {
    private String name;  //名称
    private int age ;  //年龄

    /*
     * 抽象方法
     */
    public abstract void show();
    //没有方法体
    
    
    //抽象类中可以有普通方法
    public void printSelf(){
        System.out.println("这是个抽象类中的普通方法");
        
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}

2.4、如果抽象类被继承

  • 如果子类不是抽象类,则必须重写父类抽象类的全部抽象方法。(普通方法选择重写或者不写)
package com.pb.demo3;
/*
 * 学生类继承Person1抽象类
 */
public class Student extends Person1 {
    
    //继承时,会强制要求重写父类的抽象方法
    @Override
    public void show() {
        System.out.println("重写父类的抽象方法");

    }

}

2.5 、一些注意事项

  • abstract不能与final关键字一起使用
  • private 关键字不能修饰抽象方法
  • abstract修饰的抽象方法没有方法体

2.6、图像对比

三、接口

3.1、接口定义

接口使用interface关键字来定义

简单的说,接口是一个不能实例化,且只能拥有抽象方法的类型

public interface 接口名称{

抽象方法

}
public interface Person {

}
package com.pb.demo4;

public interface Person {
    
    /*
     * 定义2个抽象方法
     */
    public void run();
    
    public  void say();

}

3.2.为什么接口中的抽象方法不用使用abstract关键字?

因为接口中只能有抽象方法,所以不必专门使用abstract关键字来修饰,当然也可以加上不过完全没有必要

3.3、接口的抽象方法

接口的抽象方法只能由public来修饰

四、使用抽象类和接口

4.1、抽象类使用继承来实现

/*
 * 抽象类
 */
public abstract class Person {
    
    /*
     * 普通方法
     */
    public void run(){
        System.out.println("抽象类的普通方法! 走一走");
    }
    
    /*
     * 抽象方法
     */
    public abstract void say();
}
/*
 * 继承抽象类
 */
public class Student  extends Person{

    @Override
    public void say() {
        System.out.println("实现父类的抽象方法!说一说");
        
    }

}
public class Test {

    public static void main(String[] args) {
        //声明子类对象
        Student stu=new Student();
        //调用子类重写的方法
        stu.say();
        //调用父类的普通方法
        stu.run();

    }

}

结果:

实现父类的抽象方法!说一说
抽象类的普通方法! 走一走

4.2、接口的使用

使用implements来实现接口,解决java中单继承的关系,接口可以是多个

package com.pb.demo4;

public interface Person {
    
    /*
     * 定义2个抽象方法
     */
    public void run();
    
    public  void say();

}
package com.pb.demo4;

/*
 * 实现接口Person
 */
public class PersonImp implements Person {

    /*
     * 必须重写接口的全部抽象方法
     */
    @Override
    public void run() {
        System.out.println("实现接口的走一走抽象方法");

    }

    @Override
    public void say() {
        System.out.println("实现接口的说一说抽象方法");

    }

}
package com.pb.demo4;

public class Test {

    public static void main(String[] args) {
        //声明对象
        PersonImp p=new PersonImp();
        //调用实现的方法
        p.run();
        p.say();

    }

}

结果:

实现接口的走一走抽象方法
实现接口的说一说抽象方法

4.3 、对比实现

五、抽象类和接口的简单区别

5.1、区别

  • 抽象类使用abstract声明,接口使用interface声明
  • 抽象类可以有抽象方法也可以有普通方法,接口只能有抽象方法
  • 实现方式不同:抽象类使用继承extends来实现,接口使用implements来实现

5.2、相同点

  • 抽象类和接口都不能实例化

5.3、图形对比

5.4、使用规则

  • 抽象类和接口都不能实例化
  • 抽象类与接口分别被继承与实现的场合,其子类必须实现其中的抽象方法
  • 抽象类中的抽象方法访问修饰符不能为private,接口中的抽象方法访问修饰符必须为public

 六、简单实现抽象类

package com.pb.demo5;
/*
 * 鸟类抽象类
 */
public abstract class Bird {

    /*
     * 飞的普通方法
     */
    public void fly(){
        System.out.println("弹射飞!");
    }
    /*
     * 攻击抽象方法
     */
    public abstract void attack();
    
}
package com.pb.demo5;
/*
 * 火箭鸟
 */
public class RocketBird extends Bird {

   /*
    * 重写攻击方法
    */
    @Override
    public void attack() {
        System.out.println("火箭鸟攻击方式:加速冲撞!");

    }
 

}
package com.pb.demo5;
/*
 * 分裂鸟
 */
public class SplittBird extends Bird {

   /*
    * 重写攻击方法
    */
    @Override
    public void attack() {
        System.out.println("分裂鸟攻击方式:分裂攻击!");
    }

   

}
package com.pb.demo5;

public class Test {

    public static void main(String[] args) {
        
        /*
         * 多态的应用
         */
        //创建鸟类对象,实例化为分裂鸟对象
        Bird splitbird=new SplittBird();
        //创建鸟类对象,实例化为火箭鸟对象
        Bird rocketbird=new RocketBird();
        //分别调用鸟类的普通飞的方法
        //分别调用子类重写后的叫方法
        //分别调用子类重写后的攻击方法
        splitbird.fly();
 
        splitbird.attack();
        
        rocketbird.fly();
   
        rocketbird.attack();
        
    }
}

结果:

弹射飞!
分裂鸟攻击方式:分裂攻击!
弹射飞!
火箭鸟攻击方式:加速冲撞!

从上例子中可以看出:子类相同的方法,如:飞的方法 可以放在父类的抽象类中使用普通方法实现,实现代码的重用,而不同的部分,使用抽象方法,子类来实现自己的方法,简单来讲:抽象类就是抽取公共的部分在抽象来中来实现

如:完全没有相同的方法,但都有这此方法,该怎么实现呢?这时候就需要接口大神出场

七、简单接口实现

还是以上例为例,比如,连有叫的方法,但每种 鸟的叫声都不一样呢?有的会叫,有的不会叫,

package com.pb.demo5;
/*
 * 叫的接口
 */
public interface Shout {
    /*
     * 叫的方法
     */
  public void shout();
}
package com.pb.demo5;

public class AoShoutImpl implements Shout {

    @Override
    public void shout() {
        System.out.println("嗷嗷叫!");

    }

}
package com.pb.demo5;

public class ZhaShoutImpl implements Shout {

    @Override
    public void shout() {
        System.out.println("喳喳叫!");

    }

}
package com.pb.demo5;

public class NoCanShoutImpl implements Shout {

    @Override
    public void shout() {
        System.out.println("不会叫!");

    }

}
package com.pb.demo5;
/*
 * 鸟类抽象类
 */
public abstract class Bird {
    Shout shout;

    /*
     * 构造方法
     */

    public Bird(Shout shout) {
        super();
        this.shout = shout;
    }
/*
 * 叫的普通方法
 */
    public void shout(){
        //调用自身叫的方法
        shout.shout();
    }
    
    /*
     * 飞的普通方法
     */
    public void fly(){
        System.out.println("弹射飞!");
    }

    /*
   * 抽象攻击方法
   */
    public abstract void attack();
    
}
package com.pb.demo5;

/*
 * 炸弹鸟
 */
public class Bombbird extends Bird {

    
    
    public Bombbird(Shout shout) {
        super(shout);
    }

    @Override
    public void attack() {
    System.out.println("炸弹鸟攻击方式:炸弹攻击");

    }

    @Override
    public void shout() {
        System.out.println("炸弹鸟:喳喳叫!");

    }

}
package com.pb.demo5;

/*
 * 胖子鸟
 */
public class Fatbird extends Bird {

    public Fatbird(Shout shout) {
        super(shout);

    }

    @Override
    public void attack() {
    System.out.println("胖子鸟攻击方式:下蛋攻击");

    }

    @Override
    public void shout() {
        System.out.println("胖子鸟:不会叫!");

    }

}
package com.pb.demo5;

/*
 * 红色鸟
 */
public class Redbird extends Bird  {

    public Redbird(Shout shout) {
        super(shout);
        
    }

    @Override
    public void attack() {
    System.out.println("红色鸟攻击方式:普通攻击");

    }

    @Override
    public void shout() {
        System.out.println("红色鸟:喳喳叫!");

    }

}
package com.pb.demo5;

import com.pb.demo5.Bird;

/*
 * 火箭鸟
 */
public class RocketBird extends Bird  {

   public RocketBird(Shout shout) {
        super(shout);
        
    }

    /*
    * 重写攻击方法
    */
    @Override
    public void attack() {
        System.out.println("火箭鸟攻击方式:加速冲撞!");

    }
   
    /*
     * 重写叫的方法
     */
    @Override
    public void shout() {
        System.out.println("火箭鸟:嗷嗷叫!");
        
    }
  

}
package com.pb.demo5;



/*
 * 分裂鸟
 */
public class SplittBird extends Bird {

   public SplittBird(Shout shout) {
        super(shout);
        
    }
    /*
    * 重写攻击方法
    */
    @Override
    public void attack() {
        System.out.println("分裂鸟攻击方式:分裂攻击!");
    }
    /*
     * 重写叫的方法
     */
    @Override
    public void shout() {
        System.out.println("分裂鸟:嗷嗷叫!");
        
    }

}
package com.pb.demo5;

import com.pb.demo5.Bird;

public class Test {

    public static void main(String[] args) {
        /*
         * 创建接口对象
         */
        Shout  aoshout=new AoShoutImpl();
        Shout zhashout=new ZhaShoutImpl();
        Shout noshout=new NoCanShoutImpl();
        /*
         * 多态的应用
         */
        //创建鸟类对象,实例化为分裂鸟对象
        Bird splitbird=new SplittBird(aoshout);
        Bird rocketbird=new RocketBird(aoshout);
        Bird bomb=new Bombbird(zhashout);
        Bird redbird=new Redbird(zhashout);
        Bird fatbird=new Fatbird(noshout);
        splitbird.fly();
        splitbird.attack();
        splitbird.shout();
    
        rocketbird.fly();
        rocketbird.shout();
        rocketbird.attack();
        
        bomb.fly();
        bomb.shout();
        bomb.attack();
      
        redbird.fly();
        redbird.shout();
        redbird.attack();
        
        fatbird.fly();
        fatbird.shout();
        fatbird.attack();
        
        
    }
}

结果:

弹射飞!
分裂鸟攻击方式:分裂攻击!
分裂鸟:嗷嗷叫!
弹射飞!
火箭鸟:嗷嗷叫!
火箭鸟攻击方式:加速冲撞!
弹射飞!
炸弹鸟:喳喳叫!
炸弹鸟攻击方式:炸弹攻击
弹射飞!
红色鸟:喳喳叫!
红色鸟攻击方式:普通攻击
弹射飞!
胖子鸟:不会叫!
胖子鸟攻击方式:下蛋攻击

由上可以看出:抽象类方便代码复用,接口方便代码维护

posted @ 2015-02-19 14:13  森林森  阅读(701)  评论(0编辑  收藏  举报