2013-04-16 35 views
7

ben etkili yapar genel bir yöntem oluşturmak istiyorum hiçbir Number.valueOf() yöntemidir ve 0 döküm edilemez T.Java jenerikler ve sayısal tipleri

Örnek kullanım:

String value = "0.00000001"; 

System.out.println("Double: " + MyClass.<Double>sloppyParseNumber(value)); 
System.out.println("Float: " + MyClass.<Float>sloppyParseNumber(value)); 

double d = MyClass.sloppyParseNumber(value); 
float f = MyClass.sloppyParseNumber(value); 

Java ile olası jenerik yöntemle yukarıda uyguluyor? Evet ise nasıl? Eğer hayır ise, iyi bir alternatif yaklaşım nedir?


Düzenleme: birkaç olası çiftleri var gibi görünüyor, ama tam olarak bu kapakları birini bulamadık. Bu iki işlemi yapabilmem için çekmesi gereken bir hile olduğunu umuyorum: Number alt sınıfına dize ayrıştırma ve Number alt sınıfı için 0 değerini döndür.

+1

['Number'] (http://docs.oracle.com/javase/6/docs/api/java/lang/Number.html) özet sınıfı, ayrıştırma belirli bir tür tarafından yapıldığı için, dizeyi bir türe ayrıştırmak için herhangi bir yöntem içermez. Bir öneri jenerik kullanmamak, ama 'ToInteger',' ... ToDouble' vb. Gibi fonksiyonlar yaratmaktır. –

+0

Bunu yapmanın kolay bir yolu olduğunu sanmıyorum. Yeni MyClass (value) .asDouble(); gibi bir şeyi kullanırım ve "asInteger", "asLong", "asFloat", "asDouble" vb. Yöntemlerini elle uygulardım. – assylias

+3

'T.valueOf() 'wouldn' Statik bir yöntem olsa bile çalışın 'Number.valueOf() '; Bunun gibi jenerik türleri kullanamazsınız. –

cevap

3

TofuBeer ile% 100 katılıyorum.

static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) { 

    if (clas == null) throw new NullPointerException("clas is null"); 

    try { 

     if(clas.equals(Integer.class)) { 
      return (T) Integer.valueOf(str); 
     } 
     else if(clas.equals(Double.class)) { 
      return (T) Double.valueOf(str); 
     } 
     //so on 

    catch(NumberFormatException|NullPointerException ex) { 
     // force call with valid arguments 
     return sloppyParseNumber("0", clas); 
    } 

    throw new IllegalArgumentException("Invalid clas " + clas); 

} 

Ama tamamen T itibaren, çalışma zamanında türünü alamıyor: Ama durumda zaman uğruna ayrıntı önlemek isteyen, bu da yapmalıdır.

static String trimTo0(String str) { 
    if (str == null) return "0"; 
    str = str.trim(); 
    if (str.isEmpty()) return "0"; 
    return str; 
} 

Kullanımı:

+0

Bu, soruyu sorduğum soruya en yakın olan yaklaşım gibi görünüyor, yine de cevabını istisnaları yakalamak ve doğru alt sınıfı döndürmek için tercih etmemi tercih ediyorum (yani "T" yi döndürmek ve "Sınıf clas" parametresine sahip olmak istiyorum)). – hyde

+0

Düzenlendi. Teşekkürler. – Jatin

3

Java jenerik bilgileri yalnızca derleme zamanı denetimleri sağlar ve derleme sonrasında tür bilgileri hemen hemen atılır. Yani, T.valueOf ifadesi Java'da mümkün değildir. Çözüm, yorumlarda daha önce bahsedildiği gibi ayrıntılı bir yola gitmek. Ayrıca, neden derleme zamanında türünü belirttiğiniz için MyClass.<Double>sloppyParseNumber(value), ancak MyClass.sloppyParseDouble(value) yapmak istediğiniz herhangi bir neden var mı?

+0

@hyde: Anladığımdan emin değilim. "Her zamanki gibi aynı işlevdir ve türün hiçbir şey yapmaz" dediğiniz zaman, neden türün hiçbir şey yapmadığını düşündüğünü düşünüyorsunuz? Güncellenmiş örneğinizde 'sloppyParseNumber' dönüş tipi ne olacak? Geçilen sayının "BigDecimal", "Double", "Float", "Integer" vb. Olarak mı ayrıştırılacağını nasıl bilecek? –

+0

Bir daha deneyelim: MyClass'ın amacı. sloppyParseNumber', yöntemin Double nesnesini döndürmesini sağlamak olurdu, ancak aslında Java jenerikleri bu şekilde çalışmaz, yöntem, <> 'içinde arayan tarafından belirtilen türü bilmez. – hyde

2

Türü, en iyi durumda olduğu için, Number ve Number, valueOf yönteminin ne işe yaramayacağı konusunda bir yöntem yoktur.

kolay yolu sadece ... sloppyParseInt, sloppyParseFloat, vb gibi statik yöntemler bir dizi yapmaktır

Sen Hoşuma emin değilim böyle bir şey yapabileceğini ve muhtemelen üzerinde geliştirilebilir:

public class Main 
{ 
    private static final Map<Class<? extends Number>, NumberConverter> CONVERTERS; 

    static 
    { 
     CONVERTERS = new HashMap<>(); 
     CONVERTERS.put(Integer.class, new IntegerConverter()); 
    } 

    public static void main(String[] args) 
    { 
     Number valueA; 
     Number valueB; 

     valueA = CONVERTERS.get(Integer.class).convert("42"); 
     valueB = CONVERTERS.get(Integer.class).convert("Hello, World!"); 

     System.out.println(valueA); 
     System.out.println(valueB); 
    } 
} 

interface NumberConverter<T extends Number> 
{ 
    T convert(String str); 
} 

class IntegerConverter 
    implements NumberConverter<Integer> 
{ 
    @Override 
    public Integer convert(String str) 
    { 
     try 
     { 
      return Integer.valueOf(str); 
     } 
     catch (NumberFormatException ex) 
     { 
      return 0; 
     }  
    } 
} 
+2

Daha iyi bir API'nin 'NumberConvert.convert (Integer.class, string)' gibi bir çağrı olması ve ayrıntıları dahili olarak ele alması gerektiğini düşünüyorum. –

0

Yani, alternatif bir yaklaşım karar bu, söz konusu yöntemin daha sınırlı olduğunu

String value = null; 
System.out println("Double value: " + Double.parseDouble(trimTo0(value))); 

Not bu geçersiz dönüştürmez, sivil sayısal dizeleri "0". Bunu tam olarak yapmak, iki ayrı yöntemi, bir ondalık noktasını ve bir başka sadece tam sayıları destekleyenleri gerektirir.

0

Bu deneyebilirsiniz:

İşte
private <T> T convertToType(Class<T> clazz,String str) throws Exception { 
    return clazz.getConstructor(String.class).newInstance(str); 
} 

Eğer türü bir dize parametresi olan bir yapıcı olması gerektiğini dikkate almak gerekir.