JAVA学习脚印5: 继承特性及特殊类

JAVA学习脚印5: 继承特性及特殊类

本节将学习类的继承特性及一些特殊类,本节所述实例中的类设计参考自《java核心技术》。


1.java继承特点

 

· java中使用关键字extends表示继承,所有的继承都是公有public继承(区别于c++中的三种继承方式即public、protected、private)。

· 子类中可以增加域、增加方法或者覆盖超类的方法,但是绝对不能删除继承的任何域和方法。因此在设计类的时候应该将通用的方法放在超类中,而将具有特殊用途的方法放在子类中。

· 子类可以通过super关键字类调用超类的方法或者超类的构造器,可以使用this关键字类引用隐式参数或者调用本类的其他构造器。注意super关键字不是一个对象的引用,不能将其赋给另一个对象变量,它只是一个编译器调用超类方法的特有关键字。

经理与雇员类的设计如图1所示:


图1 职员与经理类的继承关系图


测试代码如例5-1:

5-1 ManagerTest.java

package com.learningjava;

import java.util.Date;
import java.util.GregorianCalendar;

/**
 * this program demonstrate inheritance
 * from the book 《Core Java,Volume I:Fundamentals》
 */
public class ManagerTest {
	public static void main(String[] args) {
		Employee[] staffs = new Employee[3];
		staffs[0] = new Employee("Steve",5000,1985,9,4);
		staffs[1] = new Employee("Jason",6000,1983,8,12);
		Manager mgr = new Manager("Jery",8000,1980,11,7);
		mgr.setBonus(5000);
		staffs[2] = mgr;
		for(Employee item : staffs)
			System.out.println("name= "+item.getName()+
					",salary= "+item.getSalary());
	}
}
/**
 * a class to descript employee
 * from the book 《Core Java,Volume I:Fundamentals》

 */
class Employee {
	/**
	 * @param name name to set
	 * @param salary salary to set
	 * @param hireday hireday to set
	 */
	public Employee(String name, double salary, Date hireday) {
		this.name = name;
		this.salary = salary;
		this.hireday = hireday;
		setId();
	}
	/**
	 * 
	 * @param name name to set
	 * @param salary salary to set
	 * @param year month day  to create a GregorianCalendar
	 */
	public Employee(String name, double salary, int year,int month,int day) {
		this.name = name;
		this.salary = salary;
		GregorianCalendar calendar = new GregorianCalendar(year,month-1,day);
		this.hireday = calendar.getTime();
		setId();
	}
	public void raiseSalary(double percent) {
		double raise = salary*percent/100;
		salary += raise;
	}
	public String getName() {
		return name;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public Date getHireday() {
		return hireday;
	}
	public void setHireday(Date hireday) {
		this.hireday = hireday;
	}
	public int getId() {
		return id;
	}
	private void setId() {
		this.id = nextId;
		nextId++;
	}
	private String name; 
	private double salary;
	private Date hireday;
	private int id;
	private static int nextId = 1;
}
/**
 *  a class to descript manager
 *
 */
class Manager extends Employee {

	public void setBonus(double b) {
		bonus = b;
	}
	public Manager(String name, double salary, int year,int month,int day) {
		super(name, salary,year,month,day);
		bonus = 0;
	}
	public Manager(String name, double salary, Date hireday) {
		super(name, salary, hireday);
		bonus = 0;
	}
	@Override
	public double getSalary() {
		double baseSalary = super.getSalary();
		return baseSalary+bonus;
	}
	
	private double bonus;
}

· 检验是否应该使用继承的规则

类之间最常见的有三种关系即,依赖(use-a)、聚合(has-a)、继承(is-a)关系。

is-a表明子类的每个对象也是超类的对象。例如每个经理都是雇员,因此可以将Manager类设计成为Employee类的子类,反之每个雇员却并不都是经理。

2.java中的特殊类

1) final类——阻止继承

如果希望阻止人们继承某个类,可以使用final关键字将该类定义为final类,String类就是一个final类,声明为public final class String。final关键字作用于类的域时称为final域,表明该域在构造对象以后就不能修改其值了;final作用于方法时称为final方法,表明该方法不能被子类覆盖。注意,final类的方法自动地成为final方法,而域不自动为final域。

阻止继承主要是为了确保它们不会在子类中改变语义。

 

2) abstract类——高层次抽象

抽象类是对类进行高度抽象后形成的类,它比一般类更加通用。

规定,包含一个或多个抽象方法的类本身必须声明为抽象类。

抽象方法起着占位的作用,它的具体实现在它的具体实现子类中。注意,拓展抽象类有两种选择。一种是在子类中定义全部的抽象的方法,这样一来,子类不再抽象;还有一种是子类中定义部分抽象方法或抽象方法也不定义,这样子类也成为抽象类。

  注意,类即使不含抽象方法,也可以将其声明为抽象类。

  注意,抽象类不能创建出实例,而只作为派生其他类的基类。但是可以定义一个抽象类的  对象引用变量,用于引用非抽象子类的对象。

例如设计一个抽象类层次如下图2所示:



抽象继承关系

具体可参考例5-2:

5-2  PersonTest.java

package com.learingjava;

import java.util.Date;
import java.util.GregorianCalendar;

/**
 * this program demonstrates abstract classes
 * from the book 《Core Java,Volume I:Fundamentals》
 */
public class PersonTest {
	public static void main(String[] args) {
		Person[] people = new Person[2];
		//fill array
		people[0] = new Employee("Steven",5000,1985,9,4);
		people[1] = new Student("Jobs","computer science");
		//print info
		for(Person item : people)
			System.out.println(item.getName()+","+item.getDescription());
	}
}
/**
 * an abstract class 
 * with abstract method getDescription()
 */
abstract class Person {
	
	public Person(String name) {
		super();
		this.name = name;
	}
    public String getName() {
    	return name;
    }
    //abstract method
    public abstract String getDescription();
	private String name;
}
/**
 * a class to descript employee
 * from the book 《Core Java,Volume I:Fundamentals》
 */
class Employee extends Person{
	/**
	 * @param name name to set
	 * @param salary salary to set
	 * @param hireday hireday to set
	 */
	public Employee(String name, double salary, Date hireday) {
		super(name);
		this.salary = salary;
		this.hireday = hireday;
		setId();
	}
	/**
	 * 
	 * @param name name to set
	 * @param salary salary to set
	 * @param year month day  to create a GregorianCalendar
	 */
	public Employee(String name, double salary, int year,int month,int day) {
		super(name);
		this.salary = salary;
		GregorianCalendar calendar = new GregorianCalendar(year,month-1,day);
		this.hireday = calendar.getTime();
		setId();
	}
	public void raiseSalary(double percent) {
		double raise = salary*percent/100;
		salary += raise;
	}
	@Override
	public String getDescription() {
		return String.format("an employee with a salary of ¥%.2f", salary);
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public Date getHireday() {
		return hireday;
	}
	public void setHireday(Date hireday) {
		this.hireday = hireday;
	}
	public int getId() {
		return id;
	}
	private void setId() {
		this.id = nextId;
		nextId++;
	}
	private double salary;
	private Date hireday;
	private int id;
	private static int nextId = 1;
}
/**
 * a class to descript student
 *
 */
class Student extends Person {
	/**
	 * 
	 * @param name the student's name
	 * @param major the student's major
	 */
	public Student(String name,String major) {
		super(name);//pass the name to the superclass constructor
		this.major = major;
	}
	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return "a student majoring in "+major;
	}
	private String major;
}

3) Object类——所有类的超类


java中每个类都是由Object类派生而来的,如果没有明确指出某个类的超类,则该类的超类就是Object。

注意,Object类作为所有类的超类,这种类型的引用变量可以引用任何类型的对象。

但是要想对其引用的对象进行具体的操作,还需要清楚该对象该的原始类型,并进行相应的类型转换。如:

Object obj = new Student("Jobs","computer science");

Student stu = (Student) obj;//change to the origin type

还要注意,所有的数组类型,不管是对象数组还是基本数据类型的数组都拓展于Object类。

Student[] students = new Student[10];

Object obj =  students;//ok

Object类有四个关键方法,需要我们注意,参见《JAVA学习脚印7:  Object类的四个关键方法》


4)enum枚举类

java中所有的枚举类型都是Enum类的子类,定义简单的枚举类如下:

public enum Size {SMALL,MEDIUM,LARGE,EXTRAL_LARGE};可以给枚举类增加构造函数、方法和域。

获取枚举常量时使用Enum类的静态方法valueOf,其原型为:

public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name)

例如: Size size = Enum.valueOf(Size.class, "SMALL");构造了枚举变量

注意,在比较两个枚举类型的值时,不要使用equals,而是直接使用"=="就可以了。


5)Class类

java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,这个信息保存着每个对象所属的类足迹,保存着些信息的类被称为Class类。例如如下代码:

Manager mgr = new Manager("Jery",8000,1980,11,7);
Class<? extends Manager> cl = mgr.getClass();
System.out.println(cl.getName());
System.out.println(cl.getClass().getName());

输出:com.learningjava.Manager

       java.lang.Class

Class对象表示一个特定类的属性,例如这里的cl表示com.learningjava.Manager类的属性。

Class类是java语言提供的反射库中的一个类,能够分析类能力的程序被称为反射(reflective)。反射机制主要应用在工具构造上,反射机制可参考:《java学习脚印:Class类与反射机制》



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值