继承
1. super关键字的学习
-
逻辑关系:
- Manager继承Employee成为Employee的一个子类
- Manager的实例域增加了bonus属性
- Manager类中相应增加了setBonus()方法
-
super关键字
- 在计算Manager的salary时,我们需要家和奖金bonus,而父类的实例域均为private,由于,Manager类的构造器不可以访问Empoloyee类的私有域,所以,我们用super来实现子类对父类中构造器和方法的使用
-
Employee类
import java.time.LocalDate; class Employee{ //data field private String name; private double salary; private LocalDate hireDay; //constructor public Employee(String name,double salary,int year,int month,int day){ this.name = name; this.salary = salary; this.hireDay = LocalDate.of(year,month,day); } //method public String getName(){ return name; } public double getSalary(){ return salary; } public LocalDate gethireDay(){ return hireDay; } public void raiseSalary(double byPercent){ salary += salary * byPercent/100; } }
-
Manager类
class Manager extends Employee{ private double bonus; public void setBonus(double bonus){ this.bonus = bonus; } public Manager(String name,double salary,int year,int month,int day){ super(name,salary,year,month,day); bonus = 0; } public double getSalary(){ return bonus + super.getSalary(); } }
-
super.getSalary();
- 调用父类的getSalary()方法
-
super(name,salary,year,month,day);
- 调用父类的Employee(String name,double salary,int year,int month,int day)构造器
-
ManagerTest类
public class Test{ public static void main(String[] args){ Manager boss = new Manager("hahaha",200,2018,7,16); boss.setBonus(50); Employee[] staff = new Employee[3]; staff[0] = boss; staff[1] = new Employee("xixixi",100,2018,7,16); staff[2] = new Employee("xixixi",100,2018,7,16); //输出所有的Employee信息 for(Employee e : staff){ System.out.println("name : " + e.getName() + ",salary : " + e.getSalary()); } } } /* 在JDK1.8中输出结果为: ------------------------------ name : hahaha,salary : 250.0 name : xixixi,salary : 100.0 name : xixixi,salary : 100.0 ------------------------------ */
-
super与this的区别
-
this的两个用途
- 一是引用隐士参数
- this.name = name;
- 二是调用该类其他的构造器
- this(name,salary)
- 一是引用隐士参数
-
super的两个用途
- 一是调用超类的方法
- super.getSalary()
- 二是调用超类的构造器
- super(name,salary,year,month,day);
- 一是调用超类的方法
-
2. 多态与动态绑定
-
输出所有的Employee信息
for(Employee e : staff){ System.out.println("name : " + e.getName() + ",salary : " + e.getSalary()); }
-
当e引用Employee对象时,e.getSalary()调用的是Employee类中的getSalary()方法,当e引用Manager对象时,e.getSalary()调用的是Manager类中的getSalary()方法。
-
一个对象变量可以指示多种实际类型的现象被称为多态,在运行时能够自动地选择调用哪个方法的现象称为动态绑定。
- 可理解为:多态就是父类的引用指向子类对象。此时,对象变量是多态的。
-
多态类型
- 方法的多态
- 方法的重载:
- 方法名称相同,参数类型和个数不同,与返回值无关
- 方法的重写(继承中使用)
- 方法名称、参数类型、返回值与父类一致
- 方法的重载:
- 对象的多态
- 父类的引用指向子类对象
- 方法的多态
3. 阻止继承:final类和方法
-
回顾:
- 实例域声明为final时,构造对象之后就不允许改变他们的值
-
当类声明为final时,则不允许继承扩展
- final类中的所有方法自动成为final方法
-
当方法声明为final时,子类将不能覆盖这个方法。
-
强制类型转换
- Manager为Employee一个子类,此时:
-
Employee boss = new Manager();
-
若要调用Manager类中特定方法setBonus(),则需要强制类型转换
if(boss instanceof Manager){ Manager bos = (Manager)boss; bos.setBouns(500); }
-
向下转型的强制类型转换不太常见。
-
- Manager为Employee一个子类,此时:
4. 访问控制符号
- private
- 仅对本类可见
- protected
- 对本包和所有子类可见
- public
- 对所有类可见
抽象类
1. 抽象类相关概念
-
包含一个或者多个抽象方法的类本身被声明为抽象的
-
除抽象方法外,抽象类还可以包含具体的数据和具体方法
-
类即使不含有抽象方法,也可以将类声明为抽象类
-
抽象类不能被实例化
-
可以定义一个抽象类的对象引用,指向引用一个非抽象子类的实例化对象
Person p = new Student();
2. 抽象类的使用举例
- 定义抽象类Person
- 抽象方法getDescription();
- 具体方法:getName();
public abstract class Person{
private String name;
public abstract String getDescription();
public Person(String name){
this.name = name;
}
public String getName(){
return name;
}
}
-
定义抽象类子类Employee类
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 String getDescription(){ return String.format("an employee with a salary of $.2f",salary); } public double getSalary(){ return salary; } public LocalDate gethireDay(){ return hireDay; } public void raiseSalary(double byPercent){ salary += salary * byPercent/100; } }
-
定义抽象类的子类Student类
class Student extends Person{ private String major; public Student(String name,String major){ super(name); this.major = major; } public String getDescription(){ return "a student majoring in" + major; } }
-
Person类测试
public class PersonTest{ public static void main(String[] args){ Person[] people = new Person[2]; people[0] = new Employee("hahaha",200,2018,7,17); people[1] = new Student("xixixi","CS"); for(Person p : people){ System.out.println(p.getName() + " , " + p.getDescription()); } } } /* 1. 此时涉及到对象的多态:父类的引用指向子类对象 2. 父类类型数组中存放着子类的实例化对象 3. 虽然Person为抽象类,但是 Persoon[] people = new Person[3];仍然正确 */
Object类
- 所有类的超类
-
equals()方法
- Object中的equals用于检测一个对象是否等于另外一个对象。
- Object中是判断两个对象是否为同一引用
- 我们需要重写equals()方法
-
Employee中重写equals方法
public class Employee{ ...... public boolean equals(Object otherObject){ //判断使用为同一引用 if(otherObject == this) return true; //判断otherObject是否为空 if(otherObject == null) return false; //判断是否属于同一类 if(getClass() != otherObject.getClass()) return false; //现在可知Employee为otherObject的一个实例化对象 Employee other = Employee(otherObject); //判断是否相等 return this.name == other.name && this.salary = other.salary && this.hireDay == other.hireDay; } }
-
泛型数组列表
优点
- 动态的更改数组的大小
- 可存放任意类型的数组
例子
-
声明和构造一个保存Employee对象的数组列表
ArrayList<Employee> staff = new ArrayList<>();
<>中为Employee -
为数组列表中添加Employee对象
staff.add(new Employee("hahah",200,2018,7,16));
-
返回当前数组中的元素个数
staff.size();
缺点
- 不太方便获取数组列表中的元素
- 因此在遍历数组列表时,可以将数组列表转换为数组
-
扩展数组,并添加所有元素
ArrayList <X> list = new ArrayList<>();
while(....){
x = ....;
list.add(x);
}X[] a = new X[list.size()];
list.toArray(a);
-
网友评论