1.1 面向对象的特征(了解)

1.9 什么是单例模式?有几种?(必会)

第一种(懒汉,线程不安全)这种写法 lazy loading 很明显,但是致命的是在多线程不能正常工作。
第二种(懒汉,线程安全)
这种写法能够在多线程中很好的工作,而且看起来它也具备很好的 lazy
loading,但是,遗憾的是,效率很低,99%情况下不需要同步。
第三种(饿汉)
这种方式基于 classloder 机制避免了多线程的同步问题,不过,instance 在
类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都
是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方
法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效
果。
第四种(饿汉,变种)
表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。
第五种(静态内部类)
这种方式同样利用了 classloder 的机制来保证初始化 instance 时只有一个线
程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方
式是只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到
lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定
被初始化。因为 SingletonHolder 类没有被主动使用,只有显示通过调用
getInstance 方法时,才会显示装载 SingletonHolder 类,从而实例化
instance。想象一下,如果实例化 instance 很消耗资源,我想让他延迟加载,
另外一方面,我不希望在 Singleton 类加载时就实例化,因为我不能确保
Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例
化 instance 显然是不合适的。这个时候,这种方式相比第三和第四种方式就显
得很合理。
第六种(枚举):
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线
程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒
不过,个人认为由于 1.5 中才加入 enum 特性,用这种方式写不免让人感觉
生疏,在实际工作中,我也很少看见有人这么写过。
第七种(双重校验锁)
从加载时机区分 饿汉就是类一旦加载,就把单例初始化完成,保证 getInstance 的时候,单例
是已经存在的了。 而懒汉比较懒,只有当调用 getInstance 的时候,才回去初始化这个单例。
从线程是否安全区分
饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,
懒汉式本身是非线程安全的,为实现线程安全需要改变几种写法。
从资源和性能
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个
单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因
为其资源已经初始化完成,而懒汉式顾名思义,会延迟加载,在第一次使用该
单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作
比较多,性能上会有些延迟,之后就和饿汉式一样了。

6.8面向对象的特征有哪些方面?

1)继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继 承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的
重要手段。
2) 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象
的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我 们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程
接口。
3) 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调
用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外
界提供的服务,那么运行时的多态性可以解释为:当 A 系统访问 B 系统提供的服务时,B 系统有多种提供服务的方式, 但一切对 A 系统来说都是透明的。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写
(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做
两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对 象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
4)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对 象有哪些属性和行为,并不关注这些行为的细节是什么

6.9重载和重写的区别?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态
性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为
重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方
法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。
方法重载的规则:
1.方法名一致,参数列表中参数的顺序,类型,个数不同。
2.重载与方法的返回值无关,存在于父类和子类,同类中。
3.可以抛出不同的异常,可以有不同修饰符。
方法重写的规则:
1.参数列表必须完全与被重写方法的一致,返回类型必须完全与被重写方法的返回类型一致。
2.构造方法不能被重写,声明为 final 的方法不能被重写,声明为 static 的方法不能被重写,但是能够被再次 声明。
3.访问权限不能比父类中被重写的方法的访问权限更低。
4.重写的方法能够抛出任何非强制异常(UncheckedException,也叫非运行时异常),无论被重写的方法是
否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则 可以。

6.10instanceof关键字的作用