2013-09-06 17 views
5

Trong khi đọc về hiệp biến Overriding, tôi tìm hiểu thực tế rất lạ,Làm thế nào hiệp biến trọng phương pháp được thực hiện bằng cầu nối kỹ thuật trong java

hiệp biến phương pháp trọng được thực hiện bằng cách sử dụng kỹ thuật chuyển tiếp. nó cũng cho biết rằng tính năng này được thực hiện trong java5 trở lên. (Tôi nghĩ rằng đó là vì Generics giới thiệu từ java5)

Làm thế nào nó happens.Please giúp tôi với ví dụ.

Trả lời

7

Hãy xem xét một ví dụ:

public interface Shape<T extends Shape<T>> { 
    T getType(); 
    void setType(T type); 
} 

public class Circle implements Shape<Circle> { 
    Circle getType() { } 
    void setType(Circle circle) { } 
} 

Nó có vẻ tốt như bây giờ. Tuy nhiên, sau khi xóa kiểu, giao diện mất đi loại chung của nó và loại T được thay thế bằng giới hạn trên. Giao diện và lớp học trông giống như:

public interface Shape { 
    Shape getType(); 
    void setType(Shape type); 
} 

public class Circle implements Shape { 
    Circle getType() { } 
    void setType(Circle circle) { } 
} 

Bây giờ, đây là vấn đề. Phương pháp trong Circle sau khi xóa không thực sự là phiên bản bị ghi đè của Shape. Lưu ý rằng, bây giờ các phương thức hiển thị, áp dụng hạn chế lớn hơn đối với tham số cần thiết và giá trị nó trả về. Điều này là do xóa bỏ thay đổi chữ ký của phương thức trong giao diện.

Để giải quyết vấn đề này, trình biên dịch thêm phương thức cầu cho những người, đại biểu cuộc gọi đến các phương thức thực tế đó trong lớp.

Vì vậy, các lớp được thực sự chuyển đổi sang:

public class Circle implements Shape { 
    Circle getType() { } 
    void setType(Circle circle) { } 

    // Bridge method added by compiler. 
    Shape getType() { return getType(); } // delegate to actual method 
    void setType(Shape shape) { setType((Circle)shape); } // delegate to actual method 
} 

Vì vậy, phương pháp cầu hiện nay là phiên bản ghi đè các phương pháp trong giao diện, và họ giao phó cuộc gọi đến phương pháp thực tế mà không được công nhiệm vụ .

Lưu ý rằng loại được sử dụng trong phương pháp cầu là xóa thông số loại của giao diện, trong trường hợp này là Shape.


Tài liệu tham khảo:

+0

Rất thú vị! Và không có lỗi vì hai phương thức có cùng tên/tham số trong cùng một lớp? I E. thông báo "Phương thức trùng lặp getType() trong loại Vòng kết nối"? – sp00m

+0

@ sp00m: sẽ xảy ra lỗi nếu bạn cố chuyển nó tới trình biên dịch Java, vì các phương thức không thể khác nhau chỉ bằng kiểu trả về. Nhưng ở cấp độ bytecode JVM, hạn chế đó không tồn tại. – mhsmith

1

Điều này có nghĩa là nếu bạn có một phương thức có kiểu trả về biến đổi (hẹp hơn), trình biên dịch sẽ tạo ra phương thức tổng hợp cầu tổng hợp cho bạn và gọi phương thức ghi đè thông qua phương thức cầu này. Hiệp phương sai trong kiểu trả về đã được giới thiệu trong Java 5, cùng lúc với Generics và nó được thực hiện bằng cách sử dụng phương thức cầu cầu.

Ví dụ 1: Phương sai hiệp phương theo kiểu trả về cũng được thực hiện bằng phương pháp cầu tổng hợp ngay cả khi không có generics.

Ví dụ:

abstract class A {  

    public abstract A get(); 
} 

class B extends A { 

    @Override 
    public B get() { 
    return this; 
    } 
} 

sẽ được thực hiện trong bytecode bởi trình biên dịch sử dụng một phương pháp tổng hợp cầu mà đại biểu cho phương thức ban đầu. Về nguyên tắc, bạn có thể tưởng tượng rằng các trình biên dịch ghi đè hiệp biến như sau:

abstract class A {  

    public abstract A get(); 
} 

class B extends A { 

    //bytecode only bridge method 
    @Override 
    public A get() { 
    return get; 
    } 

    public B get() { 
    return this; 
    } 
} 

Ví dụ 2 - Generics: Hãy xem xét một ví dụ khi Generics có liên quan.

abstract class A<T> {  

    public abstract T get(); 
} 

class B extends A<String> { 

    @Override 
    public String get() { 
    return "hello"; 
    } 
} 

Phương pháp này get() của lớp B là hiệp biến trong kiểu trả về với phương pháp get trong lớp A. Khi biên dịch bit mã này trình biên dịch sẽ thực hiện xóa có nghĩa là nó sẽ thay thế generics với giới hạn của họ và thêm phôi để đảm bảo rằng tất cả mọi thứ hoạt động.

Sau khi tẩy xoá các lớp trông như thế này:

abstract class A { 

    public abstract Object get(); 
} 

class B extends A { 

    @Override 
    public String get() { 
    return "hello"; 
    } 
} 

Bây giờ kể từ khi phương pháp chữ ký của getpublic Object get() mà không phải là một chữ ký đó là hiện diện trong lớp B trình biên dịch sẽ tạo ra một phương pháp cầu trong lớp B trong để đạt được trọng số.

Bạn có thể nghĩ về lớp học B giống như bên dưới. Tuy nhiên, điều quan trọng cần lưu ý là mã bên dưới sẽ không bao giờ được tạo. Nó sẽ không biên dịch. Trình biên dịch chỉ tạo phương thức tương đương get trong bytecode.

class B extends A { 

    //bridge method 
    @Override 
    public Object get() { 
    return get(); 
    } 

    public String get() { 
    return "hello"; 
    } 
} 

Mỗi sử dụng đa hình của lớp B qua A mà gọi get sẽ gọi phương thức cầu đó sẽ uỷ thác cho get thực phương pháp.

1

Với hai loại sau đây:

public class Node<T> { 
    private T data; 
    public Node(T data) { this.data = data; } 

    public void setData(T data) { 
     System.out.println("Node.setData"); 
     this.data = data; 
    } 
} 

public class MyNode extends Node<Integer> { 
    public MyNode(Integer data) { 
super(data); } 
    public void setData(Integer data) { 
     System.out.println("MyNode.setData"); 
     super.setData(data); 
    } 
} 

Khi biên dịch một lớp hoặc giao diện kéo dài một lớp tham số hoặc thực hiện một giao diện tham số, trình biên dịch có thể cần phải tạo ra một phương pháp tổng hợp, được gọi là phương pháp cầu, như một phần của quá trình tẩy xóa kiểu.

Để giải quyết vấn đề này và duy trì tính đa hình của các loại chung sau khi xóa, trình biên dịch Java tạo ra phương thức cầu để đảm bảo rằng việc phân loại hoạt động như mong đợi. Đối với lớp MyNode, trình biên dịch tạo ra phương thức cầu sau đây cho setData:

class MyNode extends Node { 

    // Bridge method generated by the compiler 
    // 
    public void setData(Object data) { 
     setData((Integer) data); 
    } 

    public void setData(Integer data) { 
     System.out.println("MyNode.setData"); 
     super.setData(data); 
    } 

    // ... 
} 
Các vấn đề liên quan