第七章 复用类

简介

复用代码是java众多引人注目的功能之一。但要像成为极具革命性的语言,仅仅能够复制代码并对之加以改革是不够的,它嗨必须能够做更多的事情
怎么进行复用,java中主要是两种方法–组合继承

  • 组合:只需要在新的类中产生现有类的对象。由于新的类是由现有类的对象所组成,所有这种方法称为组合。该方法只是复用现有程序代码的功能,而非它的形式。
  • 继承:它按照现有类的类型来创建新类。无需改变现有类的形式,采用现有类的形式并在其中添加新代码。这种神奇的方式叫做继承。继承是面向对象程序设计的基石之一。

组合语法

简单来说,如何使用组合技术,只需将对象引用至于新类中即可。

public class SprinkLerSystem{
	//String类型
	private String value1,value2;
	//基本类型
	private int i;
	//引用类型,组合的使用
	private WaterSource waterSource=new WaterSource();

}

继承语法

继承是OOP语言和java语言不可或缺的一部分,当创建一个类的时候总是在实现继承。一般没有直接extends指名的都是隐式从Object根类中继承。
如何实现继承?

public class son extends parent{
}

上面就是 son类继承parent类,此时son类又叫子类(导出类),parent类又叫父类(基类)。

初始化基类

直接上代码

class Art{
	Art(){print("Art constructor");}
}

class Drawing extends Art{
	Drawing(){print("Drawing constructor");}
}

public class Cartoon extends Drawing {
	public Cartoon (){print("Cartoon constructor");}
	public static void main(String[]args){
		Cartoon x=new Cartoon();
	}
}

//Outpt:
//Art constructor
//Drawing constructor
//Cartoon constructor

由此得出结论:
构建过程是从基类向导出类扩散,所有基类在导出类构造器可以访问它之前就已经被初始化了。
换句话讲:向访问基类再从上至下依次初始化

如何选择组合还是继承

组合和继承都允许在新的类中放置子对象,组合是显示地这样做,而继承是隐式的做。这时候很多朋友都想,到底该怎么选择?
首先了解下组合和继承的区别:
组合:技术通常用于在新类中实现现有类的功能而非它的接口的情形。即在新类中嵌入某一个对象,让其实现所需要的功能,但新类的用户看到的实时为新类所定义的接口,而非所嵌入对象的接口
继承:在继承中,使用某个现有类,并开发一个它的特殊版本。
另外,同时使用组合和继承是很常见的事情

protected关键字

在大致了解完 继承之后,protected关键字终于有了意义,在理想世界中使用private就已经足够了。但是实际项目中,经常会想要讲某些事物尽可能的对这个世界隐藏起来,但任允许导出类的成员访问它们,这时候就可以使用protected关键字。

向上转型

class Instrument{
	static void tune(Instrument i){......};
}

public class Wind extends Instrument{
	public static void main(String[] args){
	Wind flute=new Wind();
	Instrument.tune(flute);//向上转型
	}

}

此例中 tune()方法可以接受Instrument引用,但在Wind.main()中,传递给tune()方法的是一个Wind引用,鉴于java对类型的检查十分严格,接受某种类型的方法同样可就收另一种类型就会很奇怪,除非你认识Wind对象同样也是Instrument对象,
在tune()中,程序代码可以对Instrument和它所有的导出类起作用,这种将Wind引用转换为Instrument引用的动作,我们叫做向上转型

而实现向上转型继承是必须的。

为啥叫向上转型?
因为继承关系图,子类在父类的下面,子类想转为父类就是从下往上转型。
因此也向下转型也就是父类转换为子类对象。

final关键字

根据上下文环境,java的关键字final存在细微的区别。但通常它是指“这是无法改变的”。不想改变可能出于这两个原因:设计效率

以下谈谈可能使用到final的三种情况:数据,方法

final数据

许多编程语言都有这种情况,向编译器告知一块数据是恒定不变的,有时候数据恒定不变是很有用的。
比如1:一个永不改变的编译时常量。2:一个在运行时候被初始化的值,而你不希望它被改变。
对于编译期常量这种情况,这类常量必须是基本数据类型,而且是final修饰,并且在对其定义的时候,必须对其进行赋值。

final修饰数据类型可分类两类

  • 基本类型:修饰基本类型代表数值恒定不变。
  • 引用类型:修饰引用类型代表无法改变引用。一旦引用被初始化指向一个对象,就无法再把它指向另外一个对象。然而其自身却可以被修改。

一个即使static又是final的域只占一段不能改变的存储空间。

final修饰参数
另外final还可修饰参数:代表你无法在方法中更改参数引用所指向的对象。

public calss FinalArguments {
	 void with(final Gizmo g){
	 	// !g=new Gizmo();
	 	//错误,final修饰参数之后不能改变参数引用指向的对象
	 }
}

final 方法

使用fianl方法的原因有两个。
第一个原因是把方法锁定,以防止继承类修改它的含义。
第二个原因是过去建议使用final方法,是因为效率,但在java SE5/6之后就建议让编译器和jvm去处理效率问题。

final 和 private 关键字

类中所有private方法都是隐式地指定为final。由于无法取用private方法,所有也就无法覆盖它。可以对private方法添加final修饰词,但这并不能给该方法增加任何额外的意义。

final 类

将整个类定义为final时,就表明你不打算继承该类,而且也不允许别人这么做。简单的说,年拟不希望它有子类

初始化及类加载

在许多传统语言中,程序是作为启动过程的一部分立刻被加载。然后是初始化,紧跟着程序开始运行。
这里注意static修饰符
在c++中如果一个static期望在另一个static在被初始化之前就能有效的使用它,这样就会出现问题。
但是java不会这样。java一切皆对象。每个类的编译代码都是存在它自己的独立文件中,该文件只有被使用的时候才会被加载。可以这样说:“类的代码在初次使用才加载。”。
初次使用也是static初始化的地方,所有static对象和static代码段都会在加载的时候按照程序中的顺序进行初始化。
当然定义为static的东西只会被初始化一次

继承与初始化

在这里插入图片描述
观察上面代码,在Beetle上运行java时,所发生的第一件事情就是试图访问Beetle.main()(一个static方法),于是加载器开始启动并找出Beetle类的编译代码(在名为Beetle.calss的文件中)。在对其进行加载的时候发现他又基类,于是它转为去加载基类,直到找到根基类。
根基类中static初始化即会被执行,然后依次是下一个导出类。
至此必要的类都加载完毕,对象就可以创建了。首先对象中的所有的基本类型都会被设置被默认值。对象引用被设置为null。然后基类的构造器会被调用。基类的构造器和导出类的构造器一样,以相同的顺序来经历相同的过程。在基类构造器完成后,实例变量按其顺序被初始化,最后,构造器的其余部分被执行

总结

继承和组合都能从现有类型生成新类型。组合一般是将现有类型作为新类型底层实现的一部分来加以复用,而继承复用的是接口。
在使用继承时,由于导出类具有基类接口,因此它可以向上转型至基类,者对于多态来讲至关重要。
尽管继承十分重要,但是设计程序的时候尽量有限考虑使用组合,因为组合更加灵活,只有在必要的时候才使用继承。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值