Java面向对象 第5节 抽象类和接口

一、抽象类和抽象方法

  1. 区分抽象方法和普通方法
    1)当一个方法被abstract修饰时,该方法成为抽象方法
    2)抽象类所在的类必须定义为抽象类
    3)抽象方法不会有具体的实现,而是在抽象类的子类中通过方法重写进行实现
    4)定义抽象方法语法:
    [访问修饰符]  abstract  <返回类型> <方法名>([参数类表])
    5)区别:
      抽象方法需要用abstract修饰,普通方法不需要;抽象方法没有方法体
  2. 区分普通类和抽象类
    1)当一个类被abstract修饰时被称为抽象类
    2)定义抽象类:abstract  class <类名>{    }
    3)区别:
      抽象类需要用abstract修饰,普通类不需要;
           普通类可以实例化,抽象类不能被实例化(但可以创建一个引用变量,其类型是一个抽象类,指向非抽象的子类实例)
  3. 抽象类结构
    public abstract  class 类名{
        修饰符  abstract  返回值类型 方法名();
        修饰符  返回值类型  方法名(){ 
             方法体
        }
  4. 抽象类和抽象方法的使用:
    抽象方法只能定义在抽象类中,抽象类中可以包含抽象方法和普通方法及普通类包含的一切成员;
    如果子类没有实现父类的所有抽象方法,则子类必须定义为抽象类;
    没有抽象构造方法,也没有抽象静态方法;
    抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
package com.abstractInterface;
public abstract class Base {
	//抽象类中可以没有抽象方法,但包含了抽象方法的类就必须被定义为抽象类
	public abstract void method1();
	public abstract void method2();
	public void method3(){}
	//没有抽象的构造方法
	//public abstract Base(){}
	//没有抽象的静态方法
	//static abstract void method4();

	public Base(){
		System.out.println("父类的无参构造方法");
	}
	static void method4(){
		System.out.print("静态方法表示类所特有的功能,这种功能的实现不依赖于类的具体实例,也不依赖于它的子类。因此,当前类必须为静态方法提供实现");
	}
}

  

package com.abstractInterface;
//如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类
public abstract class Sub1 extends Base {
	public void method1() {
		System.out.println("重写父类的method1");
	}
}

  

package com.abstractInterface;
//否则就必须实现父类的所有抽象方法
public class Sub2 extends Base {
	public Sub2(){
		System.out.println("子类的无参构造方法");
	}
	@Override
	public void method1() {
		System.out.println("重写父类的抽象方法method1");
	}
	@Override
	public void method2() {
		System.out.println("重写父类的抽象方法method2");
	}
}

  

public class Test {
	public static void main(String[] args) {
		//抽象类不允许实例化
		//Base base=new Base();
		//抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
		//抽象类不能被实例化,但可以创建一个引用变量,其类型是一个抽象类,指向非抽象的子类实例
		Base sub=new Sub2();
		sub.method1();
		sub.method4();
	}
}

  

二、抽象类的优势

   

  如图,设计一个抽象类,它有两个普通方法:飞行(弹射飞)和叫(嗷嗷),还有一个抽象方法攻击。分裂鸟和火箭鸟为这个抽象类的子类。
  分裂鸟和火箭鸟都继承了父类的飞行和叫的方法,并重写了父类的攻击方法(两种鸟的攻击方式不同)。

  总结:抽象类中已经实现的方法可以被其子类使用,使得代码可以被复用;同时提供了抽象方法,保证了子类具有自身的独特性

三、抽象类的局限性

   "愤怒的小鸟"的游戏中,分裂鸟和火箭鸟的叫声都是“嗷嗷”,但是红色鸟和炸弹鸟飞出来后是“渣渣”叫,胖子鸟飞出来后干脆不叫,所以类图做如下修改:

  

  此时,使用抽象类就会出现以下问题:1.叫的方法不在通用;2.子类继承鸟抽象类后,写出来的叫的方法可能会出现代码重复的情况,如红色鸟和炸弹鸟都是“喳喳“叫。

  问题1,可以将叫方法给抽象方法,由其子类去具体实现;但这样会造成代码冗余的问题,如这里的分裂鸟和火箭鸟的叫方法也会一样,也就是问题2会更加突出。

  为解决上述问题,最理想的方法是使用接口。

四、接口

  

  生活中,常见的如USB接口有以下特点:USB接口本身没有实现任何功能;USB接口规定了数据传输的要求;USB接口可以被多种USB设备实现

  1. 接口概念
    java中接口的作用和生活中的接口类似,他提供一种约定,是的实现接口的类早形式上保持一致。
    如果抽象类中所有的方法都是抽象方法,就可以使用java提供的接口来表示,所以,从这个角度来讲,接口是一种特殊的”抽象类“,但两者语法和设计理念都不同
  2. 定义和实现一个简单的接口


    接口是一个不能实例化的类型,需要注意:
    1)接口:接口中不能有构造方法;
                    接口使用interface修饰符,访问修饰符只能是public,且可选;
               接口成员可以是全局变量和公共的抽象方法(默认用 public 修饰);
                    接口中的变量都是静态常量(public static final),并必须指定初始值;
    2)实现接口:实现接口用implements关键字;
                      实现接口的类必须实现接口中定义的所有抽象方法,否则必须定义为抽象类;
                           接口的实现类中允许包含普通方法;
                           实现类可以实现多各接口;

    package com.interfaceDemo;
    /**
     * USB接口。
     * @author yu
     */
    public interface UsbInterface {
    	/**
    	 * USB接口提供服务。
    	 */
    	void service();
    }
    

      

    package com.interfaceDemo;
    /**
     * U盘。
     * @author yu
     */
    public class UDisk implements UsbInterface {
    	public void service() {
    		System.out.println("连接USB口,开始传输数据。");
    	}
    }
    

      

    package com.interfaceDemo;
    /**
     * USB风扇。
     * @author yu
     */
    public class UsbFan implements UsbInterface {
    	public void service() {
    		System.out.println("连接USB口,获得电流,风扇开始转动。");
    	}
    }
    

      

    package com.interfaceDemo;
    /**
     * 测试类。
     * @param args
     */
    public class Test {
    	public static void main(String[] args) {
    		//1、U盘
    		UsbInterface uDisk = new UDisk();
    		uDisk.service();
    		//2、USB风扇
    		UsbInterface usbFan= new UsbFan();
    		usbFan.service();
    	}
    }
  3. 更复杂的接口
    1)接口本身也可以继承接口:
      [修饰符] interface 接口名 extends 父接口1,父接口2,....{
               常量定义;
               方法定义;
           }
    2)一个普通类只能继承一个父类,但能同时实现多个接口,也可以同时继承抽象类和实现接口:
          class 类名 extends 父类名 implements 接口1,接口2,....{
             类的成员;
          }
    package com.interfaceDemo;
    /**
     * 鸟叫的接口
     * @author yu
     */
    public interface ShoutAbility {
    	/**
    	 * USB接口提供服务。
    	 */
    	public void shout();   //鸟叫的抽象方法
    }
    /****************************************/
    package com.interfaceDemo;
    /**
     * 嗷嗷叫
     * @author yu
     */
    public class AoShout implements ShoutAbility {
    	public void shout() {
    		System.out.println("嗷嗷。。。。。");
    	}
    }
    /******************************************/
    package com.interfaceDemo;
    /**
     * USB风扇。
     * @author yu
     */
    public class ZhaShout implements ShoutAbility {
    	public void shout() {
    		System.out.println("喳喳。。。。。");
    	}
    }
    /******************************************/
    package com.interfaceDemo;
    /*
     * 无叫声
     */
    public class NoShout implements ShoutAbility{
        public void shout(){
            //无叫声
        }
    }
    /******************************************/
    package com.interfaceDemo;
    /*
     * 鸟类
     */
    public abstract class Bird {
        ShoutAbility shoutAbility;   //鸟叫的方式
        String birdName;  //鸟的名字
        //构造方法,用来初始化鸟叫的行为
        //构造方法
    //    public Bird(String birdName){
    //        this.birdName = birdName;
    //    }
        public Bird(ShoutAbility shoutAbility,String birdName){
            this.shoutAbility = shoutAbility;
            this.birdName = birdName;
        }
        //叫
        public void Shout(){
            shoutAbility.shout();
        }
        //飞行
        public void fly(){
            System.out.println(this.birdName+"弹射飞!");
        }
        //攻击
        public abstract void attrack();
    }
    /********************************/
    package com.interfaceDemo;
    /*
     * 分裂鸟
     */
    public class SplitBird extends Bird{
        //构造方法
        public SplitBird(ShoutAbility shoutAbility,String birdName){
            super(shoutAbility,birdName);
        }
        //重写分裂方法
        public void attrack(){
            System.out.println("分裂攻击!");
        }
    
    }
    /************************************/
    package com.interfaceDemo;
    /*
     * 火箭鸟
     */
    public class RocketBird extends Bird{
        public RocketBird(ShoutAbility shoutAbility,String birdName){
            super(shoutAbility,birdName);
        }
        public void attrack(){
            System.out.println("加速冲撞!");
        }
    }
    /********************************************/
    package com.interfaceDemo;
    /*
     * 红色鸟
     */
    public class RedBird extends Bird{
        //构造方法
        public RedBird(ShoutAbility shoutAbility,String birdName){
            super(shoutAbility,birdName);
        }
        //重写分裂方法
        public void attrack(){
            System.out.println("普通攻击!");
        }
    }
    /******************************************/
    package com.interfaceDemo;
    /*
     * 炸弹鸟
     */
    public class BombBird extends Bird{
        //构造方法
        public BombBird(ShoutAbility shoutAbility,String birdName){
            super(shoutAbility,birdName);
        }
        //重写分裂方法
        public void attrack(){
            System.out.println("爆炸攻击!");
        }
    }
    /********************************************/
    package com.interfaceDemo;
    /*
     * 胖子鸟
     */
    public class FatBird extends Bird{
        //构造方法
        public FatBird(ShoutAbility shoutAbility,String birdNme){
            super(shoutAbility,birdNme);
        }
        //重写分裂方法
        public void attrack(){
            System.out.println("扔蛋攻击!");
        }
    }
    /********************************************/
    package com.interfaceDemo;
    
    import java.text.Bidi;
    
    /**
     * 测试类。
     * @param args
     */
    public class Test {
    	public static void main(String[] args) {
    		ShoutAbility shoutAbility = new AoShout();  //嗷嗷叫
    		ShoutAbility shoutAbility1 = new ZhaShout();  //喳喳叫
    		ShoutAbility shoutAbility2 = new NoShout();  //无叫声
    
    		Bird bird = new SplitBird(shoutAbility,"分裂鸟");
    		bird.fly();
    		bird.Shout();
    		bird.attrack();
    
    		Bird bird1 = new RocketBird(shoutAbility,"火箭鸟");
    		bird1.fly();
    		bird1.Shout();
    		bird1.attrack();
    
    		Bird bird2 = new RedBird(shoutAbility1,"红鸟");
    		bird2.fly();
    		bird2.Shout();
    		bird2.attrack();
    
    		Bird bird3 = new BombBird(shoutAbility1,"爆炸鸟");
    		bird3.fly();
    		bird3.Shout();
    		bird3.attrack();
    
    		Bird bird4 = new FatBird(shoutAbility2,"胖子鸟");
    		bird4.fly();
    		bird4.Shout();
    		bird4.attrack();
    
    	}
    }
    

      

  4. 面向对象的设计原则
    1)摘取代码中变化的行为,形成接口
    2)多用组合,少用继承
    3)针对接口编程,不依赖于具体实现:具体代码实现中,体现在方法参数尽量使用接口,方法的返回值尽量使用接口,属性类型尽量使用接口等
    4)针对扩展开放,针对改变关闭:项目中需求发生变化,应添加一个新的接口或类,而不要去修改源码
    总的来说,接口和抽象类是实现堕胎的2种重要方式,是面向对象设计的基础

转载于:https://www.cnblogs.com/yutianbao/p/10562297.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值