題目:
- 實驗:利用IDE的debug功能給例6.4和例6.6的new語句設定斷點,使用單步除錯(step into/step over)跟蹤子類物件例項化(初始化)的執行順序,並總結該過程。(教材:Java物件導向程式設計,第二版,袁紹欣主編)
- 如何實現兩個物件之間互發訊息,請舉例說明。
- 談談組合與繼承的區別以及兩者的使用場景(即什麼時候宜用組合?什麼時候宜用繼承? )。
- Java中的執行時多型的含義是什麼?有什麼作用?請舉例說明。
- 使用介面改寫例6.8中的程式。
- 簡述運算子instanceof的使用場景。
1. 實驗:利用IDE的debug功能給例6.4和例6.6的new語句設定斷點,使用單步除錯(step into/step over)跟蹤子類物件例項化(初始化)的執行順序,並總結該過程。
下面給出6.4除錯動圖(大小限制,該動圖尺寸不大)
下面給出6.6除錯動圖
程式說明:
package bookcode.ex6.part6_6;
class Pare {
int i = 3;
Pare() {
super();
}
};
class Construct extends Pare {
int i = 8;
Construct() {
}
Construct(int num) {
this();
}
public static void main(String args[]) {
Construct ct = new Construct(9);
System.out.println(ct.i);
System.out.println(ct.getSuper());
}
int getSuper() {
return super.i;
}
}
先執行的是子類的this(),Construct()中有一個隱含的super(),使得類Construct在生成物件時,父類 i=3 顯式初始化能夠執行。
例項化執行順序總結:
- 為子類物件分配記憶體空間,對域變數進行預設初始化。
- 繫結構造方法,將new物件中的引數傳遞給構造方法的形式引數。
- 呼叫this或super語句,二者必居其一,也只有一。
- 進行例項變數的顯式初始化操作。
- 執行當前構造方法體中的程式程式碼。
2. 如何實現兩個物件之間互發訊息,請舉例說明。
使用引用的屬性或方法其實都是呼叫物件的屬性或方法,而訊息概念的引入就是為了說明這樣的過程。訊息的實質就是引用向物件發出的服務請求,是對資料成員和成員方法的呼叫。下面列舉能否傳送訊息的三個條件:
- 引用必須真實引用了特定的物件,否則會丟擲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();
}
}
3. 談談組合與繼承的區別以及兩者的使用場景(即什麼時候宜用組合?什麼時候宜用繼承? )。
- 組合:通過物件內部的屬性引用來實現。使物件之間的耦合性較為鬆散。
- 繼承:從已有的類派生出新的類。在不同的類中也可能會有共同的特徵和動作,可以把這些共同的特徵和動作放在一個類中,讓其它類共享。因此可以定義一個通用類,然後將其擴充套件為其它多個特定類,這些特定類繼承通用類中的特徵和動作。繼承是 Java 中實現軟體重用的重要手段,避免重複,易於維護,易於理解。
- 組合就像房間裡面的窗戶、牆壁、地板、桌子、椅子等,他們之間並不存在結構上的相似性,只是功能上組合可以發揮更大的作用,但是單獨是可以獨立執行的。繼承就像對房間進行擴充成為一棟樓,前面的零部件它都具備,但是如果沒有房間,大樓是無法構建的,具有結構和功能上的關聯。
- 顯而易見,在不具有結構和功能上的相似性時,使用繼承可以減少程式碼重複率,易於維護;在結構實現不同、功能“可疊加”時,使用組合無疑是優於繼承的。
4. Java中的執行時多型的含義是什麼?有什麼作用?請舉例說明。
Java提供了兩種多型機制——過載和覆蓋。執行時多型指的是覆蓋,在執行時根據輸入引數動態選擇不同的 成員方法執行,體現了一個類本身的多型性,使程式碼具有良好的擴充性。
舉例:同樣的紅燒魚,廚師老師的紅燒方法傳給廚師徒弟後,廚師徒弟在紅燒方法上做了改動,這是紅燒方法的重寫,就相當於 java 的方法重寫。
重寫程式碼如下:
class Ct{
void hongshao(int a){
System.out.println("這是廚師老師的紅燒int的方法");
}
}
class Cs extends Ct{
void hongshao(int a) {
System.out.println("這是廚師徒弟的紅燒int的方法");
}
}
過載程式碼如下:
class Cs extends Ct{
void hongshao(int a) {
System.out.println("這是廚師徒弟的紅燒int的方法");
}
void hongshao(float b) {
System.out.println("這是廚師徒弟紅燒float的方法");
}
void hongshao(int a,float b) {
System.out.println("這是廚師徒弟紅燒int和float的方法");
}
}
5. 使用介面改寫例6.8中的程式。
建立介面
package bookcode.ex6.part6_8;
public interface Shape {
double getArea();
double getPerimeter();
void show();
}
圓類
package bookcode.ex6.part6_8;
public class Circle implements Shape{
private int r;
public Circle(int _r){
r = _r;
}
@Override
public double getArea() {
return r * r * Math.PI;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * r;
}
@Override
public void show() {
System.out.println("Circle Area:" + getArea());
System.out.println("Circle Perimeter:" + getPerimeter());
}
}
矩形類
package bookcode.ex6.part6_8;
public class Rect implements Shape {
private int k;
private int m;
public Rect(int width, int height) {
k = width;
m = height;
}
public double getArea() {
return (k * m);
}
public double getPerimeter() {
return (2 * k + 2 * m);
}
@Override
public void show() {
System.out.println("Rect Area:" + getArea());
System.out.println("Rect Perimeter:" + getPerimeter());
}
}
三角形類
package bookcode.ex6.part6_8;
import com.sun.tools.javac.file.SymbolArchive;
public class Triangle implements Shape{
private int x, y, z, m;
public Triangle(int _x, int _y, int _z){
x = _x;
y = _y;
z = _z;
m = (x + y +z) / 2;
}
@Override
public double getArea() {
return (Math.sqrt(m *(m - x) * (m - y) * (m - z)));
}
@Override
public double getPerimeter() {
return 2 * m;
}
@Override
public void show() {
System.out.println("Triangle Area:" + getArea());
System.out.println("Triangle Perimeter:" + getPerimeter());
}
}
執行
package bookcode.ex6.part6_8;
public class RunShape{
public static void main(String args[]){
Rect rect = new Rect(5 , 6);
Triangle triangle = new Triangle(3, 4, 5);
Circle circle = new Circle(5);
rect.show();
System.out.println();
triangle.show();
System.out.println();
circle.show();
}
}
6. 簡述運算子instanceof的使用場景。
instanceof 是 Java 的一個二元操作符,instanceof 是 Java 的保留關鍵字。它的作用是測試它左邊的物件是否是它右邊的類或子類的例項,返回 boolean 的資料型別。
package bookcode.ex6.part6_15;
class Uncle{}
class Pare{}
class Pare1 extends Pare{}
class Pare2 extends Pare1{}
public class InstanceofTest {
public static void main(String args[]) {
Uncle uncle = new Uncle();
Pare pare = new Pare();
Pare1 pare1 = new Pare1();
Pare2 pare2 = new Pare2();
//驗證pare
if (pare instanceof Pare) {
System.out.println("pare instanceof Pare");
}
if (!(pare instanceof Pare1)){
System.out.println("pare not instanceof Pare1");
}else if (pare instanceof Pare1){
System.out.println("pare instanceof Pare1");
}
if(!(pare instanceof Pare2)){
System.out.println("pare not instanceof Pare2");
}else if (pare instanceof Pare2){
System.out.println("pare instanceof Pare2");
}
System.out.println();
//驗證pare1
if (pare1 instanceof Pare1) {
System.out.println("pare instanceof Pare");
}
if (!(pare1 instanceof Pare)){
System.out.println("pare1 not instanceof Pare");
}else if(pare1 instanceof Pare){
System.out.println("pare1 instanceof Pare");
}
if(!(pare1 instanceof Pare2)){
System.out.println("pare1 not instanceof Pare2");
}else if(pare1 instanceof Pare2){
System.out.println("pare1 instanceof Pare2");
}
System.out.println();
//驗證pare2
if (pare2 instanceof Pare2) {
System.out.println("pare instanceof Pare");
}
if (!(pare2 instanceof Pare)){
System.out.println("pare2 not instanceof Pare");
}else if (pare2 instanceof Pare){
System.out.println("pare2 instanceof Pare");
}
if(!(pare2 instanceof Pare1)){
System.out.println("pare2 not instanceof Pare1");
}else if (pare2 instanceof Pare1){
System.out.println("pare2 instanceof Pare1");
}
System.out.println();
//驗證uncle
if (uncle instanceof Uncle){
System.out.println("uncle instanceof Uncle");
}
// 語法錯誤,無法編譯通過
/*
if (uncle instanceof Pare) {
System.out.println("uncle instanceof Pare");
}else {
System.out.println("uncle instanceof Pare");
}
if (!(uncle instanceof Pare1)){
System.out.println("uncle not instanceof Pare1");
}else {
System.out.println("uncle instanceof Pare1");
}
if(!(uncle instanceof Pare2)){
System.out.println("uncle not instanceof Pare2");
}else {
System.out.println("uncle instanceof Pare2");
}
*/
}
}