Java generics T so với Object


127

Tôi đã tự hỏi sự khác biệt giữa hai khai báo phương thức sau là gì:

public Object doSomething(Object obj) {....}

public <T> T doSomething(T t) {....}

Có điều gì bạn có thể / sẽ làm với cái này mà không phải cái kia không? Tôi không thể tìm thấy câu hỏi này ở nơi khác trên trang web này.

Câu trả lời:


112

Cô lập với ngữ cảnh - không có sự khác biệt. Trên cả hai tobjbạn chỉ có thể gọi các phương thức của Object.

Nhưng với ngữ cảnh - nếu bạn có một lớp chung:

MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();

Sau đó:

Foo newFoo = my.doSomething(foo);

Cùng mã với đối tượng

Foo newFoo = (Foo) my.doSomething(foo);

Hai ưu điểm:

  • không cần truyền (trình biên dịch ẩn điều này với bạn)
  • biên dịch an toàn thời gian hoạt động. Nếu Objectphiên bản được sử dụng, bạn sẽ không chắc rằng phương thức luôn trả về Foo. Nếu nó trả về Bar, bạn sẽ có một ClassCastException, trong thời gian chạy.

14

Sự khác biệt ở đây là trong lần đầu tiên, chúng tôi chỉ định rằng người gọi phải chuyển một cá thể Đối tượng (bất kỳ lớp nào) và nó sẽ nhận lại một Đối tượng khác (bất kỳ lớp nào, không nhất thiết phải cùng loại).

Trong lần thứ hai, kiểu được trả về sẽ cùng kiểu với kiểu đã cho khi lớp được định nghĩa.

Example ex = new Example<Integer>();

Ở đây chúng tôi chỉ định kiểu T sẽ là gì, cho phép chúng tôi thực thi nhiều ràng buộc hơn trên một lớp hoặc phương thức. Ví dụ, chúng ta có thể khởi tạo một LinkedList<Integer>hoặc LinkedList<Example>và chúng ta biết rằng khi chúng ta gọi một trong các phương thức này, chúng ta sẽ nhận lại một cá thể Số nguyên hoặc Ví dụ.

Mục tiêu chính ở đây là mã gọi có thể chỉ định loại đối tượng nào mà một lớp sẽ hoạt động, thay vì dựa vào kiểu ép kiểu để thực thi điều này.

Xem Java Generics * từ Oracle.

* Liên kết cập nhật.


13

Sự khác biệt là với các phương thức chung, tôi không cần ép kiểu và tôi gặp lỗi biên dịch khi làm sai:

public class App {

    public static void main(String[] args) {

        String s = process("vv");
        String b = process(new Object()); // Compilation error
    }

    public static <T> T process(T val) {

        return val;
    }
}

Sử dụng đối tượng, tôi luôn cần truyền và tôi không gặp bất kỳ lỗi nào khi tôi làm sai:

public class App {

    public static void main(String[] args) {

        String s = (String)process("vv");
        String b = (String)process(new Object());
    }

    public static Object process(Object val) {

        return val;
    }
}

giống như đề cập đến việc bạn không cần phải cast các đối tượng nữa, kể từ android 6.
John Lord

2

Bạn không cần thực hiện thêm lớp truyền. Trong trường hợp đầu tiên, bạn sẽ luôn nhận được một đối tượng của lớp java.lang.Object mà bạn sẽ cần truyền đến lớp của mình. Trong trường hợp thứ hai, T sẽ được thay thế bằng lớp được định nghĩa trong chữ ký chung và không cần ép lớp.


2

Trong thời gian chạy, không có gì. Nhưng tại thời điểm biên dịch, thứ hai sẽ thực hiện kiểm tra kiểu để đảm bảo kiểu của tham số và kiểu của giá trị trả về khớp (hoặc là các kiểu con của) bất kỳ kiểu nào mà T giải quyết (ví dụ đầu tiên cũng thực hiện kiểm tra kiểu nhưng mọi đối tượng là một kiểu phụ của Đối tượng nên mọi kiểu sẽ được chấp nhận).


2

T là một loại chung chung. Có nghĩa là nó có thể được thay thế bởi bất kỳ đối tượng đủ điều kiện nào trong thời gian chạy. Bạn có thể gọi một phương thức như sau:

String response = doSomething("hello world");

HOẶC LÀ

MyObject response = doSomething(new MyObject());

HOẶC LÀ

Integer response = doSomething(31);

Như bạn thấy, có sự đa hình ở đây.

Nhưng nếu nó được khai báo là trả về Object, bạn không thể thực hiện điều này trừ khi bạn nhập kiểu cast.


Chúng ta có thể nói rằng <T>không có autoboxing?
SMUsamaShah

0

trong trường hợp đầu tiên, nó nhận một tham số của bất kỳ kiểu ví dụ nào và trả về một kiểu foo. Trong trường hợp thứ hai, nó nhận một tham số kiểu foo và trả về một đối tượng kiểu foo.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.