
import javautilHashMap;
import javautilMap;
import javautilregexMatcher;
import javautilregexPattern;
public class ParseString {
private static final String PARAM_KEY = "!";
public static void main(String[] args) throws Exception {
// 待解析字符串
String method = "methodName(methodName2(methodName4(2,3,4),2),methodName3(),strName)";
// 这句很重要,先删除字符串中所有的空格,后面的正则中不再需要考虑空字符问题
method = methodreplaceAll("\\s+", "");
// 输出结果
for (MapEntry<String, Integer> entry : parseMethod(method)entrySet()) {
Systemoutprintln(entrygetKey() + " --- " + entrygetValue());
}
}
private static Map<String, Integer> parseMethod(String method) {
Map<String, Integer> ret = new HashMap<>();
Pattern p = Patterncompile("^([^\\(]+)\\(()\\)$");
Matcher m = pmatcher(method);
if (!mfind())
throw new RuntimeException("错误的方法字符串:" + method);
// 找到方法
Map<String, Integer> paramMap = parseParams(mgroup(2));
retput(mgroup(1)trim(), paramMapremove(PARAM_KEY));
retputAll(paramMap);
return ret;
}
private static Map<String, Integer> parseParams(String params) {
Map<String, Integer> ret = new HashMap<>();
int count = 0;
while(paramslength() > 0) {
if (paramssplit(",")[0]indexOf("(") >= 0) {
// 第一个参数为方法
String method = findFirstMethod(params);
params = (methodlength() == paramslength()) "" : paramssubstring(methodlength() + 1);
retputAll(parseMethod(method));
} else {
// 第一个参数为非方法
params = paramsreplaceAll("[^,]+(,(+))", "$2");
}
count++;
}
retput(PARAM_KEY, count);
return ret;
}
private static String findFirstMethod(String params) {
String method = "";
boolean start = false;
int matchCount = 0;
for (int i = 0; i < paramslength(); i++) {
char ch = paramscharAt(i);
if (ch == '(') {
start = true;
matchCount++;
} else if (ch == ')') {
matchCount--;
}
method += paramssubstring(i, i + 1);
if (start && matchCount == 0) break;
}
if (start)
return method;
throw new RuntimeException("错误的参数字符串:" + params);
}
}
可以使用以下代码来获取src目录下所有的包名,类名,方法名 以及通过一个类名获得该类下的所有方法名。
import javaioFile;
import javalangreflectMethod;
public class LoopApp {
public static void main(String[] args) throws Exception {
String packageName = "";
File root = new File(SystemgetProperty("userdir") + "\\src");
loop(root, packageName);
}
public static void loop(File folder, String packageName) throws Exception {
File[] files = folderlistFiles();
for (int fileIndex = 0; fileIndex < fileslength; fileIndex++) {
File file = files[fileIndex];
if (fileisDirectory()) {
loop(file, packageName + filegetName() + "");
} else {
listMethodNames(filegetName(), packageName);
}
}
}
public static void listMethodNames(String filename, String packageName) {
try {
String name = filenamesubstring(0, filenamelength() - 5);
Object obj = ClassforName(packageName + name);
Method[] methods = objgetClass()getDeclaredMethods();
Systemoutprintln(filename);
for (int i = 0; i < methodslength; i++) {
Systemoutprintln("\t" + methods[i]getName());
}
} catch (Exception e) {
Systemoutprintln("exception = " + egetLocalizedMessage());
}
}
}
可以使用js的eval函数实现,示例如下:
<script type="text/javascript">
//自定义函数,用于d出三个参数的值
function alertFunc(str1,str2,str3){
alert(str1);
alert(str2);
alert(str3);
}
//自定义函数:根据传入的函数名,调用函数
function callAlert(functionName){
//根据函数名得到函数类型
var func=eval(functionName);
//创建函数对象,并调用
new func(arguments[1],arguments[2],arguments[3]);
}
</script>
<!--编写按钮,在点击事件中调用函数-->
<button onclick="callAlert('alertFunc','tom','hello','world')" >测试函数调用</button>
如何通过接口的DispID 获取方法名?
最近研究了Delphi RTTI
想要实现一个类似TAutoObject功能的类
经过以下试验分析
Delphi 的双重接口的调用模式大致如下
Delphi(Pascal) code //接口
ITest = interface(IDispatch)
['{C8E5E6FF-FBF2-4397-A4F3-8041DF9548E8}']
function Test: Boolean; stdcall;
end;
{$m-}{$METHODINFO OFF}
//disp接口
ITestDisp = dispinterface
['{C8E5E6FF-FBF2-4397-A4F3-8041DF9548E8}']
function Test: Boolean; dispid 500;
end;
TTest = class(TInterfacedObject, ITest, IDispatch)
protected
function Test: Boolean; stdcall;
function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
end;
//以下是调用
var
I: ITest;
Disp: ITestDisp;
V: Variant;
begin
//用非disp接口调用, 直接执行到 Test 方法内部
I := TTestCreate;
ITest;
//用dips接口调用,执行到Invoke,再由 Invoke 执行其它方法
Disp := TTestCreate as ITestDisp;
DispTest;
//用Variant调用,首先执行到 GetIDsOfNames 获取方法ID,然后再执行到 Invoke 再由 Invoke 执行其它方法
V := TTestCreate as ITestDisp;
VTest;
end;
我想要的效果正是类似DispID的效果, 既只要有接口就可以调用, 避免传错参数或调错方法,
然而我发现当执行到 Invoke 时传来的只是方法的DispID
于是我无从下手了,不知道该如何把DispID解释成方法名或方法地址,于是无法进行调用实际想调用的方法
跟据我的实验,用Variant的方式,只要在其调用GetIDsOfNames时生成一个模拟的DispID,
这个DispID便可以由Invoke获取了,然而这个DispID却不是接口声明时的DispID,于是
用disp接口仍然无法获取方法地址
我跟踪过TAutoObject的调用,他的调用是通过工厂类直接执行,然而一直跟踪下去才发现他是调用了Ole32 API,而这个API
是需要IDL Table支持的,即一定要是COM或COM+才能获取到。
用Variant调用的方式确实能满足我的需要,但其不能直接使用接口调用,传错参数也能编译通过,并且效比较低,
首先要执行 GetIDsOfNames获取方法ID,再进行调用。
经过跟踪调试发现,只要引用了ComObj单元,Disp接口调用时,都会调用到ComObj的DispCallByIDProc函数指针,该指针指向
DispCallByID 函数,通过修改这个函数的指针,指向自己的DispCallByID,由DispCallByID转向Invoke以外的另一个方法把
方法名传过去,也能达到我想要的效果,但是这样做是修改了Delphi内部的调用机制,比起
这种方法,我更倾向于使用原有的机制,如果通过通过DispID获取到方法地址那才是最佳解决案。
一、从注解中获取
使用注解方式,我们需要自定义一个注解,在注解中指定参数名,然后通过反射机制,获取方法参数上的注解,从而获取到相应的注解信息。这里自定义的注解是Param,通过value参数指定参数名,定义了一个工具类ParameterNameUtils来获取指定方法的参数名列表,这里获取测试类ParameterNameTest中定义的方法method1的参数名列表表,下面是具体的代码。
以上就是关于java 在字符串中截取方法名全部的内容,包括:java 在字符串中截取方法名、java怎么获取src目录下所有的包名,类名,方法名 以及通过一个类名获得该类下的所有方法名、如何通过一个js方法的方法名,获取到这个js方法定义的代码(方法体)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)