2008-09-29 22 views
42

Có những tình huống, ở đó thực tế để có một kiểu truyền trở lại một giá trị null thay vì ném một ClassCastException. C# có toán tử as để thực hiện việc này. Có một cái gì đó tương đương có sẵn trong Java, do đó bạn không phải kiểm tra một cách rõ ràng cho ClassCastException?Làm thế nào để mô phỏng toán tử C# trong Java

Trả lời

47

Dưới đây là một thực hiện như, theo đề nghị của @Omar Kooheji:

public static <T> T as(Class<T> clazz, Object o){ 
    if(clazz.isInstance(o)){ 
     return clazz.cast(o); 
    } 
    return null; 
} 

as(A.class, new Object()) --> null 
as(B.class, new B()) --> B 
+1

Aaron, nếu tôi muốn chuyển một kiểu chung chung như tham số clazz vào hàm "as" của bạn? – mfalto

+1

câu trả lời tự ... không thể thực hiện được trong Java vì xóa kiểu – mfalto

+2

Tôi thích thiết kế của hàm trên 'as', nhưng nó làm phiền tôi rằng phương thức' isInstance' sẽ được gọi hai lần, do sử dụng phương thức 'cast' của lớp' Lớp '.Bên trong, phương thức này sử dụng phương thức 'IsIsntance' để kiểm tra tính tương thích giữa các kiểu. Tuy nhiên, chúng ta có thể mong đợi rằng JVM có thể nội tuyến mã 'cast' bên trong hàm' as' đã cho và sau đó Jitter có thể loại bỏ các cuộc gọi dư thừa sang phương thức 'IsInstance', nhưng chúng ta không thể chắc chắn về điều đó. –

13

Bạn có thể sử dụng từ khóa instanceof thay cho C# 'is', nhưng không có gì giống như as.

Ví dụ:

if(myThing instanceof Foo) { 
    Foo myFoo = (Foo)myThing; //Never throws ClassCastException 
    ... 
} 
+9

Vâng, dàn diễn viên cũ. Shame Java không có thứ gì tao nhã như toán tử 'as'. –

+1

'as' là một điều rất hữu ích. –

25

tôi nghĩ rằng bạn sẽ phải cuộn của riêng bạn:

return (x instanceof Foo) ? (Foo) x : null; 

EDIT: Nếu bạn không muốn mã khách hàng của bạn để đối phó với null, sau đó bạn có thể giới thiệu một Null Object

interface Foo { 
    public void doBar(); 
} 
class NullFoo implements Foo { 
    public void doBar() {} // do nothing 
} 
class FooUtils { 
    public static Foo asFoo(Object o) { 
     return (o instanceof Foo) ? (Foo) o : new NullFoo(); 
    } 
} 
class Client { 
    public void process() { 
     Object o = ...; 
     Foo foo = FooUtils.asFoo(o); 
     foo.doBar(); // don't need to check for null in client 
    } 
} 
-2

tôi đang suy đoán bạn propably thể creas một như nhà điều hành

cái gì đó như

as<T,Type> (left, right) 
which evaluates to 
if (typeof(left) == right) 
    return (right)left 
else 
    return null 

Tôi không chắc chắn làm thế nào bạn muốn làm điều đó, tôi là một C# vào lúc này và mũ Java của tôi đã nhận được một bụi chút kể từ khi tôi rời khỏi trường đại học.

+1

So sánh loại bê tông, nghĩa là 'typeof (bên trái) == right' không phải là thứ' as'. – weston

10

Bạn có thể viết phương thức tiện ích tĩnh như thế này. Tôi không nghĩ rằng nó có thể đọc được một cách khủng khiếp, nhưng đó là sự gần đúng nhất của những gì bạn đang cố gắng làm. Và nếu bạn sử dụng nhập khẩu tĩnh, nó sẽ không quá tệ về khả năng đọc.

package com.stackoverflow.examples; 
public class Utils { 
    @SuppressWarnings("unchecked") 
    public static <T> T safeCast(Object obj, Class<T> type) { 
     if (type.isInstance(obj)) { 
      return (T) obj; 
     } 
     return null; 
    } 
} 

Dưới đây là một trường hợp thử nghiệm đó chứng tỏ cách thức hoạt động (và rằng nó làm việc.)

package com.stackoverflow.examples; 
import static com.stackoverflow.examples.Utils.safeCast; 
import static junit.framework.Assert.assertNotNull; 
import static junit.framework.Assert.assertNull; 

import org.junit.Test; 

public class UtilsTest { 

    @Test 
    public void happyPath() { 
     Object x = "abc"; 
     String y = safeCast(x, String.class); 
     assertNotNull(y); 
    } 

    @Test 
    public void castToSubclassShouldFail() { 
     Object x = new Object(); 
     String y = safeCast(x, String.class); 
     assertNull(y); 
    } 

    @Test 
    public void castToUnrelatedTypeShouldFail() { 
     Object x = "abc"; 
     Integer y = safeCast(x, Integer.class); 
     assertNull(y); 
    } 
} 
+0

Điều này không thực sự hiệu quả. isAssignableTừ các bài kiểm tra để xem liệu obj có phải là một thể hiện của một siêu lớp của T. Do đó, safeCast (new Object(), A.class) .doA() sẽ trả về một lớp ngoại lệ, chứ không phải là một NPE. –

+0

bạn nói đúng. Tôi đã có hai đối tượng lớp ngược. Tôi đã chỉnh sửa câu trả lời và nó phải chính xác ngay bây giờ. –

+1

Có lý do cụ thể nào để sử dụng loại .isAssignableFrom (obj.getClass() thay vì type.isInstance (obj)? – VoidPointer

0

Trong java 8, bạn cũng có thể sử dụng cú pháp luồng với Tùy chọn:

Object o = new Integer(1); 

Optional.ofNullable(o) 
     .filter(Number.class::isInstance) 
     .map(Number.class::cast) 
     .ifPresent(n -> System.out.print("o is a number")); 
Các vấn đề liên quan