[英]JAVA: Cast String to (dynamically known) primitive type in order to instantiate a (dynamically known) class
我有一個使用文本文件 ( 一個要求 )的存儲庫類,這意味着我必須讀取字符串並轉換它們才能實例化對象。 問題是我希望我的存儲庫類可以像我一樣使用它,以便使用它來操作不同的對象類型。
那么,是否有一種(更優雅的)方法可以將字符串動態地轉換為運行時所需的任何字段(原始)類型,同時避免使用大量ifs / switch的try-catch結構?
作為一個簡短的簡化版本,我希望objectA.txt只包含objectA的信息,類似於objectB.txt和我的Repository代碼來處理兩者:
存儲庫repo A =新存儲庫(“objectA.txt”,<A> 的類型列表 ); 輸入A a = repoA.getOne();
存儲庫repo B =新存儲庫(“objectB.txt”,< B類型列表 >); B b = repoB.getOne();
是)我有的:
public class FileRepository extends InMemoryRepository{
private String fileName;
private List<Class> types;
public FileRepository(String fileName, List<Class> types) {
//@param types
// - list containing the Class to be instantiated followed by it's field types
super();
this.fileName = fileName;
this.types=types;
loadData();
}
private void loadData() {
Path path = Paths.get(fileName);
try {
Files.lines(path).forEach(line -> {
List<String> items = Arrays.asList(line.split(","));
//create Class array for calling the correct constructor
Class[] cls=new Class[types.size()-1];
for (int i=1; i<types.size(); i++){
cls[i-1]=types.get(i);
}
Constructor constr=null;
try {
//get the needed constructor
constr = types.get(0).getConstructor(cls);
} catch (NoSuchMethodException e) {
//do something
e.printStackTrace();
}
//here is where the fun begins
//@arg0 ... @argn are the primitives that need to be casted from string
//something like:
//*(type.get(1))* arg0=*(cast to types.get(1))* items.get(0);
//*(type.get(2))* arg1=*(cast to types.get(2))* items.get(1);
//...
Object obj= (Object) constr.newInstance(@arg0 ... @argn);
});
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
PS:我是JAVA新手,所以請盡可能簡單地解釋。
沒有IDE,所以我希望這是有道理的:
private static final Map<Class, Function<String, ?>> parsers = new HashMap<>();
static {
parsers.put(Long.class, Long::parseLong);
parsers.put(Integer.class, Integer::parseInt);
parsers.put(String.class, String::toString);
parsers.put(Double.class, Double::parseDouble);
parsers.put(Float.class, Float::parseFloat);
// add your own types here.
}
public <T> T parse(Class<T> klass, String value) {
// add some null-handling logic here? and empty values.
return (T)parsers.get(klass).apply(value);
}
然后,當您需要為構造函數創建參數時:
parameters =
IntStream
.range(0, cls.size-1)
.map(i -> (Object)parse(types.get(i), items.get(i)))
.toArray(Object[]::new);
我認為你可以利用自動裝箱和自動拆箱加上觀察所有包裝類提供一個名為valueOf
的方法,該方法接受一個String並返回相應(包裝)類型的實例,使得給定的字符串代表合法的該類型的價值 。
以下是針對您的需求的類型安全實現的嘗試:
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.Consumer;
/**
* Created by kmhaswade on 3/18/16.
*/
//@ThreadUnsafe
public class NonStreamingGenericPrimitiveDataRepo<T> implements Iterable<T> {
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
@Override
public boolean hasNext() {
return theIterator.hasNext();
}
@Override
public T next() {
String next = theIterator.next();
try {
Method m = theType.getDeclaredMethod("valueOf", String.class);
return (T) m.invoke(null, next);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException("This is impossible!");
} catch (InvocationTargetException e) {
throw new RuntimeException("data: " + next + " does not represent type: " + theType);
}
}
};
}
@Override
public void forEach(Consumer<? super T> action) {
throw new RuntimeException("left as an exercise :-) ");
}
private final ArrayList<String> theCache;
private final Iterator<String> theIterator;
private final Class<T> theType;
public NonStreamingGenericPrimitiveDataRepo(Reader reader, Class<T> theType) throws IOException {
Objects.requireNonNull(reader);
Objects.requireNonNull(theType);
if (Integer.class.equals(theType)
|| Long.class.equals(theType)
|| Float.class.equals(theType)
|| Double.class.equals(theType)
|| Boolean.class.equals(theType)
|| String.class.equals(theType)) {
theCache = new ArrayList<>();
try (BufferedReader br = new BufferedReader(reader)) {
String line;
while ((line = br.readLine()) != null)
theCache.add(line);
}
theIterator = theCache.iterator();
this.theType = theType;
} else {
throw new IllegalArgumentException("Not a wrapper type: " + theType);
}
}
public static void main(String[] args) throws IOException {
for (int i : new NonStreamingGenericPrimitiveDataRepo<>(ints(), Integer.class))
System.out.println("read an int: " + i);
for (float f : new NonStreamingGenericPrimitiveDataRepo<>(floats(), Float.class))
System.out.println("read a float: " + f);
for (boolean b: new NonStreamingGenericPrimitiveDataRepo<>(booleans(), Boolean.class))
System.out.println("read a boolean: " + b);
}
static StringReader ints() {
return new StringReader("1.w\n2\n-3\n4\n");
}
static StringReader floats() {
return new StringReader("1.0f\n3.25f\n-3.33f\n4.44f\n");
}
static StringReader booleans() {
return new StringReader("false \ntrue\n");
}
}
如果要從String中標識基本數據類型的類型,可以使用以下命令:
public class Test {
final static String LONG_PATTERN = "[-+]?\\d+";
final static String DOUBLE_PATTERN = "[-+]?(\\d*[.])?\\d+";
final static String BOOLEAN_PATTERN = "(true|false)";
final static String CHAR_PATTERN = "[abcdefghijklmnopqrstuvwxyz]";
public static void main(String[] args) {
String[] xList= {
"1", //int
"111111111111", //long
"1.1", //float
"1111111111111111111111111111111111111111111111111111.1", //double
"c", //char
"true", //boolean
"end" //String
};
for (String x: xList){
if(x.matches(LONG_PATTERN)){
long temp = Long.parseLong(x);
if (temp >= Integer.MIN_VALUE && temp <= Integer.MAX_VALUE){
System.out.println( x + " is int use downcast");
} else {
System.out.println( x + " is long");
}
} else if(x.matches(DOUBLE_PATTERN)){
double temp = Double.parseDouble(x);
if (temp >= Float.MIN_VALUE && temp <= Float.MAX_VALUE){
System.out.println( x + " is float use downcast");
} else {
System.out.println( x + " is Double");
}
} else if (x.toLowerCase().matches(BOOLEAN_PATTERN)){
boolean temp = x.toLowerCase().equals("true");
System.out.println(x + " is Boolean");
} else if(x.length() == 1){
System.out.println(x + " is char");
}else {
System.out.println( x + " is String");
}
}
}
}
輸出:
1 is int use downcast
111111111111 is long
1.1 is float use downcast
1111111111111111111111111111111111111111111111111111.1 is Double
c is char
true is Boolean
end is String
上面的代碼將您的String分為4個主要部分long integer,double,boolean,如果none則匹配String。 正如java所述,原始數據類型分為兩類:
Integers
byte
char (represented as a character)
short
int
long
Floating point numbers
float
double
Boolean
boolean
這樣,您就可以識別String所在的類型。 您可以修改代碼以檢查范圍並鍵入相應的數字,也可以是字節和短。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.