java中的多态关系的运用
1、多态发生的三个必备条件
继承、重写、父类引用指向子类对象
2、注意
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
方法的重写,也就是子类能够重写父类的方法
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。要想调用父类中被重写的方法,则必须使用关键字super。
3、好处
可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
4、例子
1 //父类 2 package com.test.five; 3 4 public class Parent { 5 public void Test(){ 6 System.out.println("我 是 父类"); 7 } 8 } 9 10 //子类一 11 package com.test.five; 12 13 public class Child extends Parent { 14 public void Test(){ 15 System.out.println("我 是大儿子"); 16 } 17 public void Sex(){ 18 System.out.println("我 是个男的"); 19 } 20 } 21 //子类二 22 package com.test.five; 23 24 public class Sister extends Parent{ 25 public void Test(){ 26 System.out.println("我也是个子类"); 27 } 28 public void Sex(){ 29 System.out.println("我是个女儿"); 30 } 31 } 32 //测试类 33 package com.test.five; 34 35 public class Test { 36 public static void main(String[] args) { 37 Parent p = new Child(); 38 p.Test();//父类声明,子类创建,调用该对象的方法(子类父同时所拥有的方法) 39 Show(p); 40 Show(new Sister()); 41 Show(new Child()); 42 } 43 //测试类中的静态类方法,在测试类中可以直接调用此方法(不用再实例化类的对象) 44 public static void Show(Parent p){ 45 p.Test(); 46 if( p instanceof Child){ 47 Child c = (Child)p; 48 c.Sex(); 49 }else if(p instanceof Sister){ 50 Sister s = (Sister)p; 51 s.Sex(); 52 } 53 } 54 }
得出的结果是:
我 是大儿子
我 是大儿子
我 是个男的
我也是个子类
我是个女儿
我 是大儿子
我 是个男的
5、注意(例子)
1 //父类 2 package com.test.six; 3 4 public class Emploee { 5 private String name; 6 private String address; 7 private int num; 8 public Emploee(String name,String address,int num){ 9 System.out.println("Emploee的构造函数"); 10 this.name = name; 11 this.address = address; 12 this.num = num; 13 } 14 public void check(){ 15 System.out.println("Emploee中check的name:"+this.name+" ,address = "+this.address); 16 } 17 public String toString(){ 18 return name+" "+address+" "+num; 19 } 20 public String getName() { 21 return name; 22 } 23 public void setName(String name) { 24 this.name = name; 25 } 26 public String getAddress() { 27 return address; 28 } 29 public void setAddress(String address) { 30 this.address = address; 31 } 32 public int getNum() { 33 return num; 34 } 35 } 36 37 //子类 38 package com.test.six; 39 40 public class Salary extends Emploee { 41 private double salary; 42 //构造函数 43 public Salary(String name, String address, int num,double salary) { 44 super(name, address, num); 45 System.out.println("salary的构造函数"); 46 setSalary(salary); 47 } 48 public double getSalary() { 49 return salary; 50 } 51 52 public void setSalary(double salary) { 53 if(salary >=0.0){ 54 this.salary = salary; 55 } 56 } 57 public void check(){ 58 System.out.println("这是salary的check的方法"); 59 System.out.println("Salary中的name="+getName()+" 薪资="+getSalary()); 60 } 61 public double computePay() { 62 System.out.println("计算工资,付给:" + getName()); 63 return salary/52; 64 } 65 } 66 //测试类 67 package com.test.six; 68 69 public class Test { 70 public static void main(String[] args) { 71 Salary s = new Salary("张三", "北京", 3, 8000.0); 72 Emploee e = new Salary("李四", "上海", 5, 10000.0); 73 System.out.println("salary对象引用中的方法调用"); 74 s.check(); 75 s.computePay(); 76 System.out.println("emploee对象引用中的方法调用"); 77 e.check(); 78 } 79 }
得到的结果如下:
1 Emploee的构造函数 2 salary的构造函数 3 Emploee的构造函数 4 salary的构造函数 5 salary对象引用中的方法调用 6 这是salary的check的方法 7 Salary中的name=张三 薪资=8000.0 8 计算工资,付给:张三 9 emploee对象引用中的方法调用 10 这是salary的check的方法 11 Salary中的name=李四 薪资=10000.0
----一旦实例化一个对象,其执行顺序,首先:
在不涉及继承的前提下,当首次加载类时,按照如下顺序执行:
1、按照出现顺序先后执行静态成员变量定义与静态块;
2、按照出现顺序先后执行动态成员变量定义与动态块;
3、执行构造函数;
4、再次实例化对象时只执行第2、4步即可;
在涉及到继承时,按照如下顺序执行:
1、执行父类的静态成员变量定义与静态块,执行子类的静态成员变量与静态块
2、执行父类非静态成员变量定义与动态块,执行父类构造方法;
3、执行子类的非静态成员变量定义与动态块,执行子类构造方法;
注意:父类构造方法中用到的方法如果已被子类重写,那么在构造子类对象时在
调用父类构造函数中使用子类重写的方法。
例子一:
package com.test.seven; public class TestOne { private static TestOne t1 = new TestOne(); //静态变量 private static int i1; private static int i2 = 2; public TestOne(){ i1++; i2++; } public static void main(String[] args) { TestOne t2 = new TestOne(); System.out.println("t2.i1 = " +t2.i1); System.out.println("t2.i2 = "+t2.i2); } }
得到的结果如下:
t2.i1 = 2
t2.i2 = 3
执行过程:
首先执行给t1、i1、i2分别给予初始值null,0,0,在执行TestOne t1 = new TestOne();
这样子i1++,i2++被执行,i1,i2都变成1,执行完毕后接着执行int i1 , i1,i2的值仍然是1,1,当执行int i2=2时,i2被赋予了值,即i1=1,i2=2;再执行
TestOne t2 = new TestOne(),i1,i2在执行++,此时i1=2,i2=3,输出i1,i2,结果就是:t2.i1=2,t2.i2=3通过上面代码可以知道:
系统默认的给予比通过等号的赋予先执行。
例子二:
package com.test.seven; public class TestOne { private static TestOne t1 = new TestOne(); //静态变量 private static int i1; private static int i2 = 2; //静态块 static{ System.out.println("静态块"); } //动态块 { System.out.println("动态块"); } public TestOne(){ i1++; System.out.println("i1--------------"+i1); i2++; System.out.println("i2--------------"+i2); } public static void main(String[] args) { TestOne t2 = new TestOne(); System.out.println("t2.i1 = " +t2.i1); System.out.println("t2.i2 = "+t2.i2); } }
得到的结果如下:
1 动态块 2 i1--------------1 3 i2--------------1 4 静态块 5 动态块 6 i1--------------2 7 i2--------------3 8 t2.i1 = 2 9 t2.i2 = 3