- Jackson 是 Playfrmework 2 中默认的 JSON 处理框架,先前是 GSON,JSON 是 Playframework 中的第一等公民,可见 Jackson 在 Playframewok 中的重要地位。Jackson 提供了一系列的注解可用,像 @JsonIgnore, @JsonProperty, @JsonUnwrapped, @JsonFilter 等。人的需求总是很难得到满足,所以免不了还是要定义自己的注解。比如有这样一个需求,JavaBean 中被 @MaskField(这个即将成为我第一个自定义的注解) 标记的属性或 getter 方法,总是输出为
******, 无此标记的属性或方法输出原始值。我尝试过 @JsonFilter 或是单纯的自定义 JsonSerializer, 并不怎么如意。本人最终的实现方式涉及到- @JacksonAnnotationsInside -- 用来创建自己的 @MaskField 注解
- JsonSerializer -- 被 @MaskField 标记的字段采用自定义的 JsonSerializer 来序列化
- JacksonAnnotationIntrospector -- 禁用某一特定的注解,这样可以在做任意时候启用或禁用 @MaskField Read More
初学 Java 的人很不经意间就会把常量定义在接口中,大概唯一的理由是接口不能实例化,而使用接口中定义的常量也是不用附着在实例上的。 这主要还是 JDK 本身给我们做了很多这样的榜样, 如 java.io.ObjectStreamConstans, 多是出现在 Enum 类型到来之前。
其实 Java 的接口常量是一种反模式,理由如下:
1. 接口是不能阻止被实现或继承的, 也就是说子接口或实现中是能够覆盖掉常量的定义(重名),这样通过父,子接口(或实现) 去引用常量是可能不一致的
2. 同样的,由于被实现或继承,造成在继承树中可以用大量的接口, 类 或实例去引用 同一个常量,从而造成接口中定义的常量污染了命名空间。(Java 编译器竟然允许使用实例去引用类变量)
3. 接口暗含的意思是:它是需被实现的,代表着一种类型,它的公有成员是要被暴露的 API。而在接口中定义的常量说不上是 API4. 这点有些重复,Java 允许通过子类去引用父类中定义的常量,各级对像实例去引用父类的常量,所以这会造成相当的混乱不堪。定义的常量不能保证单一的引用方式。
参见: Effective java 第 19 条: 接口只用于定义类型
既然接口中不适于定义常量,那么该在何处为常量安家呢?接口为 实现/继承 而生,如果放在类中,并且这个类是 final,且封闭掉构造方法就行。 于是我们先前的接口常量定义 Read More
枚举的声明很简单, 像
enum Gender { Male, Female }, 其余事情就是 Java 编译器帮我们干的了,所以 enum 也就是一块语法糖。有了枚举确实是很方便,避免了传统常量的无范围性。那么编译器到底在后面做了什么呢?以及理解了这个之后我们可以怎么去使用 Java 的枚举, 下面就从这个例子说起:public enum Gender {
Male,
Female
}把上面的编译成 Gender.class, 然后用 javap -c Gender 反编译出来就是 Read More
- 使用过 Java 反射的大多都知道, 想要修改某个类或对象的私有变量的值的话, 在调用 set 设置新值之前执行一下 setAccessible(true) 即可。这样利用的 Java 的反射就能绕过 private 的限制 ,不再有 IllegalAccessException 异常了。这是一个 trick, 调用 Java 的私有方法也能这么做,有些人或许或这样来测试 Java 私有方法。
提前说一句:在修改 final 型值时,要特别留意它的常量值本身是否被编译器优化内联到某处,否则你会看到虽然没什么异常,但取出的还是原来的值。后面会稍为深入的讲到。
例如下面是一段完整的代码, 由于调用了 setAccessiable(true), 所以能成功把 OneCity 的私有属性 name 的值改为 "Shenzhen": Read More - 在 NodeJS 中进行异步操作很简单,而 Java 到了 7 开始才支持异步的 IO 操作。虽然之前的版本有引入非阻塞 IO,但编码中还不易体现出它的优越性。亮一下 NodeJS 用异步 IO 的例子:
var fs = require('fs');
fs.readFile('Test.scala', 'utf-8', function(err, data){
if( !err ) {
console.log(data);
}
});
console.log('continue doing other thins');
执行输出是
continue doing other things
CONTENT FROM FILE Test.scala
对的,理想中的异步操作就是,传递回调函数来读取文件,读取完成后招待回调,且不阻塞主线程。
在 Java 8 之前,因为没有 Lambda 支持只能应用内部类的方式。JDK 提供了以下异步 Channel 来实现异步操作
AsynchronousFileChannel Read More - 在上一篇中写道 Java 泛型 -- 依据声明的变量类型自动推断,主要是说明了通过声明类型告知泛型方法具体类型,其后有个小结三种方式告知泛型类或泛型方法具体类型,在此重列如下:
一. 具体类型写在两尖括号中
1. List<String> list
2. new HashMap<String, String>
3. instance.<String>foo() //如方法 <T> T foo() { return (T) obj; }
二. 变量声明类型指示具体类型
1. List<String> list = new ArrayList<>() // 这个例子应该可以列在这里,List<String> 指示了具体类型是 String, 所以后只需要空 <>,JDK7 or later
2. String s = obj.foo() //比如方法是 <T> T foo() { return (T) obj; }, 由于前面的 String s 声明,所以不必写成 String s = instance.<String>foo()
三. 实参类型指示具体类型
1. instance.foo(String.class) //方法为 <T> T foo(Class<T> type) { return (T) obj; }, instance.foo(String.class) 返回的就是字符串值
2. instance.foo("abc") //方法为 <T> foo(T value) { return (T) obj; }, instance.foo("abc") 返回的就是字符串值 Read More - Java 泛型在调用方法操作时应用具体参数还是很好理解的,比如
Map<String, Integer> map = new HashMap<>(); //钻石操作符是 JDK 1.7 引入的
后续的 put 操作调用的具体方法就是
Integer put(String key, Integer value)
因为 put 方法的原型是
V put(K key, V value)
上面的代码我们是看到了 <>,所以知道是泛型调用。有时候并不需要 <>,但实际上也是进行的泛型调用,那就是 Java 可以依据变量声明类型来作特化调用 -- 应用具体参数类型。
例如:
List<String> list = Collections.emptyList(); //虽不见 <>, 但同样是泛型调用,类型为 String Read More - 我们在用 Java 解析 XML,当文档不是一个合法的 XML 时,可能会收到
[Fatal Error]的控制台输出,即使把整个代码都 catch 住,仍然不能抑制住 [Fatal Error] 的信息输出。比如常见到这样的输出:[Fatal Error] :1:1: Content is not allowed in prolog.
为什么不能禁掉它呢,本来 catch 了异常对程序已经有了很好的保护,想眼不见心不烦,但还是避之不及。
因为,因为这个 XML 解析器用System.error.print()输出来了,当然你可以用 System.setErr(PrintStream) 重定向掉错误输出,但不现实,波及面太大。我们需要找到源头,首先交代解决方案就是覆盖掉默认的 ErrorHandler。
看下这段 XML 解析代码: Read More - 因为写过类似下面的一段代码来实始化一个匿名实例看上面的
1package cc.unmi; 2 3public class Test { 4 public String name; 5 6 public static Test buildTest(final String name) { 7 Test test = new Test(){{ 8 this.name = name; //希望把 buildTest() 方法参数中的 name 赋给 this.name 9 }}; 10 System.out.println(test.name); // 仍然是 null 11 return test; 12 } 13}buildTest()方法中的this.name = name希望能把方法参数 final String name 中的 name 值赋值给 this.name, 但是无效,this.name = name 是在把自己赋给自己。 Read More - 对于一个 Java 方法 foo(int id, String name); 我们如何能在代码中获得形式参数名 id 和 name 呢?
我们知道通过反射 APIMethod.getGenericParameterTypes()可以获得方法的参数类型,但是对于参数名一般就是 arg0, arg1, arg2 ..., 因为 Java 编译时把形式参数名擦除了。所以对完全擦除了形式参数名的字节码应该是没办法了,但我们自己写的类还是有能力去管控的。
对于自己写的类,有两种办法获得形式参数名,分别是
1) Java8 的 -parameters 编译参数,然后用 Java8 新引入的反射 API Parameter
我们先在 Java8 下运行下面的代码 Read More