2004年十一月月 发布的文章

Effective Java阅读笔记-item24、25、34

Dreamhead把他用大把银子买来的“Effective Java”借给我阅读,我真是很感动亚,我只能用行动来感谢Dreamhead了。^_^

24、需要时使用保护性拷贝
在学习这个item之前我们看看下面这段“危险的”代码(改编自书中例子):

Considering the following code:
//Period.java
import java.util.Date;
public final class Period {
    private final Date start;
    private final Date end;
    public Period(Date start , Date end){
        //do some checking , end should be later than start
        this.start = start;
        this.end   = end;
    }
    public Date start(){
        return this.start;
    }
    public Date end(){
        return this.end;
    }
    //remainder omitted…
    public static void main(String[] args) {
        Date start = new Date(2004 , 11 , 28);
        Date end   = new Date(2004 , 11 , 30);
        Period p = new Period(start , end);
        
        System.out.println("Normal period:");
        System.out.println(p.start());
        System.out.println(p.end());

        //danger code part1
        System.out.println("Unnormal period part1:");
        end.setMonth(4);
        System.out.println(p.start());
        System.out.println(p.end());

        //danger code part2
        System.out.println("Unnormal period part2:");
        p.end().setMonth(5);
        System.out.println(p.start());
        System.out.println(p.end());
    }
}

//output:
Normal period:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904
Unnormal period part1:
Wed Dec 28 00:00:00 CST 3904
Mon May 30 00:00:00 CST 3904
Unnormal period part2:
Wed Dec 28 00:00:00 CST 3904
Thu Jun 30 00:00:00 CST 3904

Period类声称提供一段不可改变的时间段,不过从上面的输出结果来看我们可以轻易的修改这个时间段。为了使上面的Period类真正成为非可变类,我们需要进行“defensive copy”。

Danger code part1提示我们“对构造函数的每个可变参数进行保护性拷贝”;
Danger code part2提示我们“对类中public方法返回的可变内部域进行保护性拷贝”;

修改如下:
public Period(Date start , Date end){
        //do some checking , end should be later than start
        this.start =new Date( start.getTime());
        this.end = new Date(end.getTime());
}
public Date start(){
    return (Date)this.start.clone();
}
public Date end(){
    return (Date)this.end.clone();
}
修改后再运行,结果如下:
Output:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904
Unnormal period part1:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904
Unnormal period part2:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904

切记:在把类的内部组件的引用返回给客户之前,你应该返回一个保护性拷贝,如内部数组。

还有一点就是如果有可能你尽量使用immutable object作为你的内部组件,这样你就可以不必关心“defensive copy”的问题了。

25、小心设计方法的原型
在这个item中记住几个原则即可(这几个原则对我这个菜鸟来说用处还是蛮大的):
- 小心选择方法名字(可参考那本java developers almanac的索引来看看java中方法都是如何命名的)
- 对于参数类型,优先选用接口而不是类
- 小心使用function object , 原因不是主流的代码风格,难于理解。

34、通过接口引用对象
Item25中提到了“对于参数类型,优先选用接口”,更一般的讲我们应该用接口来引用对象。
书中的例子:
List subscribers = new Vector(); //good – use interface as type!
Vector subscribers = new Vector(); //bad-use class as type!

如果没有合适的接口,使用类来引用对象也是完全适合的。
其中有一种情况是当我们没有合适的接口时,我们尽量使用基类(往往是abstract class)来引用实现类(子类)的对象。

Effective Java阅读笔记-item18

Dreamhead把他用大把银子买来的“Effective Java”借给我阅读,我真是很感动亚,我只能用行动来感谢Dreamhead了。^_^

18、优先考虑静态成员类(static member class)
在C++的应用中我们很少使用嵌套类,我只在MFC和COM组件中遇到过这些,而且这些嵌套类被隐藏在应用背后,一般的应用中则很少使用。而在Java中嵌套类的应用还是要比在C++中多些。Java中嵌套类主要之功用就是辅助其outer class,为outer class提供服务。

嵌套类分类:
- static member class:
- nonstatic member class:
- anonymous class:
- local class

按照书中的方式我们根据各种类型嵌套类的用途来说:
* static member class
基本格式:
public class OuterClass{
    publc/private static class InnerClass{
        //…
    }
}

对于static型的member class:
多个outer class instance共享一个static member class,就是说static member class和outer类的一般静态成员地位是一样的, static member class可以访问outer class的所有成员,包括private的成员。

书中的例子:(两层嵌套,既使用了static member class又使用了anonymous classes)
//Calculator.java
public class Calculator {
   public static abstract class Operation {
      private final String name;
      Operation(String name)   { this.name = name; }
      public String toString() { return this.name; }
      // Perform arithmetic op represented by this constant
      abstract double eval(double x, double y);      
      // Doubly nested anonymous classes
      public static final Operation PLUS = new Operation("+") {
         double eval(double x, double y) { return x + y; }
      };      
   }
   // Return the results of the specified calculation
   public double calculate(double x, Operation op, double y) {
      return op.eval(x, y);
   }
}
//CalcTest.java
public class CalcTest {
    public static void main(String args[]) {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        operate(x, Calculator.Operation.PLUS, y);
    }
    static void operate(double x, Calculator.Operation op, double y) {
        Calculator c = new Calculator();
        System.out.println(x + " " + op + " " + y + " = " +
                           c.calculate(x, op, y));
    }
}
//command: java CalcTest 3 4
//output: 3.0 + 4.0 = 7.0

* nonstatic member class
基本格式:
public class OuterClass{
    publc/private class InnerClass{
        //…
    }
}

对于non-static型的member class:

每个outer class instance都要维护一个member class的实例,且这种关系在outer class被实例化后就不变了。nonstatic member class的实例是在其outer class实例化时才有意义的。

所以当嵌套类的实例可以不依赖于其outer class的实例而存在时。我们应该使用static member class。
nonstatic member classes 常被用來定义 Adapter ,允许我们将outer class的实例视为某些不相关的类的实例。
例如:像Set和List这样的集合接口的实现往往利用nonstatic member class来实现iterator

书中例子:
public MySet extends AbstractSet{
    //…
    private class MyIterator implements Iterator{//inner class or nested class
    
    }
    public Iterator iterator(){
        return new MyIterator();
    }
}

* anonymous classes(匿名类)

匿名类不是outer class的一个成员,它在使用处被同时声明和实例化。匿名类通常只是实现了其接口或超类中的方法。它们不会声明新方法。

匿名类的用途很广泛。
- 用来创建一个function object
如代码:
Collections.sort(list, new Comparator() {
    public int compare(Object o1, Object o2) {
      return ((String)o1).length() – ((String)o2).length();
    }
  }
);
像这样的匿名类可读性差,建议不要把匿名类写的很长。
这里我们假设匿名类的名字为$,这实际上的代码可能是像这样的:
class $ implements Comparator{
    public int compare(…){
        //implement the compare method
}
}
Collections.sort(list, new $());

- 创建process object,例如 Thread、Runnable 实例
- 给 static factory 方法使用,可以在 static factory method 返回一份 anonymous 的实例

* local class(局部类)
使用local class把握一个原则:local class与局部变量的使用(包括声明和scope)几乎一模一样。

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats