八、请写出两种单例模式
单例模式是一种常见的设计模式,在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。正是由于这个特点,单例对象通常作为程序中的存放配置信息的载体,因为它能保证其他对象读到一致的信息。这种方式只需访问该单例对象即可达到统一,但是在多线程环境下,随着应用场景的不同,也可能带来一些同步问题。
应用场景:窗口管理系统、打印缓冲池、文件系统它们都是单例原型的例子。
饿汉模式:
/**
* 演示单例模式之饿汉模式
* @author Administrator
*
*/
public class EagerSingleton
{
// 在定义的时候就初始化instance,
private static EagerSingleton instance=new EagerSingleton();
// 构造函数必须是私有的,不能被外部直接调用。
private EagerSingleton()
{
}
// 暴露给外部,提供实例。
public static EagerSingleton getSingleInstance()
{
return instance;
}
}
在加载类的时候就实例化了对象,如果对象比较大,直接加载到内存中,比较浪费资源。针对这种改进,使用了一个新的设计方法——延迟加载(Lazy-load Singleton)。
懒汉模式:
/**
* 演示单例模式之懒汉模式
* @author Administrator
*
*/
public class LazySingleton {
private static LazySingleton instance = null;
// 构造函数必须是私有的,不能被外部直接调用。
private LazySingleton()
{
}
// 暴露给外部,提供实例。
public static LazySingleton getSingleInstance()
{
if (instance == null)
{
instance = new LazySingleton();
}
return instance;
}
}
这种写法就是所谓的懒汉模式。它使用了延迟加载来保证对象在没有使用之前,是不会进行初始化的。
但是,通常这个时候面试官又会提问新的问题来刁难一下。他会问:这种写法线程安全吗?回答必然是:不安全。
比如两个线程同时进入getInstance()发现instance为空,那么它们都会去执行new Singleton(),
从而导致实例不止一个。
怎么解决呢,很简单,在那个方法前面加一个同步锁Synchronized就OK了
同步的代价必然会一定程度的使程序的并发度降低,我们观察到,线程不安全的原因其实是在初始化对象的时候,所以,可以想办法把同步的粒度降低,只在初始化对象的时候进行同步。所以衍生出一个新的设计思想——双重检查锁(Double-Checked Lock)。
双重锁定:
/**
* 演示单例模式之双重锁定
* @author Administrator
*
*/
public class DoubleCheckedSingleton {
private static DoubleCheckedSingleton instance;
private DoubleCheckedSingleton()
{
}
public static synchronized DoubleCheckedSingleton getSingleInstance()
{
//性能改进——双重锁定: Double-Check Locking
if(instance==null) // 1. 先判断
{
synchronized (DoubleCheckedSingleton.class) // 2. 再同步
{
if (instance == null) //3. 再判断
{
instance = new DoubleCheckedSingleton(); //4. 实例化
}
}
}
return instance;
}
}
问题在哪里?假设线程A执行到调用上述getSingleInstance()方法,它判断对象为空,于是线程A执行下面初始化这个对象,但初始化是需要耗费时间的,但是这个对象的地址其实已经存在了。此时如果线程B也执行调用上述getSingleInstance()方法,它判断不为空,于是直接跳到最后,返回得到了这个对象。但是,这个对象还没有被完整的初始化!得到一个没有彻底初始化完全的对象有什么用!!
关于这个Double-Checked Lock的讨论有很多,目前公认这是一个Anti-Pattern(即:反面模式),不推荐使用!
这里又要提出一种新的模式——Initialization on Demand Holder. 这种方法使用内部类来做到延迟加载对象,在初始化这个内部类的时候,JLS(Java Language Sepcification)会保证这个类的线程安全。这种写法最大的巧妙在于,完全使用了Java虚拟机的机制进行同步保证,没有一个同步的关键字。其原理是利用类初始化时会加上初始化锁确保类对象的唯一性。
完美实现:
/**
* 演示单例模式之完美实现
* @author Administrator
*
*/
public class Singleton
{
private static class SingletonHolder
{
public final static Singleton instance = new Singleton();
}
public static Singleton getInstance()
{
return SingletonHolder.instance;
}
}
枚举单例:
在枚举中构造方法限制为私有,在访问枚举实例时会执行构造方法,同时每个枚举实例都是 static final 类型的,也就表明只能被实例化一次。在调用构造方法时,单例被实例化。也就是说,因为 enum 中的实例被保证只能被实例化一次,所以 instance 也保证只被实例化一次。
class Resource{
}
public enum SingleTon{
INSTANCE;
private Resource instance();
SingleTon(){
instance = new Resource();
}
public Resource getInstance(){
return instance;
}
}
九、listview如何优化(这个很重要,多次被问到)
1.分页加载
2.convertView缓存
3.viewHolder
4.scrollListener,记住滑动的状态
5.setTag,getTag防止乱序
十、Activity和Fragment的生命周期
Activity:
onCreate---->onStart—>onResume—>onPause–>onStop—>onDestroy
Fragment:
onAttach–>onCreate—>onCreateView—>onActivityCreated—>
onStart—>onResume—>onPause—>onDestroyView—>onDestroy—>onDetach
最好是画成流程图。
十一、Android的数据存储有哪些方式,优缺点?
1.SharePreference
2.SQLite
3.ContentProvider
4.文件存储
5.网络存储