例6.4的代码如下(示例):
public class AddClass { public int x = 0,y = 0,z = 0; AddClass(int x){ this.x = x; } AddClass(int x,int y){ this(x); this.y = y; } AddClass(int x,int y,int z){ this(x,y); this.z = z; } public int add(){ return x+y+z; } } //以上为第一个类AddClass --------------------分界线------------------ public class SonAddClass extends AddClass { int a = 0, b = 0, c= 0; SonAddClass(int x){ super(x); a = x+7; } SonAddClass(int x,int y){ super(x,y); a = x+5; b = y+5; } SonAddClass(int x,int y,int z){ super(x,y,z); a = x+4; b = y+4; c = z+4; } public int add(){ System.out.println("super:x+y+z= "+super.add()); return a+b+c; } } //以上是第二个类的内容 AddClass ------------------------分界线---------------------- //这是第三个类的内容,测试类。 public class JavaDemo { public static void main(String[] args){ SonAddClass p1 = new SonAddClass(2,3,5);//设置断点行 SonAddClass p2 = new SonAddClass(10,20); SonAddClass p3 = new SonAddClass(1); System.out.println("a+b+c= "+p1.add()); System.out.println("a+b= "+p2.add()); System.out.println("a= "+p3.add()); } }以下为对例6.4的分析: 设置断点并且开始Debugger后,我们单步调试,进入类SonAddClass的构造函数,这里根据参数个数,进入第三个构造函数,即为SonAddClass(int x,int y,int z) 这个构造函数中,显示调用了父类的构造函数(利用super关键字) super(x,y,z);进入父类AddClass的构造函数体,同样的根据参数,进入AddClass(int x,int y,int z)在这个函数体里,使用了关键字this来调用同类的其它构造方法,进入AddClass(int x,int y) ,同上,又进入了函数AddClass(int x) 但是进入这个最终函数后,下一步并没有直接执行this.x = x语句,而是先对数据成员进行了初始化,public int x = 0,y = 0,z = 0;初始化完成后,进入构造函数,执行 this.x = x调用完成后,退回到AddClass(int x,int y) 中,执行this.y = y;,后再退回到函数AddClass(int x,int y,int z) 函数,执行this.z = z;至此,父类的构造函数调用完毕,回退到子类的构造函数. SonAddClass(int x,int y,int z) super(x,y,z);同样的,下一步是执行语句int a = 0, b = 0, c= 0;对变量进行初始化,再进行接下来的赋值:a = x+4; b = y+4; c = z+4;至此,一个子类对象正式实例化完毕。 后两行new语句同理,
SonAddClass p2 = new SonAddClass(10,20); SonAddClass p3 = new SonAddClass(1);例6.6代码如下(示例):
public class Pare { int i = 3; Pare(){ System.out.println("super"); } } //以上为第一个类 ----------------------------分界线------------------- public class Construct extends Pare{ int i = 8; Construct(){ System.out.println("this"); } Construct(int num){ this(); } int getSuper(){ return super.i; } } //以上为第二个类 -------------------------分界线------------------- public class javaDemo { public static void main(String[] args){ Construct ct = new Construct(9); System.out.println(ct.i); System.out.println(ct.getSuper()); } } //以上为测试类。例子6.6分析过程与6.4类似。区别在于例6.6没有显示的调用父类的构造函数,但是执行过程中,程序还是调用了父类的构造函数,并进行了父类数据成员的初始化。
综上,子类对象实例化过程如下:
为对象分配内存空间,并且对成员变量 进行默认的初始化。绑定构造方法,将new中的参数传递给构造方法的形式参数。调用this或者super语句(二者必居其一,但不能同时存在)。进行显示初始化操作。执行当前构造方法的方法体中的程序代码具体流程如下图所示:
实现两个对象之间互发消息,那么采用组合的设计方式,在两个对象之间建立联系;在两个类内都有对方的对象引用作为数据成员,并真正的调用过程中,二者的对象引用都互相指向对方的对象。 代码如下(示例):
//车类 public class Car { private String name; private double price; private People people; public Car(String name,double price){ this.name = name; this.price = price; } public void setPeople(People people){ this.people = people; } public People getPeople(){ return this.people; } public String getInfo(){ return"汽车型号: "+this.name+", 汽车价格: "+this.price; } } --------------------------------分界线------------------------ //第二个类 public class People { private String name; private int age; private Car car; public People(String name, int age){ this.name = name; this.age = age; } public void setCar(Car car){ this.car= car; } public Car getCar() { return car; } public String getInfo(){ return "姓名: "+this.name+", 年龄: "+this.age; } } -------------------------------------分界线----------------- //测试类 public class JavaDemo { public static void main(String args[]){ People people1 = new People("张三",29); Car car = new Car("奔驰G50",1588800.00); people1.setCar(car); car.setPeople(people1); System.out.println(people1.getCar().getInfo()); System.out.println(car.getPeople().getInfo()); } }以上程序中,车类对象中有人类对象的引用作为其数据成员,同样的,人类对象中也会有车类对象的引用作为数据成员,当通过代码
people1.setCar(car); car.setPeople(people1);建立二者之间的联系后,下一步就可以通过类之间定义的方法来互发消息,即为:
System.out.println(people1.getCar().getInfo()); System.out.println(car.getPeople().getInfo());运行时多态指的是覆盖,在运行时根据输入参数动态选择不同的成员方法执行,体现了一个类本身的多态性,使代码具有良好的拓展性。 例6.6代码如下(示例):
public class javaDemo { public static void main(String args[]){ int resultA = sum(10,20); System.out.println("结果:"+resultA); int resultB = sum(10,20,30); System.out.println("结果:"+resultB); int resultC = sum(10.0,20.0); System.out.println("结果:"+resultC); } public static int sum(int a,int b){ return a+b; } public static int sum(int a,int b,int c){ return a+b+c; } public static int sum(double a,double b){ return (int)(a+b); } }关于重载,更多的请看我的上一篇文章。java课程学习第4课
例6.8即为对抽象类的具体实现
而与抽象类不同的是,接口中没有域变量,只有常量,因此在接口中我们只能定义求面积与周长的方法,而且必须是抽象方法,否则会报错。 接口定义如下(示例):
//接口定义的关键字为 interface 而不是class public interface Shape { abstract public double getArea(); abstract public double getPerimeter(); }三个子类定义如下(示例):
public class Rect implements Shape { public int height; public int width; Rect(int x,int y){ this.height = x; this.width =y; } @Override public double getArea() { return height*width; } @Override public double getPerimeter() { return (width+height)*2; } } ---------上面是Rect类---------------------下面是Triangle类------------------ public class Triangle implements Shape{ public int k,x,y; public Triangle(int baseA,int baseB,int baseC){ this.k = baseA; this.x= baseB; this.y = baseC; } @Override public double getArea(){ double m= (k+x+y)/2.0; return(Math.sqrt(m*( m-k)*( m-x)*(m-y))); } @Override public double getPerimeter(){ return(k+x+y); } } ----------上面是Triangle类-----------------------下面是Circle类-------------------- public class Circle implements Shape{ public int r; public Circle(int r){ this.r = r; } @Override public double getArea() { return (r*r*Math.PI); } @Override public double getPerimeter() { return (r*2*Math.PI); } } ------------上面是Circle类-----------------下面是测试类---------------------- public class javaDemo { public static void main(String[] args){ Rect rect = new Rect(25,25); System.out.println("矩形的面积: "+rect.getArea()); System.out.println("矩形的周长: "+rect.getPerimeter()); Triangle tri = new Triangle(5,5,8); System.out.println("三角形的面积: "+rect.getArea()); System.out.println("三角形的周长: "+rect.getPerimeter()); Circle cir = new Circle(25/2.0); System.out.println("圆形的面积: "+rect.getArea()); System.out.println("圆形的周长: "+rect.getPerimeter()); } }子类继承抽象类,用的是关键字extends; 子类实现接口,用的是关键字 implements; 子类将接口中的抽象方法各自实现后,便可调用方法来求得面积与周长。
对象向下转型存在有安全隐患,为了保证转换的安全性,可以在转换前通过instance of 关键字进行对象所属类型的判断。 用法:对象引用 instanceof 类 (a instanceof A) instanceof 比较的结果有三种:true,false,语法错误(编译无法通过)
如果 a 为类A实例或者A子类的实例,则返回true,如果 a 为类A父类的实例,则返回false,如果a为null,则返回的内容是false。如果 a对象和类A没有任何关系,则编译不会通过;代码如下(示例):
class Uncle{} class Pare{} class Pare1 extends Pare{} class Pare2 extends Pare1{} public class javaDemo { public static void main(String[] args){ Uncle u1 = new Uncle(); Pare p = new Pare(); Pare1 p1 = new Pare1(); Pare2 p2 = new Pare2(); if(p instanceof Pare){ System.out.println("p instanceof Pare"); } if(!(p1 instanceof Pare)){ System.out.println("p1 not instanceof Pare"); } else{ System.out.println("p1 instanceof Pare"); } if(p1 instanceof Pare2){ System.out.println("p1 instanceof Pare2"); } else{ System.out.println("p1 not instanceof Pare2"); } if(null instanceof String){ System.out.println("null instanceof String"); } else{ System.out.println("null not instanceof String"); } } }程序输出结果:
p instanceof Pare p1 instanceof Pare p1 not instanceof Pare2 null not instanceof String