写在前面
终于,终于来了,面向对象的特征:继承,封装,多态。按常理写在前面应该先水两句的,太激动了,太激动了,抱歉。先水两句吧。
大家是不是还沉溺在昨天的520?我还沉溺在IDEA的bug中,www,今天单代码就敲了按小时计数了,特别是bug,看不懂,还好IDEA强大,这要换着eclipse可能就不会在十点之前写总结了。这段时间一直学Java去了,我开始慌小程序那边...怎么办,还啥都不会...不管了,不管了,先把这三大金刚学完在说,明天周五,课比较少,加上周末,应该可以解决...
说好的的先水的,,,说着说着又说到程序上面来了,最近喜欢上神探夏洛特,放心,这一节会非常非常用心,写到这已经前前后后大概三个小时了,好了好了,不水了,今晚早点睡。
今日所学
先放源码
import java.time.LocalDate; public class Employee { private String name; private double salary; private LocalDate hireDate; public Employee(String name,double salary,int year,int month,int day) { this.name = name; this.salary = salary; hireDate = LocalDate.of(year,month,day); } public String getName() { return name; } public double getSalary() { return salary; } public LocalDate getHireDate() { return hireDate; } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } }
public class Manager extends Employee{ private double bonus; public Manager(String name,double salary,int year,int month,int day) { super(name,salary,year,month,day); bonus = 0; } public double getBonus() { double baseSalary = super.getSalary(); return baseSalary + bonus; } public void setBonus(double b) { bonus = b; } }
public class managerTest { public static void main(String[] args) { var boss = new Manager("Pipian",80000,2001,5,22); boss.setBonus(5000); var staff = new Employee[3]; staff[0] = boss; staff[1] = new Employee("huang",5000,2001,3,4); staff[2] = new Employee("wang",5000,2001,5,6); for (Employee e:staff ) { System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); } } }
1.定义子类
可以如下继承Employee类来定义Manager类,这里使用关键字extends表示继承。extends表明正在构造的新类派生于一个已经存在的类。这个已经存在的类称为超类(基类,父类);新类称为子类(派生类,孩子类)
在Manager类中,增加一个用于存储奖金的字段,以及一个用于设置这个字段的新方法:
public class Manager extends Employee{ private double bonus; ... public void setBonus(double b) { bonus = b; } }
2.覆盖方法
超类中的有些方法对子类Manager并不一定适用。具体来说,Manager类中的getSalary方法应该返回薪水和奖金的总和。所以,需要提供一个新的方法来覆盖超类中的这个方法:
public class Manager extends Empioyee
{
...
public double getSalary()
{
...
}
...
}
如何实现这个方法呢?看下面:
public double getSaray()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
我们希望调用超类Employee类中的getSarlary方法,而不是目前的这个方法,所以我们要用到super关键字。
3.子类构造器
先来一个构造器:
public Employee(String name,double salary,int year,int month,int day) { super(name,salary,year,month,day); bonus = 0; }
由于Manager类的构造器不能访问Employee类的私有字段,所以必须通过一个构造器来初始化这些私有字段。使用super调用构造器的语句必须是子类构造器的第一条语句。
一个对象变量可以指示多种实际类型的现象称为多态。在运行的时候能够自动地选择适当的方法,称为动态绑定。(具体后面在总结)
4.多态
在Java程序设计语言中,对象变量是多态的。一个Employee类型的变量既可以引用一个Employee类型的对象,也可以引用Employee类的任何一个子类对象。
不过,不能将超类的引用赋给子类变量:
Manger m = staff[i] //ERROR
5.抽象类
如果自下而上在类的继承层次结构中上移,位于上层的类更具有一般性,可能更加抽象。从某种角度看,祖先类更具有一般性,人们只将它作为派生其他类的基类,而不是用来构造你想象的特定的实例。
public abstract class Person
{
...
public abstract String getDescription();
}
为了提高程序的清晰度,包含一个或者多个抽象方法的类本身必须被声明为抽象的。
最后来学生类的源码
public abstract class Person { public abstract String getDescription(); private String name; public Person(String name) { this.name = name; } public String getName() { return name; } }
import java.time.LocalDate; class Employee extends Person { private double salary; private LocalDate hireDay; public Employee(String name,double salary,int year,int month,int day) { super(name); this.salary = salary; hireDay = LocalDate.of(year,month,day); } public double getSalary() { return salary; } public LocalDate getHireDay() { return hireDay; } @Override public String getDescription() { return String.format("an employee with a salary of $%.2f",salary); } public void raiseSalary(double byPercent) { double raise = salary + byPercent / 100; salary += raise; } }
public class Student extends Person { private String major; public Student(String name,String major) { super(name); this.major = major; } @Override public String getDescription() { return "a student majoring in" + major; } }
public class PersonTest { public static void main(String[] args) { var people = new Person[2]; people[0] = new Employee("huang",5000,1999,5,3); people[1] = new Student("pipian","computer science"); for (Person p:people ) { System.out.println(p.getName()+","+p.getDescription()); } } }