简答
虽然从理论的角度来看也许是可能的,不;不是在编译时,这些会再次编译。
但是Pattern 使用 享元 模式,这样一旦正则表达式被编译,它就会存储在内存中,因此不需要在运行时完全编译。
编译时间
从理论上讲,编译器可能会执行所谓的constant propagation,从而在编译时解决问题。这可以在您调用的方法是最终的(或者被调用者在编译时已知)等情况下完成。
如果有人编译您的方法并检查 Java 字节码,它会编译为:
public static boolean checkRegex(java.lang.String, java.lang.String);
Code:
0: aload_1
1: ifnonnull 6
4: iconst_0
5: ireturn
6: aload_0
7: invokestatic #15 // Method java/util/regex/Pattern.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;
10: astore_2
11: aload_2
12: aload_1
13: invokevirtual #16 // Method java/util/regex/Pattern.matcher:(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;
16: astore_3
17: aload_3
18: invokevirtual #17 // Method java/util/regex/Matcher.matches:()Z
21: ireturn
public static void main(java.lang.String[]);
Code:
0: ldc #18 // String ^.+@.+\..+$
2: ldc #19 // String email@example.com
4: invokestatic #20 // Method checkRegex:(Ljava/lang/String;Ljava/lang/String;)Z
7: pop
...
如您所见,这些方法被简单地转换为 Java 字节码,并使用两个参数调用该方法。
一些编译器(主要是用于函数式和逻辑编程语言的编译器)允许程序特化:如果某个调用是使用常量完成的,编译器可以创建该方法的副本并解析已知的内容在编译时。然而,这是一个权衡,因为引入大量专门的方法会减少大型代码库。
享元运行时模式
如果你深入研究java.util.regex.Pattern的Java字节码,你会看到:
private static final HashMap<String, CharPropertyFactory> map;
static CharProperty charPropertyFor(String name) {
// <editor-fold defaultstate="collapsed" desc="Compiled Code">
/* 0: getstatic java/util/regex/Pattern$CharPropertyNames.map:Ljava/util/HashMap;
* 3: aload_0
* 4: invokevirtual java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
* 7: checkcast java/util/regex/Pattern$CharPropertyNames$CharPropertyFactory
* 10: astore_1
* 11: aload_1
* 12: ifnonnull 19
* 15: aconst_null
* 16: goto 23
* 19: aload_1
* 20: invokevirtual java/util/regex/Pattern$CharPropertyNames$CharPropertyFactory.make:()Ljava/util/regex/Pattern$CharProperty;
* 23: areturn
* */
// </editor-fold>
}
注意HashMap,所以这意味着Pattern 存储正则表达式的片段及其对应的微DFA,这种行为称为Flyweight。这意味着您只需编译一次正则表达式。显然您仍然需要执行查找,所以这不是免费优化,但它肯定会有所帮助。