先看如下代码:
1 package com.company; 2 3 public class init_java { 4 public static void main(String[] args){ 5 Employee man=new Manager("tom",22,23000,20000); 6 Manager man1=new Manager("tom",22,23000,20000); 7 System.out.println(man.getSalary()); 8 // System.out.println(man.giveMon()); 9 System.out.println(man1.giveMon()); 10 } 11 12 13 } 14 15 16 class Employee{ 17 private int age; 18 private String name; 19 private double salary; 20 private String alaname; 21 public Employee(String aname,int aage,double asalary){ 22 this("evil"); 23 this.age=aage; 24 this.salary=asalary; 25 this.name=aname; 26 } 27 public Employee(String aname){ 28 this.alaname=aname; 29 } 30 public String getName(){ 31 System.out.println(this.name); 32 return this.name; 33 } 34 public double getSalary(){ 35 return this.salary; 36 }; 37 public String getAlaname(){ 38 return this.alaname; 39 } 40 } 41 42 43 class Manager extends Employee{ 44 private double mon; 45 public Manager(String aname,int aage,double asalary,double mon){ 46 super(aname,aage,asalary); 47 this.mon=mon; 48 } 49 public double giveMon(){ 50 double salary= super.getSalary(); 51 salary+=this.mon; 52 return salary; 53 } 54 }
结果输出:
继承:
语法: class A extends B{} A继承B。java中只能单继承,和python不一样,python可以多继承。
java的多态:
A继承B,B属于超类、父类 A是子类和孩子类,关系是一对一对说,比如说超类和子类而不是超类和孩子类。
子类A的对象类型是超类B的类型一样,也就是说子类A的对象类型既是超类B的类型也A类型,也就是说子类A的对象继承超类的B的方法和属性。
但是超类B的对象却不是子类B的类型,也就是说超类B的对象不能调用子类A的方法。
他们之间关系是"is a",就是说A是B的对象。
构造器执行顺序:
如果子类A没有显示执行超类B的构造器的话,会自动执行超类B的没有带参数的构造器,如果超类B没有不带参数的构造器话,执行的时候会报错。
1 package com.company; 2 3 public class init_java { 4 public static void main(String[] args){ 5 // Employee man=new Manager("tom",22,23000,20000); 6 Manager man1=new Manager(20000); 7 // System.out.println(man.getSalary()); 8 // System.out.println(man.giveMon()); 9 System.out.println(man1.giveMon()); 10 } 11 12 13 } 14 15 class Manager extends Employee{ 16 private double mon; 17 public Manager(double mon){ 18 // super(aname,aage,asalary); 19 this.mon=mon; 20 } 21 public double giveMon(){ 22 double salary= super.getSalary(); 23 salary+=this.mon; 24 return salary; 25 } 26 } 27 28 class Employee{ 29 private int age; 30 private String name; 31 private double salary; 32 private String alaname; 33 public Employee(String aname,int aage,double asalary){ 34 this("evil"); 35 this.age=aage; 36 this.salary=asalary; 37 this.name=aname; 38 } 39 public Employee(String aname){ 40 this.alaname=aname; 41 } 42 public String getName(){ 43 System.out.println(this.name); 44 return this.name; 45 } 46 public double getSalary(){ 47 return this.salary; 48 }; 49 public String getAlaname(){ 50 return this.alaname; 51 } 52 }
直接抛出来,没有找到合适的构造器。
我们修改超类的构造器,变成无参数的构造器。或者去掉构造器。
1 package com.company; 2 3 public class init_java { 4 public static void main(String[] args){ 5 // Employee man=new Manager("tom",22,23000,20000); 6 Manager man1=new Manager(20000); 7 // System.out.println(man.getSalary()); 8 // System.out.println(man.giveMon()); 9 // System.out.println(man1.giveMon()); 10 } 11 12 13 } 14 15 class Manager extends Employee{ 16 private double mon; 17 public Manager(double mon){ 18 // super(aname,aage,asalary); 19 this.mon=mon; 20 } 21 // public double giveMon(){ 22 // double salary= super.getSalary(); 23 // salary+=this.mon; 24 // return salary; 25 // } 26 } 27 28 class Employee{ 29 // private int age=22; 30 // private String name="tom"; 31 // private double salary=20000; 32 // private String alaname="evil"; 33 public Employee(){ 34 System.out.println("ok"); 35 } 36 // public Employee(String aname){ 37 // this.alaname=aname; 38 // } 39 // public String getName(){ 40 // System.out.println(this.name); 41 // return this.name; 42 // } 43 // public double getSalary(){ 44 // return this.salary; 45 // }; 46 // public String getAlaname(){ 47 // return this.alaname; 48 // } 49 50 }
输出结果:
显示调用:super(参数1,参数2.......)表示调用超类中的相应的参数类型的构造器。这句必须放在子类的构造器的第一句,才能生效!!
同里想调用超类的方法用super.method形式!
子类覆盖父类的方法:
方法的签名:
方法的名字和方法的参数列表叫做方法的签名。子类将相同的方法签名将覆盖超类的相应的方法。但是为了保持数据类型的兼容性,需要声明返回类型为子类的类型。
注意:
如上Manager 继承了Employee,Manager 对象也是Employee对象,如果将Manager 对象声明为employee对象的时候,Manager 对象无法调用自己的方法。
1 package com.company; 2 3 public class init_java { 4 public static void main(String[] args){ 5 Employee man=new Manager("tom",20000,22,"evil",3000); 6 double mon=man.giveMon(); 7 System.out.println(mon); 8 } 9 10 11 } 12 13 class Manager extends Employee{ 14 private double mon; 15 public Manager(String aname,double asalary,int age,String alaname,double mon){ 16 super(aname,asalary,age,alaname); 17 this.mon=mon; 18 } 19 public double giveMon(){ 20 double salary=super.getSalary(); 21 salary+=this.mon; 22 return salary; 23 } 24 } 25 26 class Employee{ 27 private int age=22; 28 private String name="tom"; 29 private double salary=20000; 30 private String alaname="evil"; 31 public Employee(String aname,double asalary,int age,String alaname){ 32 this.age=age; 33 this.name=aname; 34 this.salary=asalary; 35 this.alaname=alaname; 36 } 37 public Employee(String aname){ 38 this.alaname=aname; 39 } 40 public String getName(){ 41 System.out.println(this.name); 42 return this.name; 43 } 44 public double getSalary(){ 45 return this.salary; 46 }; 47 public String getAlaname(){ 48 return this.alaname; 49 } 50 51 }
直接抛出错误:
虽然你使用的Manager的构造器构造对象,但是你声明的对象的为employee类型,而不是Manager类型。所以在执行方法,jvm会找employee的方法表,找giveMon方法。显然没有。
所以改成Manager类型就可以执行。
多态属性:
如上面代码的Manager man=new Manager("tom",20000,22,"evil",3000);中的man对象变量,虽然声明为Manger类型对象,但是我们的在调用的方法的时候,不仅可以调用他本身类Manager的方法,也可以调用超类的方法,而无需声明
对象变量man为超类的类型。这种形式叫做多态属性,通过继承,子类对象在调用方法的时候,会根据自身的方法表和超类的方法表,由调用方法的签名(名字和参数列表),通过自身和超类的方法表来动态确认自己的调用的方法。
我们叫做动态绑定。
子类在调用方法的执行过程如下:
执行方法x.f(param)的时候,分以下步骤执行:
1、编译器查看对象的声明类型和对象。
2、编译器查看调用方法的参数类型。
3、如果是被private、static、final方法或者构造器,编译器可以准确知道调用的是哪个方法。
4、当执行方法的时候,并且采用动态绑定方法的时候,会根据方法的实际类型,所对应的合适的方法。从子类到超类一次查找。
查找的过程需要查看多个类,java是怎么解决这个开销呢?在实际中,每个类中对有本类型的方法表(method table),每次查找的时候,通过查找方法表,来提高效率和减少开销。
多态:
1、无论是接口、普通类、抽象类都是声明父类的类型 调用子类的方法,来实现多态!!