import java.util.Arrays; import java.util.Collections; import java.util.List; public class Test { public static void main(String[] args) { for (int i = 0; i < foo.VALUES.length; i++) { foo.VALUES[i] = new Integer(0); } for (int i = 0; i < foo.VALUES.length; i++) { System.out.println(foo.VALUES[i]); } } } class foo { public static final Integer[] VALUES = { new Integer(0), new Integer(1), new Integer(2), new Integer(3) }; }
虽然VALUES被定义成final,可是用户在外部仍是能修改数组中的值,这是很不安全的。 java
以下代码是推荐作法,公有数组应该被替换为一个私有数组,以及一个公有的非可变列表。 程序员
private static final Integer[] PRIVATE_VALUES = {new Integer(0),new Integer(1), new Integer(2),new Integer(3)}; public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
也能够把公有数组替换成一个公有方法,它返回私有数组的一份拷贝。 数组
public static final Integer[] VALUES() { return (Integer[])PRIVATE_VALUES.clone(); }
非可变类建立和使用都比较简单,它也是线程安全的。但它有个缺点须要注意:对于每个不一样的值都要求一个单独的对象。这点很重要,关乎程序的执行效率。好比经过大量的String去生成另外一个String是不太划算的,由于除了最后的结果,中间的其余对象都会被丢弃,因此应该考虑用字符串变量StringBuffer。 安全
让一个非可变类不能被继承有三种方法: 函数
为何非可变类要设计成不能继承了,能够看一下这个讨论:http://stackoverflow.com/questions/2068804/why-is-string-final-in-java 工具
个人理解是,若是非可变类A支持继承,那么子类可能实现为可变类B,会增长使用上的复杂性。 this
好比有个拷贝函数形参是非可变类A,但我不知道传入的是A仍是B,咱们还要经过判断才能决定采用浅拷贝仍是深拷贝。 spa
想一想以下的程序输出是6,而不是3,为何? 线程
import java.util.Arrays; import java.util.Collection; import java.util.HashSet; public class Test { public static void main(String[] args) { MyHashSet mhs = new MyHashSet(); mhs.addAll(Arrays.asList(new String[] { "a", "b", "c" })); System.out.println(mhs.getSum()); } } class MyHashSet extends HashSet { private int sum = 0; public boolean add(Object arg0) { sum++; return super.add(arg0); } public boolean addAll(Collection arg0) { sum += arg0.size(); return super.addAll(arg0); } public int getSum() { return sum; } }
由于HashSet的addAll会调用add实现,因此在addAll中,sum加了3,而且有调用了add三次。 设计
从这个例子能够看出,继承时,子类的行为还要受超类的实现的影响。当一个程序员同时维护超类和子类时,这不会有什么问题,可是实现的子类依赖第三方发布包的时候呢?
实现超类时,构造函数中若是有调用其余方法,那么这些方法建议声明成final,防止子类改写。
接口优于抽象类,接口只是被用于定义类型。
常量接口模式是对接口的不良使用,接口应该只是被用来定义类型的,它们不该该用来导出常量。若是要导出常量时,应该用一个不可实例化的工具类:
public class Constants { private Constants() { } public static final int A = 1; public static final int B = 2; public static final int C = 3; public static final int D = 4; }
嵌套类有四种:静态成员类、非静态成员类、匿名类和局部类。
以下代码展现了静态成员类和非静态成员类的使用。
若是你声明的成员类不要求访问外围实例,那么请记住把static修饰符放到成员类声明中。不然,每一个实例都将包含一个额外的指向外围对象的引用,维护这份引用一消耗时间和空间,但又没有相应的好处。
public class Test { public static void main(String args[]) { Human mike = new Human("mike"); Human.Cup mikeCup = mike.new Cup(); // 非static的成员类,实例化时要依赖于外部类的实例。 System.out.println(mikeCup.whoseCup()); Human.Car joyCar = new Human.Car("joy"); // static的成员类,实例化时不依赖于外部类的实例。 System.out.println(joyCar.whoseCar()); } } class Human { private String name; public Human(String name) { this.setName(name); } public String getName() { return name; } public void setName(String name) { this.name = name; } public class Cup { String whoseCup() { return getName(); // ok } } public static class Car { private String ownerName; Car(String name) { this.ownerName = name; } String whoseCar() { // return getName(); //error...staitc的静态类不能访问外部类的非static成员。 return this.ownerName; } } }
而局部类和匿名类是针对方法而言的,若是你只须要在一个地方建立它的实例,而且已经有了一个预先存在的类型能够说明这个类的特征,则把它作成匿名类,不然就作成局部类。
以下代码展现了匿名类的两个经常使用用法:
import java.util.Arrays; import java.util.Comparator; public class Test { public static void main(String[] args) { new Thread(new Runnable() { public void run() { int i = 0; while (true) { i++; System.out.println("thread i = " + i); if (100 == i) { break; } } } }).start(); Integer[] lst = { new Integer(5), new Integer(3), new Integer(2), new Integer(1) }; Arrays.sort(lst, new Comparator() { public int compare(Object x, Object y) { return ((Integer) x).intValue() - ((Integer) y).intValue(); } }); for (Integer i : lst) { System.out.println(i); } } }