zoukankan      html  css  js  c++  java
  • Java开发笔记(五十七)因抽象方法而产生的抽象类

    前面介绍了类的常见用法,令人感叹面向对象的强大,几乎日常生活中的所有事物,都可以抽象成Java的基类及其子类。然而抽象操作也有副作用,就是某个抽象而来的行为可能是不确定的,比如半夜鸡叫,如果是公鸡则必定“喔喔喔”地叫,如果是母鸡则必定“咯咯咯”地叫,可要是不能确定这只鸡是公鸡还是母鸡抑或小鸡,系统怎么知道它会怎么叫?落实到鸡类Chicken的定义代码中,它的call方法便无法给出具体的叫声了,尽管鸡类能够派生出公鸡类和母鸡类,再在公鸡类和母鸡类重写call方法,但是外部仍然可以创建鸡类的实例,接着调用鸡类实例的call方法,此时该期望这只鸡发出什么叫声呢?不管是让鸡类胡言乱语、语无伦次,还是让鸡类默不作声、噤若寒蝉,显然都与真实情况有很大出入。
    由此可见,某些类其实并不能拿来直接使用,充其量只能算半成品,必须经过进一步的加工,形成最终的成品方能给外部调用。鉴于前述的鸡类存在叫唤这个不确定的方法,故而理应将它归入半成品之列;至于由鸡类派生而来的公鸡类与母鸡类,因为包括叫唤在内的每个方法都是明确的,所以它们才成为机能鉴权的完整类。在Java编程中,功能不确定的方法被称作抽象方法,而包含抽象方法的类受到牵连就变成了抽象类。在类的定义代码里面,通过关键字abstract来标识抽象方法及抽象类;凡是被abstract修饰的抽象方法,由于方法的具体实现并不明确,因此抽象方法没有花括号所包裹着的方法体;凡是被abstract修饰的抽象类,由于包含了至少一个抽象方法,因此不允许外部创建抽象类的实例,否则就会出现鸡类实例不知如何叫唤的尴尬。除此之外,抽象类还有下列两点需要注意:
    1、abstract只能用来修饰抽象方法和抽象类,不可用于修饰成员属性,因为属性值本身就允许通过赋值来改变,无所谓抽象不抽象。
    2、虽然抽象类依旧可以拥有构造方法,但它的构造方法并不能被外部直接调用,因为外部不允许通过构造方法来创建抽象类的实例,抽象类的构造方法只能提供给它的子类调用。
    絮絮叨叨了这么多抽象概念,接着尝试把之前的鸡类改写成抽象类,修改后的抽象鸡类定义代码示例如下:

    //演示抽象类的定义
    abstract public class Chicken {
    
    	// 定义一个名称属性
    	public String name;
    	// 定义一个性别属性
    	public int sex;
    	
    	// 定义一个抽象的叫唤方法。注意后面没有花括号,并且以分号结尾
    	abstract public void call();
    
    	// 即使抽象类定义了构造方法,外部也无法创建它的实例
    	public Chicken() {
    	}
    
    	// Java只有抽象类和抽象方法,没有抽象属性的说法
    	//abstract public String cry;
    }
    

    然后分别编写继承自鸡类的公鸡类和母鸡类,其中鸡类的抽象方法call是必须在子类中重写的,只有这样,派生而来的子类才具备所有完善的行为动作;否则的话,这个子类仍旧是个尚未完工的半成品,依然属于抽象类的行列。下面是重写了call方法的公鸡类代码例子:

    //定义一个继承自抽象鸡类的公鸡类
    public class Cock extends Chicken {
    	
    	public Cock() {
    		// 公鸡的性别固定为雄性
    		sex = 0;
    	}
    
    	// 重写了公鸡的叫唤方法。如果不重写父类的抽象方法,那么该子类仍旧为抽象类
    	public void call() {
    		System.out.println("喔喔喔");
    	}
    }
    

    同样重写了call方法的母鸡类代码如下所示:

    //定义一个继承自抽象鸡类的母鸡类
    public class Hen extends Chicken {
    	
    	public Hen() {
    		// 母鸡的性别固定为雌性
    		sex = 1;
    	}
    
    	// 重写了母鸡的叫唤方法。如果不重写父类的抽象方法,那么该子类仍旧为抽象类
    	public void call() {
    		System.out.println("咯咯咯");
    	}
    }
    

    最后轮到外部调用各种鸡类了,对于外部而言,唯一的区别是外部不能创建抽象类的实例,其它子类的调用则跟从前一样没有变化。具体的外部调用代码见下:

    		// 不能创建抽象类的实例,因为抽象类是个尚未完工的类
    		//Chicken chicken  = new Chicken();
    		// 创建一个公鸡实例,公鸡类继承自抽象类Chicken
    		Cock cock = new Cock();
    		cock.call(); // 调用公鸡实例的叫唤方法
    		// 创建一个母鸡实例,母鸡类继承自抽象类Chicken
    		Hen hen = new Hen();
    		hen.call(); // 调用母鸡实例的叫唤方法
    

    运行上面的调用代码,得到以下的日志结果,可见子类重写后的call方法正常工作。

    喔喔喔
    咯咯咯
    

      

    更多Java技术文章参见《Java开发笔记(序)章节目录

  • 相关阅读:
    StackExchange.Redis 使用 (一)
    委托的一个小问题
    MemberwishClone学习
    类的内容学习
    类的学习
    构造函数学习
    C# 重新筑基-从头开始
    C语言入门:结构体+文件的应用
    C语言入门:结构体的概要
    C语言入门:指针的概要
  • 原文地址:https://www.cnblogs.com/pinlantu/p/10355078.html
Copyright © 2011-2022 走看看