一.实验:利用IDE的debug功能给例6.4和例6.5的new语句设置断点,使用单步调试(step into/step over)跟踪子类对象实例化(初始化)的执行顺序并总结该过程。
- 为子类对象分配内存空间,对成员变量进行默认初始化
- 绑定构造方法,将new对象中的参数传递给构造方法的形式参数。
- 显示或隐式地调用super语句,对从父类继承来的实例变量进行初始化
- 按定义顺序执行实例变量初始化操作
- 执行当前构造方法体中的剩余程序代码
二.如何实现两个对象之间互发消息,请举例说明
程序=对象+消息
能否发送消息取决三个条件:
- 引用必须真实引用了特定的对象,否则会抛出NullPointerException异常。
- 被访问对象必须定义了相应的属性或方法,否则编译不会通过。
- 被访问的属性或方法必须具有可访问的权限。
class FighterPlane {
String name;
int missileNum;
public FighterPlane(String _name, int _missleNum) {
this.name = _name;
this.missileNum = _missleNum;
}
public void fire() {
if (this.missileNum > 0) {
System.out.println("now fire a missile !");
this.missileNum -= 1;
} else {
System.out.println("No missile left !");
}
}
}
class A {
FighterPlane fp;
public A(FighterPlane fpp) {
this.fp = fpp; //A对象中拥有了FighterPlane对象的引用
}
public void invoke() {
//A对象发送消息给FighterPlane的对象
System.out.println(fp.name);
}
}public class Run {
public Run() {
}
public static void main(String[] var0) {
FighterPlane ftp = new FighterPlane("su35", 10);
//产生A对象,并将ftp作为对象引用传入
A a= new A(ftp);
//发送消息,产生调用关系
a.invoke();
}
}
三.谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合,什么时候宜用继承)
- 继承和组合都是复用类
区别:
- 继承是子类继承父类所有,父类的pub和pro属性和方法都可以被子类访问和调用。
- 组合是指将已存在的类型作为一个新建类的成员变量类型,两个类之间无上下级关系。
使用场景:
- 当所需要的大量方法和属性与某个类相同时,为减少代码重复率,使用继承。
- 当只需要使用少数某个类的方法时,使用组合。
四.Java中运行时多态的含义是什么?有什么作用?
- 重载(编译时)和覆写(运行时)
作用:
- 可替代性
- 可扩充性
- 接口性
五.使用接口改写例6.8中的程序
(具体需要运行)
public interface Shapes {
public abstract double getArea();
public abstract double getPerimeter();
}
public class Rect implements Shapes{
int x,y;
double width,height;
public Rect(int x,int y,double width,double height) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
}
public double getArea() {
return width*height;
}
public double getPerimeter() {
return 2*(width+height);
}
}
public class Triangle implements Shapes {
int baseA,baseB,baseC;
double m;
public Triangle(int x,int y,int z) {
baseA=x;
baseB=y;
baseC=z;
m=(baseA+baseB+baseC)/2.0;
}
public double getArea() {
return (Math.sqrt(m*(m-baseA)*(m-baseB)*(m-baseC)));
}
public double getPerimeter() {
return (double)(baseA+baseB+baseC);
}
}
public class Circle implements Shapes{
int x,y;
double d,r;
public Circle(int x,int y,int width) {
this.x=x;
this.y=y;
r=width/2.0;
d=(double)width;
}
public double getArea() {
return (r*r*Math.PI);
}
public double getPerimeter() {
return (d*Math.PI);
}
}
import java.applet.*;
import java.awt.*;
public class RunShape extends Applet {
Rect rect=new Rect(5,15,25,25);
Triangle tri=new Triangle(5,5,8);
Circle cir=new Circle(13,90,25);
private void drawArea(Graphics g,Shapes s,int a,int b) {
g.drawString(s.getClass().getName()+"Area"+s.getArea(), a,b);
}
private void drawPerimeter(Graphics g,Shapes s,int a,int b) {
g.drawString(s.getClass().getName()+"Perimeter"+s.getPerimeter(),a,b);
}
public void paint(Graphics g) {
g.drawRect(rect.x, rect.y,(int)rect.width, (int)rect.height);
drawArea(g,rect, 50, 35);
drawPerimeter(g,rect,50,55);
drawArea(g,tri,50,75);
drawPerimeter(g,tri,50,95);
g.drawOval(cir.x-(int)cir.r,cir.y-(int)cir.r ,(int)cir.d,(int)cir.d);
drawArea(g,cir,50,115);
drawPerimeter(g,cir,50,135);
}
}
六.自定义一个类,覆写equals方法,以满足自身业务需求
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return this.name+"今年"+this.age+"岁";
}
public boolean equals(Object obj){//Object类可接受任何类
if(obj==null){//判断是否为空,若不判断则会出先空指针异常(NullPointerException)
return false;
}
if(this==obj){//判断是否在与自身比较(通过比较地址),若是则直接返回true
return true;
}
if(!(obj instanceof Person)){//instanceof作用为判断其左边对象是否为右边对象的实例,此处为判断主方法中equals()方法括号中的对象是否为Person类
return false;
}
//到达此处时必定是同类但不同地址的对象在比较
Person per=(Person)obj;//向下转型,比较属性值
return this.name.equals(per.name)&&this.age==per.age;//判定属性内容是否相等(易错点)
}
}
class Student{}
public class Test{
public static void main(String[] args) {
Person per1=new Person("张三",18);
Person per2=new Person("张三",18);
Person per3=new Person("lisi",19);
Person per4=null;
Student stu=new Student();
System.out.println(per1.equals(per1));//true
System.out.println(per1.equals(stu));//false
System.out.println(per1.equals(per3));//false
System.out.println(per1.equals(per4));//false
}
}
七.举例说明运算符instance of的使用场景
instanceof:判断对象是否为特定类的实例
用法:boolean result=object instanceof class
可避免向下转型抛出运行时异常
Shape s=new Rect(10,30);
s=new Triangle(5,5,8);
s=new Circle(12.5);
//Triangle triangle=(Triangle)s//向下转型抛出运行时异常
//triangle.drawTri();
if(s instanceof Rect){//避免向下转型抛出运行时异常
Rect rectangle=(Rect)s;
rectangle.drawRect();
}else if(s intanceof Triangle){
Triangle triangle=(Triangle)s;
triangle.drawTri();
}else if(s intanceof Circle){
Circle.circle=(Circle)s;
Circle.drawCir();
}
八.谈谈抽象类与接口的异同以及两者的使用场景。
共同点:二者都有抽象方法,都不能实例化。都有自己的声明,并能引用具体子类或实现类对象
不同点 | 抽象类 | 接口 |
---|---|---|
属性 | 可以有域变量 | 不能有域变量,只能是静态常量 |
成员方法 | 可以有具体方法,而且具体方法可以调用抽象方法 | 如果有方法,则全部是抽象方法 |
实现策略 | 必须有子类继承 | 必须有实现类实现 |
扩展性 | 弱 | 强 |
- 抽象类:既想约束子类具有共同的行为,又想拥有缺省的方法,又能拥有实例变量
- 接口:保持稳定性且有一定的扩展性