【发布时间】:2016-06-20 19:40:59
【问题描述】:
我已经花了几天时间解决这个棘手的问题,但找不到解决方案。
这是我想要做的: 读取一行输入并更改数据的解释,基于某些 关键词。这些关键字可以由客户端对象动态注册。他们 注册一个 keyword 和一个 "callback" 函数(因为需要更好的词)。 当遇到关键字时调用此“回调”函数,以便 处理输入字符串并返回一个标准化的对象。
为此,我创建了一个以关键字为键、方法引用为值的 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 的方式,我会很高兴听到它。
感谢您的关注。非常期待收到您的来信。
【问题讨论】:
标签: java methods interface callback pass-by-reference