Co więcej, większość języków skryptowych (takich jak Perl) i niestatyczne języki kompilacji (takie jak Pick) obsługują automatyczną konwersję dynamicznych ciągów znaków w czasie wykonywania na (względnie dowolne) konwersje obiektów. MOŻNA to osiągnąć również w Javie bez utraty bezpieczeństwa typów, a dobre rzeczy w językach statycznych zapewniają BEZ nieprzyjemnych efektów ubocznych niektórych innych języków, które robią złe rzeczy z dynamicznym rzutowaniem. Przykład Perla, który wykonuje pewne wątpliwe obliczenia:
print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
W Javie lepiej jest to osiągnąć (IMHO), używając metody, którą nazywam „cross-castingiem”. W przypadku rzutowania krzyżowego odbicie jest używane w ładowanej z opóźnieniem pamięci podręcznej konstruktorów i metod, które są wykrywane dynamicznie za pomocą następującej metody statycznej:
Object fromString (String value, Class targetClass)
Niestety, żadne wbudowane metody Java, takie jak Class.cast (), nie zrobią tego w przypadku String to BigDecimal lub String to Integer ani żadnej innej konwersji, w której nie ma obsługującej hierarchii klas. Z mojej strony chodzi o zapewnienie w pełni dynamicznego sposobu osiągnięcia tego celu - do czego nie sądzę, aby wcześniejsze odniesienie było właściwym podejściem - konieczności kodowania każdej konwersji. Mówiąc najprościej, implementacja polega po prostu na rzutowaniu ze łańcucha, jeśli jest to legalne / możliwe.
Tak więc rozwiązaniem jest prosta refleksja, szukanie publicznych Członków:
STRING_CLASS_ARRAY = (nowa klasa [] {String.class});
a) Member member = targetClass.getMethod (method.getName (), STRING_CLASS_ARRAY); b) Member member = targetClass.getConstructor (STRING_CLASS_ARRAY);
Przekonasz się, że wszystkie prymitywy (Integer, Long itp.) I wszystkie podstawy (BigInteger, BigDecimal itp.), A nawet java.regex.Pattern są objęte tym podejściem. Używałem tego z dużym sukcesem w projektach produkcyjnych, w których istnieje ogromna liczba dowolnych danych wejściowych wartości ciągu, w których potrzebne było bardziej ścisłe sprawdzenie. W tym podejściu, jeśli nie ma metody lub gdy metoda jest wywoływana, generowany jest wyjątek (ponieważ jest to niedozwolona wartość, taka jak nieliczbowe dane wejściowe do BigDecimal lub niedozwolone wyrażenie regularne dla wzorca), które zapewnia sprawdzenie specyficzne dla logika nieodłączna klasy docelowej.
Ma to pewne wady:
1) Musisz dobrze zrozumieć refleksję (jest to trochę skomplikowane i nie dla nowicjuszy). 2) Niektóre klasy Java, a nawet biblioteki innych firm są (niespodzianka) nieprawidłowo zakodowane. Oznacza to, że istnieją metody, które pobierają pojedynczy argument łańcuchowy jako dane wejściowe i zwracają wystąpienie klasy docelowej, ale nie jest to to, co myślisz ... Rozważmy klasę Integer:
static Integer getInteger(String nm)
Determines the integer value of the system property with the specified name.
Powyższa metoda tak naprawdę nie ma nic wspólnego z liczbami całkowitymi jako obiektami zawijającymi prymitywy int. Refleksja uzna to za możliwego kandydata do niepoprawnego utworzenia liczby całkowitej z ciągu znaków w porównaniu z elementami składowymi dekodowania, valueof i konstruktora - które są odpowiednie dla większości dowolnych konwersji typu String, w których naprawdę nie masz kontroli nad danymi wejściowymi, ale po prostu chcesz wiedzieć, czy jest to możliwe, liczba całkowita.
Aby temu zaradzić, dobrym początkiem jest znalezienie metod, które generują wyjątki, ponieważ nieprawidłowe wartości wejściowe, które tworzą wystąpienia takich obiektów, powinny zgłaszać wyjątek. Niestety implementacje różnią się pod względem tego, czy wyjątki są zadeklarowane jako zaznaczone, czy nie. Integer.valueOf (String) zgłasza na przykład sprawdzony wyjątek NumberFormatException, ale podczas wyszukiwania odbić nie można znaleźć wyjątków Pattern.compile (). Ponownie, myślę, że nie jest to błąd tego dynamicznego podejścia do rzutowania krzyżowego, a raczej bardzo niestandardowej implementacji deklaracji wyjątków w metodach tworzenia obiektów.
Jeśli ktoś chciałby uzyskać więcej szczegółów na temat tego, jak zostało wdrożone powyższe, daj mi znać, ale myślę, że to rozwiązanie jest znacznie bardziej elastyczne / rozszerzalne i zawiera mniej kodu bez utraty dobrych elementów bezpieczeństwa typów. Oczywiście zawsze najlepiej „znać swoje dane”, ale jak wielu z nas się przekonuje, czasami jesteśmy tylko odbiorcami niezarządzanych treści i musimy zrobić wszystko, co w naszej mocy, aby je właściwie wykorzystać.
Twoje zdrowie.