extends:延展、扩展
继承的格式:class A extends B{ }
A为子类、B为父类。一旦子类A继承父类B之后,子类A中就获取了父类B中声明的所有属性和方法。
注意:
①特别的,对于父类中声明的私有的属性或方法,子类继承以后,仍然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已。(封装性指的是能不能调用的问题,继承性是指能不能获取的问题)
②子类继承父类之后,还可以声明自己特有的方法和属性,实现功能的扩展。
代码体现:
①Person:
package com.atguigu.java;
public class Person {
String name;
private int age; //注意此处age为private
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
//提供的age的get和set方法 --------Student也继承了
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
②Student
package com.atguigu.java;
public class Student extends Person {
String major;
public Student(){
}
public Student(String name,int age,String major){
this.name=name;
setAge(age);
this.major=major;
}
public void study(){
System.out.println("学习");
}
public void show(){
System.out.println("name:"+name+",age:"+getAge());
}
}
③ExtendsTest
package com.atguigu.java;
public class ExtendsTest {
public static void main(String[] args) {
Person p1=new Person();
//p1.age=1; 报错
p1.eat();
Student s1=new Student();
s1.eat();
s1.sleep();
s1.name="Tom";
s1.setAge(10);
System.out.println(s1.getAge());
}
}
Java中关于继承性的规定:
注意:
①子父类是相对概念
②子类直接继承的父类为直接父类;间接继承的父类成为间接父类
③子类继承父类后,就获取了直接父类和所有间接父类中声明的属性和方法
package com.atguigu.exer;
/*①成员变量int sex和int salary;
方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0);
方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
*/
public 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");
}
}
//get和set方法
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;
}
}
package com.atguigu.exer;
/*②定义类Kids继承ManKind,并包括
成员变量int yearsOld;
方法printAge()打印yearsOld的值。*/
public class Kids extends ManKind {
private int yearsOld;
public Kids() {
super();
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge(){
System.out.println("I am "+yearsOld+" years old.");
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
}
package com.atguigu.exer;
/*定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问
其父类的成员变量及方法。*/
public class KidsTest {
public static void main(String[] args) {
Kids someKid=new Kids(12);
someKid.printAge();
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
package com.atguigu.exer;
public class Circle {
private double radius;
public Circle(){
radius=1.0;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea(){
return Math.PI*radius*radius;
}
}
package com.atguigu.exer;
public class Cylinder extends Circle {
private double length; //高
public Cylinder(){
length=1.0;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double findVolume(){
return findArea()*getLength();
}
}
package com.atguigu.exer;
public class CylinderTest {
public static void main(String[] args) {
Cylinder cy=new Cylinder();
cy.setRadius(2.1);
cy.setLength(3.4);
double volume = cy.findVolume();
System.out.println("圆柱的体积:"+volume);
double area = cy.findArea();
System.out.println("圆柱底面圆面积:"+area);
}
}
①如果我们没有显式地声明一个类的父类的话,则此类继承于java.lang.Object类
②所有的类(除object类自身)都直接或间接继承于object类;
即所有Java类具有java.lang.Object类声明的功能。
为什么要进行重写进行覆盖操作?
因为父类的方法已经不适合子类。
如上述圆的方法中有一个求面积方法,子类圆柱继承后,要对其进行重写为一个求表面积方法,此时若要调用父类的圆面积求子类圆柱体积时可以使用“super.方法”的方式。代码理解:
package com.atguigu.exer;
public class Cylinder extends Circle {
private double length; //高
public Cylinder(){
length=1.0;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double findVolume(){ //求体积
return super.findArea()*getLength();
}
//重写为返回圆柱表面积
@Override
public double findArea() {
return Math.PI*getRadius()*getRadius()*2+2*Math.PI*getRadius()*getLength();
}
}
关于重写的返回值类型:
①父类中被重写方法的返回值类型是void,则子类重写的方法的返回值类型也只能是void;
②父类中被重写方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类;
③父类中被重写方法的返回值类型是基本数据类型,则子类重写方法的返回值类型必须是相同的基本数据类型;
关于重写的抛出异常:
子类重写的方法抛出的异常类型不大于父类被重写方法抛出的异常类型(详见异常处理)
我们可以在子类的方法或构造器中。通过使用
“super.属性”或“super.方法”的方式显式调用父类中声明的属性或方法。通常省略,当父类和子类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式地使用“super.属性”的方式,表明调用的是父类中声明的属性。
当子类重写了父类中的方法后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用“super.方法”的方式表明调用的是父类中被重写的方法方法。
super调用构造器
引例:
子类中的一个构造器(其中name和age属性都在父类中声明且为非private,可使用this)
若name和age属性在父类中声明且为private,则无法使用如上“this.关键字”方式。可以考虑使用super
表示super()调用了父类中的指定参数的构造器:(该构造器如下)
总结:
①我们可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器。
②“super(形参列表)”的使用,必须声明在子类构造器的首行。
③在类的构造器中,针对“this(形参列表)”或“super(形参列表)”只能二选一。(二者都要求声明在首行,一个表示调用本类中重载的构造器,一个调用父类中指定构造器,二者不能共存)
④在构造器的首行如果没有显式的声明“this(形参列表)”或“super(形参列表)”,则默认格式为super();调用的是父类中空参的构造器
⑤在类的构造器中至少有一个类的构造器中使用了“super(形参列表)”,调用父类中的构造器。
子类对象实例化的全过程:
当我们通过子类构造器创建子类对象的时候,一定会直接或间接地调用了父类中的构造器,进而调用父类的父类的构造器,直到调用了java.lang.object类中空参的构造器为止,就把所有父类的结构加载了过来,所以实例化一个子类对象后,子类对象可以调用所有父类的方法和属性。
但注意:虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。
package com.atguigu.exer1;
public class Account {
private int id;
private double balance;
private double annualInterestRate;
public Account(int id, double balance, double annualInterestRate) {
super();
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){
System.out.println("余额不足");
}else{
balance-=amount;
}
}
public void deposit (double amount){ //存钱
if(amount >0){
balance+=amount;
return;
}
}
}
package com.atguigu.exer1;
public class CheckAccount extends Account{
private double overdraft; //可透支限额
public CheckAccount(int id, double balance, double annualInterestRate,double overdraft){
super(id, balance, annualInterestRate);
this.overdraft=overdraft;
}
public double getOverdraft() {
return overdraft;
}
public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
}
@Override //要重写withdraw方法,因为继承父类(不可透支)的取钱操作已经不适用于子类(可透支)
public void withdraw(double amount) {
if(getBalance()>=amount){ //余额足够消费
//错误写法:getBalance()-=amount
//正确方式一:
setBalance(getBalance()-amount);
//正确方式二:(调用父类中的withdraw()方法)
//super.withdraw(amount);
}else if(overdraft>=(amount-getBalance())){ //透支额度+余额足够消费
overdraft-=(amount-getBalance()); //务必注意此处顺序:若setBalance(0);在上则再调用getBanlance为0
setBalance(0); //或super.withdraw(getBalance())
}else{
System.out.println("超过可透支限额");
}
}
}
package com.atguigu.exer1;
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());
}
}