Java核心技术卷II(第8版) – 读书笔记 – 第11章

1、Java已经逐渐支持在源代码中内嵌调用其他脚本语言,如Javascript / Groovy等。此外,也支持源代码注解,以上这些都是通过编译器API完成的。

2、要内嵌脚本,首先要获取脚本引擎:

// Make manager first
ScriptEngineManager manager = new ScriptEngineManager();
// name could be js/groovy/schema ...
ScriptEngine engine = manager.getEngineByName("js");

也可以查看当前支持的引擎:

// Print all engine
for (ScriptEngineFactory factory : manager.getEngineFactories()){
    System.out.println(factory.getEngineName());
}

在我的机器上是只支持Mozilla Rhino。

如果要支持其他引擎,比如Groovy,需要去网站上下载groovy-engine.jar。

3、有了脚本后,我们就可以在Java中“执行”对应的Javascript脚本了:

try {
	engine.eval("n = 100");
	Object result = engine.eval("n * 10");
	System.out.println(result);
} catch (ScriptException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

上述eval的参数,也可以是Reader(此时的脚本语句在文件中。)

4、如果想知道当前的引擎是否是线程安全的,如下:

engine.getFactory().getParameter("THREADING");

返回null表示不是,MULTITHREAD是。

5、可以用Java的对象可以和脚本中的对象“交互”:

int k = 8888;
engine.put("m", k);
Object result = engine.eval("m");
System.out.println(result);  // 8888

6、脚本引擎ScriptEngine可以重定向输出:

engine.getContext().setWriter(new PrintWriter());

7、如果脚本引擎支持,还可以通过Invocable接口直接调用脚本的函数

((Invocable)engine).invokeFunction("aFunction", param1, param2);

8、如果引擎支持编译,还可以把js等脚本先预先编译,以提高执行效率:

Reader reader = new FileReader("xx.js");
CompiledScript script = ((Compilable)engine).compile(reader);

9、我们可以用API调用Java的编译器,用途很广泛,如:

开发环境、Java教学环境、Java模板工具(JSP)。

10、JDK6之前,Java编译器是放在jdk/lib/tools.jar中的,JDK6之后,已经称为Java公共API的一部分了,它在javax.tools.Tool.run中,调用方法也比较简单:

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, "/tmp/TestCollator.java");
if (result == 0) {
    System.out.println("Compile Success.");
}

被设置为null省略的参数分别是in/out/err stream,如果都null就是默认的stdin/out/err。

返回0表示编译成功!

11、除了上面的方法,也可以更精细的方式控制编译。对于存放在磁盘上的Java源代码,可以借助JavaFileManager/JavaFileObject来实现。

StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);
Iterable<JavaFileObject> fobjs =   fm.getJavaFileObjects(java_file1, java_file2...);

然后把上述JavaFileObjects传入另一个函数:

JavaCompiler.CompilationTask	getTask(Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits)

拿到task后必须在call()一次才算执行完毕。

13、借助Java内置的编译工具,完全可以实现内存动态加载源代码、编译(见书上例子)。

14、下面讨论注解

注解:插入到源代码中用于某种工具处理的标签。

元注解:对注解进行约束的注解。

注解的例子:

	@Test
	public void testXX() {
		System.out.println("xxx");
		Assert.assertEquals(true, false);
	}

15、定义注解:

public @interface BugReport {
    String msg() default "[none]";
        int serverity() default 0;
    }

使用注解:

@BugReport(serverity = 10)
public static void main(String[] args) throws Exception {

}

如果注解只有一个值,可以直接命名为value,如:

public @interface ZJ2 {
    String value() default "[none]";
}

可以直接写注解,不用写key:

@ZJ2("10")
public static void main(String[] args) throws Exception {

}

16、所有注解都隐式拓展自java.lang.annotation.Annotation接口。注解是编译时计算出来的,所以所有注解值必须是常量!

17、如果注解某个值是数组,需要用话括号包起来:

@BugReport(..., reportBy={"a", "n"})

18、注解可以作用于:包、类、接口、方法、构造器、实例成员、本地变量、参数变量。

19、一个上述被作用项可以有多个不同类型注解,但不能有两个以上同一类型的注解。

20、Java内置了一些注解和元注解,它们在java.lang. / java.lang.annotation / javax.annotation包中。常用的注解如下:

(1) Deprecated 标记为过时
(2) SuppressWarnings 阻止警告信息。
(3) Override 覆盖了超类方法
(4) Resource 用于资源注入,如数据库链接信息:

@Resource(name="jdbc/mydb")
private DataSource source;

(5) Generated 供代码生成工具使用,

元注解:
(1) Target,限制注解可以应用到那些项上。

例如,限制只能用在类、接口和方法上:

@Target(ElementType.TYPE, ElementType.METHOD)
public @interface BugReport

更多的限制常量见java.lang.annotation.Target
(2) Retention限制一条注解可以保存多久。

21、注解的用处之一就是自动生成包含程序额外信息的“附文件”。

22、上面在源代码、编译期间、运行期间对注解进行了处理。其实还可以在字节码级别上处理。因为类格式是标准的,我们可以用BCEL,即字节码工程库来处理。可以在Apache项目网站上下载到。

看一下官方说明:

The Byte Code Engineering Library (Apache Commons BCEL™) is intended to give users a convenient way to analyze, create, and manipulate (binary) Java class files (those ending with .class). Classes are represented by objects which contain all the symbolic information of the given class: methods, fields and byte code instructions, in particular.

Such objects can be read from an existing file, be transformed by a program (e.g. a class loader at run-time) and written to a file again. An even more interesting application is the creation of classes from scratch at run-time. The Byte Code Engineering Library (BCEL) may be also useful if you want to learn about the Java Virtual Machine (JVM) and the format of Java .class files.

BCEL contains a byte code verifier named JustIce, which usually gives you much better information about what's wrong with your code than the standard JVM message.

BCEL is already being used successfully in several projects such as compilers, optimizers, obsfuscators, code generators and analysis tools. Unfortunately there hasn't been much development going on over the past few years. Feel free to help out or you might want to have a look into the ASM project at objectweb.

具体的用的时候再看吧,本章结束。

 

Leave a Reply

Your email address will not be published. Required fields are marked *