1、继承性
-
为什么要有继承?
- 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中, 那么多个类无需再定义这些属性和行为,只要继承那个类即可;
- 此处的多个类称为子类(派生类),单独的这个类称为父类(基类或超类);可以理解为【子类 is a 父类】;
- 类继承语法规则: 【class Subclass extends SuperClass{ }】
-
继承性的好处
- 减少了代码冗余,提高了代码的复用性;
- 更有利于功能的扩展;
- 让类与类之间产生了关系,提供了多态的前提;
-
体现:一旦子类A继承了父类B以后,子类A就获得了父类B中声明的所有属性和方法;
- 特别的:父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中的私有结构;只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
- 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的扩展;
-
Java中关于继承的一些规定:
- 一个类可以被多个子类继承;
- 一个类只能有一个父类:单继承;
- 子父类是相对的概念;
- 子类直接继承的父类称为直接父类,间接继承的父类称为间接父类;
- 子类继承父类之后,就获得了直接父类以及所有间接父类中声明的属性和方法;
-
关于Object类的理解:
- 如果没有显式的声明一个类的父类,那么此类继承于java.lang.Object类;
- 所有的Java类(除java.lang.Object类)都直接或间接继承于java.lang.Object类;
- 所有的Java类都具有java.lang.Object类中声明的功能;
-
继承性练习:
/* * (1)定义一个ManKind类,包括 成员变量int sex和int salary; 方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0); 方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。 (2)定义类Kids继承ManKind,并包括 成员变量int yearsOld; 方法printAge()打印yearsOld的值。 (3)定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问 其父类的成员变量及方法。 * * */ public class KidsTest { public static void main(String[] args) { Kids somekid = new Kids(); somekid.printAge();//I am 0 somekid.setSalary(0); somekid.setSex(1); somekid.employeed();//no job somekid.manOrWoman();//man } } class ManKind{ private int sex; private int salary; public ManKind() { } public ManKind(int sex, int salary) { this.sex = sex; this.salary = salary; } public void manOrWoman(){ if (sex == 1){ System.out.println("man"); }else if (sex == 0){ System.out.println("woman"); } } public void employeed(){ if (salary == 0){ System.out.println("no job"); }else{ System.out.println("job"); } } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } } class Kids extends ManKind{ private int yearsOld; public Kids() { } public Kids(int yearsOld) { this.yearsOld = yearsOld; } public void printAge(){ System.out.println("I am " + yearsOld); } public int getYearsOld() { return yearsOld; } public void setYearsOld(int yearsOld) { this.yearsOld = yearsOld; }
2、方法重写((override/overwrite)
-
定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法;
- 说明:子类继承父类以后,可以对父类中同名同参数的方法进行覆盖操作;
- 应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参的方法时,实际执行的是子类重写父类的方法;
-
重写的一些规定:
- 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表;
- 子类重写的方法的权限修饰符不能小于父类被重写的方法的权限修饰符;
- 子类不能重写父类中声明为private权限的方法;
- 如果父类被重写的方法的返回值类型是void,那么子类重写的方法的返回值类型也只能是void;
- 如果父类被重写的方法的返回值类型是A类(假设是Object),那么子类重写的方法的返回值类型可以是A类或A类的子类(如:可以是String);
- 如果父类被重写的方法的返回值类型是基本数据类型,那么子类重写的方法的返回值类型也只能是基本数据类型;
- 子类方法抛出的异常不能大于父类被重写方法的异常;
- 子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写);因为static方法是属于类的,子类无法覆盖父类的方法。
-
重写练习:
public class OverRideTest { public static void main(String[] args) { Student student = new Student(); student.setName("tom"); student.setAge(19); student.eat();//【子类】吃饭...tom19 } } class Person{ private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public void eat(){ System.out.println("【父类】吃饭..."); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class Student extends Person{ //重写了父类中的eat()方法 public void eat(){ System.out.println("【子类】吃饭..." + this.getName() + this.getAge()); } }
3、super关键字
-
super理解为:父类的...
-
作用和说明:
- 可用于访问父类中定义的属性、方法、构造器;
- 可用【super.属性】或者【super.方法】的方式显式的调用父类中定义的属性或方法;一般可以省略【super.】,但是如果子类中定义有和父类中同名的属性时,则必须使用【super.属性】的结构,表明调用的是父类中声明的属性;
- 当子类重写了父类中的方法以后,如果想在子类的方法中调用父类中被重写的方法时,则必须使用【super.方法】的结构,表明调用的是父类中被重写的方法;
- 可以在子类的构造器中使用【super(形参列表)】调用父类中声明的指定构造器;
- 【super(形参列表)】必须声明在子类构造器首行!
- 在类的构造器中,针对于【this(形参列表)】或【super(形参列表)】只能二选一,不能同时出现!
- 子类中所有的构造器默认都会访问父类中空参数的构造器;(如果在子类的首行没有显式的声明【this(形参列表)】或【super(形参列表)】,则默认调用的是父类中空参的构造器),如果父类中没有提供空参构造器,则子类需要调用父类其他构造器;
- 在子类多个构造器中,至少有一个子类构造器使用了【super(形参列表)】;
-
子类对象实例化过程:
- 从结果上来看(继承性):
- 子类继承父类以后,就获取了父类中声明的属性和方法;
- 创建子类对象,在堆空间中就会加载所有父类中声明的属性;
- 从过程上看:
- 当通过子类构造器创建子类对象时,一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器......直到调用了【java.lang.Object】类中空参的构造器为止;正因为加载过所有的父类的结构,才可以看到内存中有父类的结构,子类对象才可以考虑进行调用;
- 虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象;
- 从结果上来看(继承性):
4、继承/super练习
-
代码如下:
public class AccountTest { public static void main(String[] args) { Account acct = new Account(1122,20000,0.045); acct.withdraw(30000); System.out.println("您的账户余额为:" + acct.getBalance()); acct.withdraw(2500); acct.deposit(3000); System.out.println("您的账户余额为:" + acct.getBalance()); System.out.println("月利率为:" + (acct.getAnnualInterestRate() * 100) + "%"); } } class Account{ private int id;//账号 private double balance;//余额 private double annualInterestRate;//年利率 public Account(int id, double balance, double annualInterestRate) { this.id = id; this.balance = balance; this.annualInterestRate = annualInterestRate; } public int getId() { return id; } public void setId(int id) { this.id = id; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public double getAnnualInterestRate() { return annualInterestRate; } public void setAnnualInterestRate(double annualInterestRate) { this.annualInterestRate = annualInterestRate; } //返回月利率 public double getMonthlyInterest(){ return annualInterestRate / 12; } //取款 public void withdraw (double amount){ if (balance >= amount){ balance -= amount; return; } System.out.println("余额不足!"); } //存款 public void deposit (double amount){ if (amount > 0){ balance += amount; } } } -
代码如下:
public class CheckAccountTest { public static void main(String[] args) { CheckAccount acct = new CheckAccount(1122,20000,0.045,5000); acct.withdraw(5000); System.out.println("您的账户余额:" + acct.getBalance()); System.out.println("您的可透支额:" + acct.getOverdraft()); acct.withdraw(18000); System.out.println("您的账户余额:" + acct.getBalance()); System.out.println("您的可透支额:" + acct.getOverdraft()); acct.withdraw(3000); System.out.println("您的账户余额:" + acct.getBalance()); System.out.println("您的可透支额:" + acct.getOverdraft()); } } class Account{ private int id;//账号 private double balance;//余额 private double annualInterestRate;//年利率 public Account(int id, double balance, double annualInterestRate) { this.id = id; this.balance = balance; this.annualInterestRate = annualInterestRate; } public int getId() { return id; } public void setId(int id) { this.id = id; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public double getAnnualInterestRate() { return annualInterestRate; } public void setAnnualInterestRate(double annualInterestRate) { this.annualInterestRate = annualInterestRate; } //返回月利率 public double getMonthlyInterest(){ return annualInterestRate / 12; } //取款 public void withdraw (double amount){ if (balance >= amount){ balance -= amount; return; } System.out.println("余额不足!"); } //存款 public void deposit (double amount){ if (amount > 0){ balance += amount; } } } class CheckAccount extends Account{ private int overdraft;//可透支限额 public CheckAccount(int id, double balance, double annualInterestRate, int overdraft) { super(id, balance, annualInterestRate); this.overdraft = overdraft; } public int getOverdraft() { return overdraft; } public void setOverdraft(int overdraft) { this.overdraft = overdraft; } @Override public void withdraw(double amount) { if (getBalance() >= amount){ super.withdraw(amount); }else if(overdraft >= amount - getBalance()){ overdraft -= amount - getBalance(); super.withdraw(getBalance()); }else{ System.out.println("超过可透支限额!"); } } }