每天一个 Linux 命令 less 命令
less 命令 的作用与 more 十分相似,都可以用来浏览文字档案的内容,不同的是 less 命令允许用户向前或向后浏览文件,而 more 命令只能向前浏览。用 less 命令显示文件时,用 PageUp 键向上翻页,用 PageDown 键向下翻页。要退出 less 程序,应按 Q 键.
1 2 3 4 5 6 7 8 -e: 文件内容显示完毕后, 自动退出; -f: 强制显示文件; -g: 不加亮显示搜索到的所有关键词, 仅显示当前显示的关键字, 以提高显示速度; -l: 搜索时忽略大小写的差异; -N: 每一行行首显示行号; -s: 将连续多个空行压缩成一行显示; -S: 在单行显示较长的内容, 而不换行显示; -x< 数字 >: 将 TAB 字符显示为指定个数的空格字符.
抽象工厂模式练习 Sunny 软件公司欲推出一款新的手机游戏软件,该软件能够支持 Symbian、Android 和 Windows Mobile 等多个智能手机操作系统平台,针对不同的手机操作系统, 该游戏软件提供了不同的游戏操作控制 (OperationController) 类和游戏界面控制 (InterfaceController) 类,并提供相应的工厂类来封装这些类的初始化过程. 软件要求具有较好的扩展性以支持新的操作系统平台,为了满足上述需求,试采用抽象工厂模式对其进行设计.
UML
代码 抽象工厂
1 2 3 4 public interface GameFactory { OperationController createOperationController () ; InterfaceController createInterfaceController () ; }
具体工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class SymbianGameFactory implements GameFactory { @Override public OperationController createOperationController () { return new SymbianOperationController (); } @Override public InterfaceController createInterfaceController () { return new SymbianInterfaceController (); } } public class AndroidGameFactory implements GameFactory { @Override public OperationController createOperationController () { return new AndroidOperationController (); } @Override public InterfaceController createInterfaceController () { return new AndroidInterfaceController (); } } public class WMGameFactory implements GameFactory { @Override public OperationController createOperationController () { return new WMOperationController (); } @Override public InterfaceController createInterfaceController () { return new WMInterfaceController (); } }
抽象产品
1 2 3 4 5 6 public interface OperationController { void play () ; } public interface InterfaceController { void show () ; }
具体产品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class SymbianOperationController implements OperationController { @Override public void play () { System.out.println("Symbian 系统操作" ); } } public class SymbianInterfaceController implements InterfaceController { @Override public void show () { System.out.println("Symbian 显示" ); } } public class AndroidOperationController implements OperationController { @Override public void play () { System.out.println("Android 操作" ); } } public class AndroidInterfaceController implements InterfaceController { @Override public void show () { System.out.println("Android 显示" ); } } public class WMOperationController implements OperationController { @Override public void play () { System.out.println("WM 操作" ); } } public class WMInterfaceController implements InterfaceController { @Override public void show () { System.out.println("WM 显示" ); } }
添加配置
1 gameType=com.dong4j.homework.WMGameFactory
测试类
1 2 3 4 5 6 7 8 9 10 11 @Test public void gameTest () throws IllegalAccessException, InstantiationException, ClassNotFoundException { GameFactory gameFactory; OperationController operationController; InterfaceController interfaceController; gameFactory = (GameFactory) ConfigUtil.getType("gameType" ); operationController = gameFactory.createOperationController(); interfaceController = gameFactory.createInterfaceController(); operationController.play(); interfaceController.show(); }
创建者模式之三:单例模式 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法
单例模式的几种实现 饿汉模式 1 2 3 4 5 6 7 8 9 public class EagerSingleton { private static final EagerSingleton instance = new EagerSingleton (); private EagerSingleton () {} public static EagerSingleton getINstance () { return instance; } }
懒汉模式 1 2 3 4 5 6 7 public class LazySingleton { private static LazySingleton instance = null ; private LazySingleton () {} public static LazySingleton getInstance () { return new LazySingleton (); } }
多线程优化 1 2 3 4 5 6 7 8 9 10 11 12 public class SynchronizedLazySingleton { private static SynchronizedLazySingleton instance = null ; private SynchronizedLazySingleton () {} public static SynchronizedLazySingleton getInstance () { if (instance == null ){ synchronized (SynchronizedLazySingleton.class){ instance = new SynchronizedLazySingleton (); } } return instance; } }
存在的问题: 当 A, B 2 个线程调用 getInstance () 时,进入 if 判断,如果此时为 null, 怎么排队进入创建对象的同步块, 当 A 创建完并返回了一个单例对象时,线程 B 进入同步块,再次创建一个新的对象.
双锁机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class DoubleSynchronizedLazySingleton { private volatile static DoubleSynchronizedLazySingleton instance = null ; private DoubleSynchronizedLazySingleton () {} public static DoubleSynchronizedLazySingleton getInstance () { if (instance == null ){ synchronized (DoubleSynchronizedLazySingleton.class){ if (instance == null ){ instance = new DoubleSynchronizedLazySingleton (); } } } return instance; } }
instance 必须用 volatile 修饰,volatile 在这里的作用是禁止重排序
静态内部类 单例 1 2 3 4 5 6 7 8 9 10 11 12 public class SynchronizedLazySingleton { private static SynchronizedLazySingleton instance = null ; private SynchronizedLazySingleton () {} public static SynchronizedLazySingleton getInstance () { if (instance == null ){ synchronized (SynchronizedLazySingleton.class){ instance = new SynchronizedLazySingleton (); } } return instance; } }
使用 classload 机制来保证初始化 instance 时只有一个线程,只有在显示调用 getInstance () 时才会创建单例对象
枚举 单例 1 2 3 public enum EnumSingleton { INSTANCE; }
使用 EnumSingleton.INSTANCE 来访问
防止单例模式被 反射,反序列化,克隆破坏 反射破坏单例模式 防止反射实例化对象
利用反射生成对象
1 2 3 4 5 6 7 Class c = Class.forName(Singleton.class.getName());Constructor constructor = c.getDeclaredConstructor();constructor.setAccessible(true ); Singleton singleton = (Singleton)ct.newInstance();
解决方法
在私有构造中抛出异常
1 2 3 4 5 6 7 8 9 public class LazySingleton { private static LazySingleton instance = null ; private LazySingleton () throws Exception { throw new Exception (); } public static LazySingleton getInstance () throws Exception { return new LazySingleton (); } }
反序列化破坏单例模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.io.Serializable;public class Singleton implements Serializable { private volatile static Singleton singleton; private Singleton () {} public static Singleton getSingleton () { if (singleton == null ) { synchronized (Singleton.class) { if (singleton == null ) { singleton = new Singleton (); } } } return singleton; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class SerializableDemo1 { public static void main (String[] args) throws IOException, ClassNotFoundException { ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("tempFile" )); oos.writeObject(Singleton.getSingleton()); File file = new File ("tempFile" ); ObjectInputStream ois = new ObjectInputStream (new FileInputStream (file)); Singleton newInstance = (Singleton) ois.readObject(); System.out.println(newInstance == Singleton.getSingleton()); } }
防止序列化反序列化破坏单例的方法:
添加 readResolve 方法
1 2 3 private Object readResolve () { return singleton; }
克隆破坏单例模式 由克隆我们可以想到原型模式,原型模式就是通过 clone 方法实现对象的创建的,clone 方式是 Object 方法,每个对象都有,那我使用一个单例模式类的对象, 调用 clone 方法,再创建一个新的对象了,那岂不是上面说的单例模式失效了。当然答案是否定,某一个对象直接调用 clone 方法,会抛出异常, 即并不能成功克隆一个对象。调用该方法时,必须实现一个 Cloneable 接口。这也就是原型模式的实现方式。还有即如果该类实现了 cloneable 接口, 尽管构造函数是私有的,他也可以创建一个对象。即 clone 方法是不会调用构造函数的,他是直接从内存中 copy 内存区域的. 所以单例模式的类是不可以实现 cloneable 接口的 .
利用枚举防止破坏 1 2 3 4 5 6 public enum EasySingleton { INSTANCE; }
使用反射破解枚举单例: 运行结果是抛出异常:Exception in thread “main” java.lang.NoSuchMethodException: cn.xing.test.Weekday.() 明明 Weekday 有一个无参的构造函数,为何不能通过暴力反射访问? 最新的 Java Language Specification (§8.9) 规定: Reflective instantiation of enum types is prohibited. 这是 java 语言的内置规范.
使用 clone 破解枚举单例 所有的枚举类都继承自 java.lang.Enum 类,而不是 Object 类。在 java.lang.Enum 类中 clone 方法如下:
1 2 3 protected final Object clone () throws CloneNotSupportedException { throw new CloneNotSupportedException (); }
调用该方法将抛出异常,且 final 意味着子类不能重写 clone 方法,所以通过 clone 方法获取新的对象是不可取的.
使用序列化破解枚举单例 java.lang.Enum 类的 readObject 方法如下:
1 2 3 4 5 6 7 private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException ("can't deserialize enum" ); } private void readObjectNoData () throws ObjectStreamException { throw new InvalidObjectException ("can't deserialize enum" ); }
同暴力反射一样,Java Language Specification (§8.9) 有着这样的规定: the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization.
引用