继承 inheritance:
继承是实现类复用的重要手段,所谓复用
,就是可以多次使用,或者再次利用,不用继续重写成员变量和方法。但不代表没有缺点,最不好的地方:破坏封装。子类拓展父类时,若访问权限允许,则可直接访问父类的成员变量和方法,破坏了良好的封装性
(Encapsulation) ,造成子类与父类的耦合。
因而,设计父类时应注意以下几点:
- 尽量隐藏内部数据
- 不要让子类随意访问
- 不要在父类的构造器中调用将被子类重写的方法
组合 combination
对于继承而言,子类可以获取父类的public方法,使用子类时,可以访问子类从父类继承的方法;组合则是把旧类对象作为成员变量组合进来。我们不需要看到被组合进来的对象的方法,所以通常用private
修饰。在功能上,两者没什么区别。
class animal{
private void beat(){
System.out.println("心跳!");
}
public void breath(){
System.out.println("呼吸!");
}
}
class bird{
private animal a;
public bird(animal){
this.a = a;
}
public void breath(){
a.breath();//复用animal的方法
}
public void fly(){
System.out.println("芜湖起飞!");
}
}
注意:
使用组合关系实现复用,需要创建两个animal对象,是否意味着开销更大?
当创建一个子类对象时,系统不仅需要为该子类定义实例变量分配内存空间,而且需要为它父类所定义的实例变量分配内存。采用继承的方式,假设父类定义了两个实例的变量,子类定义了3个变量。创建子类实例时需要为子类分配5块内存空间。当采用组合设计时,先创建父类实例,此时需要分配2快内存,再创建整体类实例,也需要分配3块内存,只是多了一个引用变量来引用所组合的对象。因此,组合和继承设计开销不会有太大差别。
单例类
这种类不像其他类,某些时候允许其他类自由创建该类对象没有什么意义,所以要降低对它的访问权限,让这样的类只能创建一个实例。
方法是把该类的构造方法用private
修饰起来,但又需要创建一个对象,所以需要提供一个public方法去用于创建该类的对象,但是不是通过对象来创建对象,而是用类本身去创建,因此方法要用static
修饰。
除此之外,该类还必须缓存对象,记录已创建的对象。同时让该静态方法能访问到,保存对象的成员变量也需要static
修饰。
class person{
//静态成员变量来保存对象
private static person OnlyPerson;
//对构造器隐藏
private person(){}
//公共方法
public static person getPerson(){
if(OnlyPerson==null){
OnlyPerson = new person();
}
return OnlyPerson;
}
}
不可变类 immutable
不可变类意思是创建该类的实例后,该实例的变量不可变。Java提供的8个包装类和String类都是不可变类!
Double d = new Double(5.6);
String s = new String("abc");
上面创建了一个Double和String对象,并传入两个值,但程序无法继续修改该值,所以Double和String类没有修改值的方法。
如果要创建一个不可变类,需要遵守如下规则:
- 使用
private
和final
修饰符来修饰该类成员 - 提供带参构造器,用于初始化成员
- 仅提供get方法
- 确保引用的对象不会被修改
- 重写hashCode()方法和equals()方法
与此对应的是可变类,比如JavaBean,提供了getter()和setter方法。
缓存实例的不可变类
不可变类的实例状态不可改变,可以方便被多个对象共享,主要是为了减小开销。不同的缓存方式有着不同的性能,可以用数组、集合等来缓存。
以Java的java.lang.Integer
类为例,new一个构造器,每次返回新的Integer
对象;如果用valueOf()方法来创建Integer
对象,则会缓存该对象。
public class IntegerCacheTest{
public static void main(){
//new一个对象
Integer a1 = new Integer(6);
//生成新对象,并缓存该对象
Inreger a2 = Integer.valueOf(6);
Integer a3 = Integer.valueOf(6);
System.out.println(a1 == a2);//false
System.out.println(a2 == a3);//true
//注意:缓存的数只能在-128~127之间
}
}
公众号:菜鸡干Java