论述题
1. 如何实现两个对象之间互发消息,请举例说明。
1)引用必须真实引用了特定的对象。
2)被访问对象必须定义了相应的属性或方法。
3)被访问的属性或方法必须具有可访问的权限。
class FighterPlane{
String name;
int missileNum;
public FighterPlane(String _name,int _missileNum){
name = _name;
missileNum = _missileNum;
}
public void fire(){
if (missileNum>0){
System.out.println("now fire a missile !");
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 static void main(String[] args)
{
FighterPlane ftp = new FighterPlane("su35",10);
//产生A对象,并将ftp对象引用作为参数传入
A a = new A(ftp);
//发送消息,产生调用关系
a.invoke();
}
}
2. 谈谈组合与继承的区别以及两者的使用场景。(即什么时候宜用组合 ?什么时候宜用继承?)
组合:在新的类中产生现有类的对象。由于新的类是由现有类的对象所组成,所以这种方法称为组合。该方法只是复用了现有程序代码的功能,而非它的形式。
继承:按照现有的类型来创建新类。无需改变现有类的形式,采用其形式并在其中添加新代码。这种方式称为继承。
当要设计的新类与原有的类的关系是“has-a”(有一个)时,适合用组合的方式。
例如,一个简单的房子(SimpleHouse)有两个窗户(Window)、有一个门(Door)、有一个桌子(Table)以及四个椅子(Chair)等等,可以用如下代码描述:
//: SimpleHouse.java
public class SimpleHouse {
private Window[] windows = new Window[2];
private Door door = new Door();
private Table table = new Table();
private Chair[] chairs = new Chair[4];
/*some code...*/
}
class Window {/*some code...*/}
class Door {/*some code...*/}
class Table {/*some code...*/}
class Chair {/*some code...*/}
//:~
当要设计的新类原有的类的关系是“is-a”时,适合用组合的方式。
例如,狗是一个宠物,猫是一个宠物,而宠物是一个原有的类,可以用如下代码描述:
//: Pet.java
abstract public class Pet {
public void jump() {
System.out.println(this.getClass().getSimpleName()+" jump");
}
abstract public void say();
/*some code...*/
}
class Dog extends Pet {
@Override
public void say() {
System.out.println("woof!");
}
/*some code...*/
}
class Cat extends Pet {
@Override
public void say() {
System.out.println("meow~");
}
/*some code...*/
}
//:~
3. Java中的运行时多态的含义是什么?有什么作用?请举例说明。
通过方法覆盖实现(子类覆盖父类方法)。
可以进行动态绑定,使用父类引用指向子类对象,再调用某一父类中的方法时,不同子类会表现出不同结果。这样做的作用就是拓展性极好。
4. 使用接口改写例6.8中的程序。
import java.awt.*;
import java.applet.*;
interface Shape {
abstract public double getArea();
abstract public double getPerimeter();
}
abstract class Shapes implements Shape {
protected int x,y,k;
protected double m;
public Shapes(int x,int y,int k,double m) {
this.x=x;
this.y=y;
this.k=k;
this.m=m;
}
}
class Rect extends Shapes {
public double getArea() {
return(k*m);
}
public double getPerimeter() {
return(2*k+2*m);
}
public Rect(int x,int y,int width,int height) {
super(x,y,width,height);
}
}
class Triangle extends Shapes {
public double getArea() {
return(Math.sqrt(m*( m-k)*( m-x)*(m-y)));
}
public double getPerimeter() {
return(k+x+y);
}
public Triangle(int baseA,int baseB,int baseC) {
super(baseA, baseB, baseC,0);
m= (baseA+ baseB+ baseC)/2.0;
}
}
class Circle extends Shapes {
public double getArea() {
return(m* m *Math.PI);
}
public double getPerimeter() {
return(2*Math.PI* m);
}
public Circle(int x,int y,int width) {
super(x,y, width, width/2.0);
}
}
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);
public void init() {}
public void paint(Graphics g) {
g.drawRect(rect.x,rect.y,rect.k,(int)rect.m);
g.drawString("Rect Area:"+rect.getArea(),50,35);
g.drawString("Rect Perimeter:"+rect.getPerimeter(),50,55);
g.drawString("Triangle Area:"+tri.getArea(),50,75);
g.drawString("Triangle Perimeter:"+tri.getPerimeter(),50,95);
g.drawOval(cir.x-(int)cir.k/2,cir.y-(int)cir.k/2,cir.k,cir.k);
g.drawString("Circle Area:"+cir.getArea(),50,115);
g.drawString("Circle Perimeter:"+cir. getPerimeter(),50,135);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<APPLET CODE="RunShape" width="500" height="200"></APPLET>
</body>
</html>
5. 自定义一个类,覆写equals方法,以满足自身业务需求。
覆写equals()方法思路:
(1)判断要比较对象的是否为null,若是直接返回false,若不比较则可能会出现空指针异常(NullPointerException);
(2)判断是否在与自身比较(通过==比较地址),若是直接返回true;
(3)判断要比较的两个对象是否为同类,若是再进行接下来比较,若不是直接返回false。若不判断,则可能出现强转异常(classCastException);
(4)通过向下转型,比较两对象内容是否相等。
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
}
}
6. 举例说明运算符instanceof的使用场景。
用instanceof判断一个对象是不是某个类或者其子类的实例,还可以将这个对象强制转换成这个类的类型。
public class Test {
static class A{ }
static class B extends A{ }
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println( "a instanceof A 的结果:" + ( a instanceof A ) );
System.out.println( "b instanceof A 的结果:" + ( b instanceof A ) );
System.out.println();
System.out.println( "a instanceof B 的结果:" + ( a instanceof B ) );
System.out.println( "b instanceof B 的结果:" + ( b instanceof B ) );
System.out.println();
/*
注意:
下面用Object类对象引用某个类实例 是实际应用中非常常见的
object instanceof class ,如果object 实际引用的对象实例 是 class 的实例对象
或者 class 的子类实例对象,则返回true
注意 “实际引用的对象实例” 这个词强调的'实际引用'.
*/
Object o = new A();
System.out.println( "o instanceof A 的结果:" + ( o instanceof A ) );
System.out.println( "o instanceof B 的结果:" + ( o instanceof B ) );
System.out.println();
o = new B();
System.out.println( "o instanceof A 的结果:" + ( o instanceof A ) );
System.out.println( "o instanceof B 的结果:" + ( o instanceof B ) );
System.out.println();
}
}
7. 谈谈抽象类与接口的异同以及两者的使用场景。
接口(interface)和抽象类(abstract class)都是支持抽象定义的两种机制。
相同点
1)两者都不能被实例化。
2)接口的实现类和抽象类的子类都必须实现了接口或抽象类中的抽象方法后才能被实例化。
不同点
1)关键字不同,接口用interface,抽象类用abstract class;类实现接口用implements,类继承抽象类用extends。
2)接口允许一个类实现多个接口,抽象类只允许单继承。
3)接口中只有全局常量(public static final)和抽象方法(public abstract)(java 8允许静态方法和默认方法),抽象类中可以包含普通类中所有可以包含的东西以外加抽象方法(抽象类中也可以没有抽象方法)。
4)接口中的访问权限只能是public,抽象类允许多种访问权限。
5)接口不能有构造方法,抽象类一定有构造方法。
6)接口强调功能的实现,其设计理念是“has-a”关系,并运用于实现比较常用的功能,方便日后维护或者添加删除方法,抽象类强调所属关系,其设计理念是“is-a”关系,倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。
使用场景
抽象类强调所属关系,多用于在同类事物中有无法具体描述的方法的场景,所以当子类和父类之间存在逻辑上的层次结构时,推荐使用抽象类。
接口强调功能的实现,多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者多个对象之间的特定交互行为时,应该使用接口;另外使用接口完全可以实现与抽象类相同的功能,使用接口可以大大降低软件系统的耦合度,应该优先考虑使用接口。