2013-02-03 27 views
11

Tôi đang cố gắng để có được vòng đầu của tôi như thế nào Java lựa chọn phương pháp nào được thực hiện:Java phương pháp quá tải lựa chọn

//Example 1 prints Square:add(Figure) 
Figure fs = new Square(); 
fs.add(fs); 

//Example 2 prints Square:add(Figure) 
Rectangle rs = new Square(); 
rs.add(fs); 

//Example 3 prints Rectangle:add(Rectangle). Expected Square:add(Square) 
rs.add(new Square()); 

//Example 4 prints Rectangle:add(Rectangle). Expected Square:add(Figure) 
Square ss = new Square(); 
ss.add(rs); 

class Figure 
{ 
    public void add(Figure f){ System.out.println("Figure:add(Figure)"); } 
} 

class Rectangle extends Figure 
{ 
    @Override 
    public void add(Figure f){ System.out.println("Rectangle:add(Figure)"); } 
    public void add(Rectangle r){ System.out.println("Rectangle:add(Rectangle)"); } 
} 

class Square extends Rectangle 
{ 
    @Override 
    public void add(Figure f){ System.out.println("Square:add(Figure)"); } 
    public void add(Square s){ System.out.println("Square:add(Square)"); } 
} 

Những gì tôi đã học được here

  • Phương pháp chữ ký được xác định dựa trên các kiểu dữ liệu thời gian biên dịch
  • Phương thức thực tế được gọi phụ thuộc vào loại động của đối tượng mà phương thức được gọi.

Dựa trên đó, kết quả của hai cuộc gọi đầu tiên như mong đợi. Tuy nhiên, tôi không hiểu kết quả của ví dụ 3 và 4.

Dường như được chỉ định trong số java language specification, nhưng tôi không hiểu.

+1

Là tác giả của câu hỏi chuyển nhượng này, tôi có thể xác nhận rằng các câu trả lời được cung cấp là chính xác. – Dominik

Trả lời

15

Tuy nhiên, tôi không hiểu kết quả của ví dụ 3 và 4.

Được rồi, chúng ta hãy nhìn vào chúng riêng rẽ.

Ví dụ 3

//Example 3 prints Rectangle:add(Rectangle). Expected Square:add(Square) 
rs.add(new Square()); 

Các bộ phận quan trọng là những thời gian biên dịch loại các biểu thức rsnew Square().

rs chỉ được khai báo là Rectangle, do đó trình biên dịch sẽ xem xét các phương pháp tuyên bố bởi Rectangle và superclasses của nó:

public void add(Figure f) 
public void add(Rectangle r) 

Kiểu của biểu thức new Square()Square, vì vậy cả hai phương pháp là áp dụng - nhưng cái thứ hai là nhiều hơn cụ thể.

Vì vậy, trình biên dịch sẽ gọi add(Rectangle) trên đối tượng mà rs đề cập đến. Đó là nó cho bên biên dịch thời gian.

Tại thời gian thực hiện, giá trị của rs đề cập đến một thể hiện của Square - nhưng Square không ghi đè add(Rectangle) nên phương pháp chọn là việc thực hiện trong Rectangle:

public void add(Rectangle r){ System.out.println("Rectangle:add(Rectangle)"); } 

Ví dụ 4

//Example 4 prints Rectangle:add(Rectangle). Expected Square:add(Figure) 
Square ss = new Square(); 
ss.add(rs); 

Một lần nữa, hãy xem xét các loại biên dịch có liên quan ... ss thuộc loại Squarers thuộc loại Rectangle (loại thời gian biên dịch, hãy nhớ).

Các phương pháp kê khai Square và superclasses của nó là:

public void add(Figure f) 
public void add(Rectangle r) 
public void add(Square s) 

Như kiểu thời gian biên dịch rs chỉ là Rectangle (không Square), hai phương pháp đầu tiên được áp dụng, nhưng ba không phải là . Do đó, một lần nữa, add(Rectangle) được chọn tại thời gian biên dịch (vì nó cụ thể hơn add(Figure)).

Một lần nữa, loại thời gian thực hiện là ssSquare, không ghi đè add(Rectangle), do đó việc triển khai trong Rectangle được sử dụng.

Hãy cho tôi biết nếu bất cứ điều gì ở đây gây nhầm lẫn - nếu bạn có thể cụ thể về phần nào, điều đó sẽ tuyệt vời.

3
rs.add(new Square()); 

Loại khai báo của rs là Hình chữ nhật. Vì vậy, nó nhìn vào một phương thức trong Rectangle và tất cả các superclasses lấy một Square hoặc một loại tương thích với Square làm đối số. Cụ thể nhất là add(Rectangle) vì Hình vuông là hình chữ nhật và Hình chữ nhật cụ thể hơn Hình.

Square ss = new Square(); 
ss.add(rs); 

Tìm phương pháp add(Rectangle) trong Square và tất cả siêu lớp. Rectangle.add(Rectangle) được chọn, vì Square.add(Square) không áp dụng (Hình chữ nhật không phải là hình vuông) và Square.add(Figure) ít cụ thể hơn.