1. 实验:利用IDE的debug功能给例6.4和例6.5的new语句设置断点,使用单步调试(step into/step over)跟踪子类对象实例化(初始化)的执行顺序,并总结该过程。
//例6.4:显式使用super调用父类的构造方法
class AddClass {
private 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;
}
}
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;
}//super(x,y,z)如果去掉会如何?
public int add() {
System.out.println("super:x+y+z="+super.add());
return a+b+c;
}
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.5:隐式使用super调用父类的构造方法
class Pare {
int i=3;
Pare(){
System.out.println("call super()");
}
}
class Construct extends Pare {
int i = 10;
Construct() {
System.out.println("execute Construct()");
}
Construct(int num) {
this(); //如果去掉此句呢?
System.out.println("execute Construct(int)");
}
public static void main(String[] args) {
Construct ct = new Construct(9);
System.out.println(ct.i);
}
}
总结:
(1)为子类对象分配内存空间,对成员变量进行默认的初始化
(2)绑定子类构造方法,将new中的参数传递给构造方法的形式参数。
(3)显式或隐式调用super语句,对从父类继承来的实例变量进行初始化。
(4)按定义顺序执行实例变量初始化操作。
(5)执行子类构造方法的剩余代码。
2. 如何实现两个对象之间互发消息,请举例说明。
通过类的对象引用,使一个类的属性是另一个类的引用
class A{
private int x;
public A(){
x=1;
}
public void show(){
System.out.println(x);
}
}
class B{
private A a;
public void show(){
a=new A();
A.show();
}
}
3. 谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合 ?什么时候宜用继承?)。
子类继承父类,父类的所有属性和方法都可以被子类访问和调用。组合是指将已存在的类型作为一个新建类的成员变量类型,又叫“对象持有”。
当你只需要使用另外一个类的方法时使用组合,但是如果你需要使用另外一个类的作用时但你不想被其他的类访问用继承反之组合。
4. Java中的运行时多态的含义是什么?有什么作用?请举例说明。
JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态。具体一点就是子类方法重写了父类方法。使用父类引用指向子类对象,再调用某一父类中的方法时,不同子类会表现出不同结果。它使得许多事情在运行时就被得以解决,提供了更大的灵活性。
class A {
void fun()
{
System.out.println(“A”);
}
}
class B extends A
{
void fun()
{
System.out.println(“B”);
}
}
class C extends A
{
void fun()
{
System.out.println(“C”);
}
}
class Test
{
public static void main(String[] args)
{
A a;
B b = new B();
C c = new C();
a=b;
a.fun();
a=c;
a.fun();
}
}
5. 使用接口改写例6.8中的程序。
package Interface;
import java.applet.Applet;
import java.awt.*;
interface Shape {
public abstract double getArea();
public abstract double getPerimeter();
}
class Rect implements Shape {
public int x, y, k;
public double m;
public Rect(int x,int y,int k,double m) {
this.x = x;
this.y = y;
this.k = k;
this.m = m;
}
public double getArea() {
return (k*m);
}
public double getPerimeter() {
return (2*(x+y));
}
}
class Triangle implements Shape {
public int a, b, c;
public double m;
public Triangle(int a,int b,int c) {
this.a = a;
this.b = b;
this.c = c;
this.m = (a + b + c)/2.0;
}
public double getArea() {
return (Math.sqrt(m*(m-a)*(m-b)*(m-c)));
}
public double getPerimeter() {
return (a+b+c);
}
}
class Circle implements Shape {
public int x, y, d;
public double r;
public Circle(int x,int y,int d) {
this.x = x;
this.y = y;
this.d = d;
this.r = d/2.0;
}
public double getArea() {
return (Math.PI*r*r);
}
public double getPerimeter() {
return (2*Math.PI*r);
}
}
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(){
}
private void drawArea(Graphics g,Shape s,int a,int b) {
g.drawString(s.getClass().getName()+" Area"+s.getArea(),a,b);
}
private void drawPerimeter (Graphics g,Shape 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,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.d/2,cir.y-(int)cir.d/2,cir.d,cir.d);
g.drawString("Circle Area:"+cir.getArea(),50,115);
g.drawString("Circle Perimeter:"+cir. getPerimeter(),50,135);
}
}
6. 自定义一个类,覆写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
}
}
7. 举例说明运算符instanceof的使用场景。
instanceof是一个二元运算符,用来判断对象是否为特定类的实例。
如·:
class A{…}
A a=new A();
boolean PD=a instance of A;
8. 谈谈抽象类与接口的异同以及两者的使用场景。
相同点:
① 抽象类和接口都不能被实例化
② 抽象类和接口都可以定义抽象方法,子类/实现类必须覆写这些抽象方法
不同点:
① 抽象类有构造方法,接口没有构造方法
② 抽象类可以包含普通方法,接口中只能是public abstract修饰抽象方法(Java8之后可以)
③ 抽象类只能单继承,接口可以多继承
④ 抽象类可以定义各种类型的成员变量,接口中只能是public static final修饰的静态常量
抽象类使用场景:既想约束子类具有共同的行为(但不再乎其如何实现),又想拥有缺省的方法,又能拥有实例变量
接口使用场景:
① 约束多个实现类具有统一的行为,但是不在乎每个实现类如何具体实现
② 作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。
③ 实现类需要具备很多不同的功能,但各个功能之间可能没有任何联系。
④ 使用接口的引用调用具体实现类中实现的方法(多态)