我现在花了几天时间处理这个琐碎的问题,但却找不到解决办法。
以下是我要做的事情: 读取行输入并根据具体情况更改数据的解释 关键字。这些关键字可以由客户端对象动态注册。他们 注册关键字和“回调”功能(想要更好的词)。 遇到关键字时会调用此“回调”函数 处理输入字符串并返回标准化对象。
为此,我创建了一个HashMap,其中Keyword为键,Method引用为value。 在程序初始化期间,所有想要使用该服务的对象都会注册它。
初始化后,读取输入并检查我的hashmap类型的关键字。如果那里存在类型,则传递值字符串以进行处理,并返回字符串数据中的标准化Object表示。
我设法通过查找其名称和检索来哄骗方法参考 方法。下面的代码可以传递,存储和检索方法,但是当尝试调用它时,它会产生IllegalArgument异常。
在我的研究过程中,我发现了几个类似问题的报告,其中也包括在这个网站上,但大多数都没有解决我的确切问题。
在one case中,有人建议调用方法不起作用,因为没有实例化方法的实例。可以通过调用newInstance方法来修复该方法所需的实例化。它对我不起作用,因为我无法从该方法引用中获取新实例。
尝试了各种不同的方法,从接口到Java8方法引用和监听器模式。他们都允许传递方法引用,但我总是遇到一个死机,因为我不得不在XSettings中声明客户端的实例。这恰恰是 我不能做什么,因为我不知道如何改变XSettings。
以下是我的代码:
Locus.java
---------------------------------
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.function.Function;
...
public class Locus implements StringConverter{
private long x;
private long y;
public Locus(int x, int y) {
super();
this.x = x;
this.y = y;
}
public Locus(long x, long y) {
super();
this.x = x;
this.y = y;
}
public Locus(String s) {
super();
Locus lc = (Locus) convert(s);
this.x = lc.x;
this.y = lc.y;
}
private long getLongFromString(String s1){
long res=0L;
if(s1.matches("[0-9]*$")) // Integer detected
res = (long)(Integer.parseInt(s1));
// Long detected
else if(s1.matches("[0-9]*[lL]$")){
s1=s1.split("[lL]")[0];
if(!s1.isempty()) // don't parse empty strings
res = Long.parseLong(s1);
} // Double detected
else if(s1.matches("[0-9][0-9]*\\.[0-9]*$"))
res = (long) Double.parseDouble(s1);
return res;
}
public Object convert (String s) {
long x=0, y=0;
if(s.contains(",")){
String[] parts = s.split("\\,");
parts[0] = parts[0].trim();
parts[1] = parts[1].trim();
x = getLongFromString(parts[0]);
y = getLongFromString(parts[1]);
}
return createLocus(x, y);
}
public static void init() {
Method method = null;
try {
method = Locus.class.getDeclaredMethod("convert", String.class);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(method != null)
XSettings.setTypeHandler("Locus", method);
}
...
}
---------------------------------
XSettings.java
---------------------------------
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Iterator;
public class XSettings {
// *************************************************
// Singleton Pattern
private XSettings(){}
private static class InstanceHolder {
public static final XSettings instance = new XSettings();
}
public XSettings getInstance() {
return InstanceHolder.instance;
}
// *************************************************
static final String cfgFileName="C:\\workspace\\Router\\route.cfg";
// Map with the payload data to be queried
public static HashMap<String, Object> settings = new HashMap<String, Object>();
// Map with Key / method-references
static HashMap<String, Method> typeHandler = new HashMap<String, Method>();
// caller method for the object converters
public static Object convertToType(String type, String value){
Object result = null;
Method method = typeHandler.get(type);
if(method!=null){ // method exists
try {
result = method.invoke(method, value); // <------ causes IllegalArgumentException
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
result=value; // No? Default pass back the input string
}
return result;
}
// store the method refernce in map
public static void setTypeHandler(String key, final Method method) {
typeHandler.put(key, method);
}
// Store a payload key value pair
public static void set(String key, Object value) {
settings.put(key, value);
}
// Retrieve a value by key
public static Object get(String key) {
return settings.get(key);
}
public static void init(){ // read input
String line;
try (
InputStream fis = new FileInputStream(cfgFileName);
InputStreamReader isr = new InputStreamReader(fis, Charset.forName("UTF-8"));
BufferedReader br = new BufferedReader(isr);
)
{
while ((line = br.readLine()) != null) { Parse the lines
String key="";
String type="";
String val="";
line=line.trim(); // trim back empty space
System.out.println(line);
if(line.isEmpty()) // skip empty lines
continue;
if(line.charAt(0)=='#') // skip comment lines
continue;
String[] subs = line.split("=",2); // split at assignment
continue;
subs[0]=subs[0].trim(); // key Part
subs[1]=subs[1].trim(); // value Part
String[] subValues = subs[0].split("::", 2); //Split at type, key section
if(subValues.length==1){ // empty value
key = subValues[0];
} else if(subValues.length>1){ // normal key, value case
type = subValues[0];
key = subValues[1];
} else { // no assignment operator, empty value
key = subs[0];
}
subValues = subs[1].split("\""); // remove double quotes from value part
if(subValues.length==0){ // no quotes and no value
val = "";
} else if(subValues.length==1){ // no quotes
val = subValues [0];
} else if(subValues.length==2){ // quotes present, stripped
val = subValues [1];
} else // more than two quotes treat as a string only
val = subs[1];
if(!typeExists(type)){ // check if type is in methodHandler
key = subs[0]; // No: set key back to full L-Value
type = "";
}
settings.put(key, convertToType(type, val)); // Call converter
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static boolean typeExists(String type) {
boolean res=false;
if(type!=null)
if(!(type.isEmpty()))
Object m = typeHandler.get(type);
res=(m!=null);
return res;
}
...
}
---------------------------------
服务功能是XSettings,客户端是Locus。 XSettings读取 逐行输入文件,扫描它以获取关键值对。钥匙可能 包含目标类名称。因此该行分为Type,Key和Value。
价值的解释因类型而异。默认情况下,仅存储字符串 远。当其他对象注册关键字并提供转换方法时 他们被拾起并转换成所需的对象。所以当关键是 查询结果是正确的对象。
我设法将方法引用一直到调用点。该 将对象传递给setTypeHandler时,对象在Locus中看起来是相同的 XSettings的方法,以及从HashMap和之前检索之后的方法 调用。然后是IllegalArgumentException ...
这可能是一种非常“C”式的做法,但我一直认为这样做 相对高效和优雅。但是,如果有更好的类似Java的方式,我会很高兴听到它。
感谢您的关注。真的很期待你的回音。
答案 0 :(得分:0)
我认为在XSettings.convertToType中,首先需要创建指定类型的实例,然后在此实例上调用指定的方法。
创建此类型的实例意味着:加载此类型的类,使用反射api搜索默认构造函数并调用此构造函数以获取此类型的实例。