复用代码是Java众多引人瞩目的功用之一。
Java能够经过创立类来复用代码,要在运用类的时分不毁坏现有代码,有两种方式:
组合:在新的类中运用现有类的对象。
继承:依照现有类的类型来创立新类,无需改动现有类的方式,并为其添加新代码。
组合语法
运用组合技术只需求将对象援用置于新类中。
每个非根本类型的对象都有一个toString()办法,而且当编译器需求一个String而你传入一个对象时,toString()会被调用。
类中的对象援用会被默许初始化为null,假如你对其调用任何办法都会抛出异常,但是能够在不抛出异常的状况下,依然能够打印一个null援用
类中对象援用的初始化位置:
在定义对象的中央
在类的结构器中
惰性初始化,即在要运用该对象的中央停止初始化
实例初始化
classSoap{
privateStrings;
Soap(){
System.out.println(“Soup()”);
s=”Constructed”;
}
@Override
publicStringtoString(){
returns;
}
}
/**
*Bath
*/
publicclassBath{
privateStrings1=”happy”,//在定义处初始化
s2;
privateSoapsoap;
privateinti;
publicBath(){
System.out.println(“InsideBath()”);
soap=newSoap();//在结构函数中初四花
}
@Override
publicStringtoString(){
if(s2==null){
s2=”Joy”;//惰性初始化
}
returns2;
}
{
i=2;//实例初始化
}
publicstaticvoidmain(String[]args){
Bathb=newBath();
System.out.println(b);
}
}
继承语法
继承是OOP言语和Java言语不可短少的局部,当创立一个类时,总是在继承,即便没有显式继承某个类,也会隐式地从Object类中继承。
继承由关键词extends指定,其方式如classDetergentextendsCleanser{},基类的一切办法和成员都会自动导入到导出类中。
能够为每个类都创立一个main办法,这样能够使得每个类的单元测试变得烦琐。即便某个类只要包访问权限,其publicmain也能够经过javaclassName的方式访问到
为了继承,普通是将一切的数据成员都指定为private,将一切的办法指定为public。
我们对继承来的办法停止重写,重写之后能够经过super关键词访问基类版本的办法,如super.func();
Java会自动在导出类的结构器中插入对基类结构器的调用,其总是在导出类结构器执行之前,即便是在定义处初始化的语句也会在基类结构器执行之后执行。
即便没有为导出类创立结构器,编译器也会在默许结构器中调用基类的结构器
假如没有默许的基类结构器,或者想要调用一个带有参数的基类结构器,就必需运用super关键词显式调用基类结构器,调用基类结构器必需是在你导出类结构器的第一条语句。
代理
代理是指,我们将一个成员对象置于要结构的类中(像组合),但与此同时我们在新类中暴露该成员对象的一切或局部办法(想继承)。
IDEA自动创立代理的过程:
先在代理类中声明要代理的成员。
Alt+Insert快捷键,选中Delegation
选中要代理的函数即可。
classSpaceShipControls{
voidup(intvelocity){}
voiddown(intvelocity){}
voidleft(intvelocity){}
voidright(intvelocity){}
voidback(intvelocity){}
voidturboBoost(){}
}
publicclassSpaceShipDelegation{
SpaceShipControlsspaceShipControls=newSpaceShipControls();
publicvoidup(intvelocity){
spaceShipControls.up(velocity);
}
publicvoiddown(intvelocity){
spaceShipControls.down(velocity);
}
publicvoidleft(intvelocity){
spaceShipControls.left(velocity);
}
publicvoidright(intvelocity){
spaceShipControls.right(velocity);
}
publicvoidback(intvelocity){
spaceShipControls.back(velocity);
}
publicvoidturboBoost(){
spaceShipControls.turboBoost();
}
publicstaticvoidmain(String[]args){
SpaceShipDelegationspaceShipDelegation=newSpaceShipDelegation();
spaceShipDelegation.left(1);
}
}
分离运用组合继承
能够分离组合和继承来创立复杂的类
编译器会强迫你去初始化基类,并且请求在结构器最开端出就要这么做,但是它不会请求你对成员对象停止初始化,因而需求本人留意。
Java中没有C++中的析构函数,就像之前所说的一样,假如我们的类确实需求做一些相似的工作(如关闭文件),我们需求本人完成一个办法来完成,而当触及到继承时,我们要确保以正确的次第调用该函数,引荐和C++中析构函数的执行次第一样编写该函数,即先清算导出类自身,再调用基类的清算函数。
清算函数需求放在finally子句中,以防异常的呈现,招致清算函数未被执行,可参考练习12
假如Java的基类具有某个曾经被屡次重载的办法称号时,在导出类中重新定义该办法的称号,不会屏蔽其在基类中的任何版本。这意味着,在导出类中,重载和重新定义(重写)容易混杂在一同,假如不看基类的定义是很难分辨某个办法能否正确的被重新定义了。我们能够运用@Override注解来标识某个办法我们希望其是重写而不是重载,假如一不当心重载了,则会呈现编译错误来提示我们。
在组合与继承之间选择
组合和继承都允许在新的类中放置子对象,组合是显式地这样做,而继承则是隐式地这样做。
组合技术通常用于想在新类中运用现有类的功用而非它的接口这种状况。有时,允许类的用户直接访问新类中组合成分是有意义的。
在继承时,运用某个现有类,开发一个它的特殊版本。通常,这意味着你在运用一个通用类,并为了某种特殊需求而将其特殊化。
向上转型
“为新的类提供办法”不是继承中最重要的局部,其重要的方面是用来表现新类和基类之间的关系。简单的说,我们能够以为“导出类是基类的一品种型”,即能够把导出类当成基类来运用
由于导出类转换为基类在继承图上是向上挪动的,由于我们将其成为“向上转型”
向上转型是从一个较为专用的类向较为通用的类转变
固然在教授OOP的过程中屡次强调继承,但是我们应该慎用继承。判别能否要运用的继承的一个简双方法就是,判别我们能否要停止向上转型,假如要停止向上转型,则用继承,反之,则用组合。
classInstrument{
publicvoidplay(){}
staticvoidtune(Instrumenti){
i.play();
}
}
publicclassWindextendsInstrument{
publicstaticvoidmain(String[]args){
Windwind=newWind();
Instrument.tune(wind);//传送参数时,用了向上转型
}
}
final关键字
final关键词的含义通常指“无法改动的”,运用这个关键词通常是由于设计和效率的缘由。,final能够用在数据、办法和类上。
final数据
数据的恒定不变分为两种状况:编译经常量和在运转时初始化并并无法的改动的值。
在Java中,这类常量必需是根本数据类型,并且用关键词final表示,并在该常量定义时对其初始化,如finalintvalue=1。通常,编译经常量还是一个static数据,即staticfinalintVALUE_ONE=1。
编译器常量的命名规则是:全用大写字母,单词与单词之间用_隔开
即便一个变量是final,我们也无法肯定其是编译经常量,由于初始化没有请求是字面量,即初始化能够经过调用函数完成,如finalintvalue=rand.nextInt(20)。
同时一个final数值,假如其是static的,那么它可能是在类导入时初始化的,而他不是static的话,它是在实例化时初始化的。
关于根本变量,final使数值恒定不变,但是关于对象援用,其只是请求对象援用不变,即不指向新的对象,而对象自身是能够被修正的。
Java允许“空白final”,即被声明为final但是又没有给定初值的域,固然能够在定义时不给定初值,按时编译器会保证,final域在运用前都必需被初始化,即假如没有在定义处给定final域的初值的话,就必需在每个结构器中对该final域停止赋值。
Java允许在参数列表中以声明的方式将参数指明为final,其含义为,在该函数中无法修正该变量:
参数类型为根本类型:能够读参数,但是不能修正
参数类型为对象类型:无法修正援用
final办法
能够将一个办法定义成final,这样能够避免任何继承类修正它的含义(即导出类无法掩盖完成)
在Java的早期完成中,对final办法的调用会被转为内嵌调用(C++中的inline),但是如今不需求用这样的方式来优化代码了
类中的一切private办法都被隐式的指定为final
“掩盖”只要在办法是基类的接口的一局部时才会呈现,即必需能将一个对象向上转型为它的根本类型并调用相同的办法,假如一个办法是private,那么它就不是接口的一局部。
final类
当将一个类的整体定义为final时,就标明该类无法被继承,同时隐式地将一切办法都定义为final。
初始化及类的加载
每个类的编译代码都存在与他本人独立的文件中。该文件只要在需求运用程序代码的时分才会被加载。
普通来说,只要在“类初次运用才加载”,即加载发作于第一次创立类的对象或第一次运用类中的静态域或静态办法。
在加载导出类是,Java编译器会留意到它继承于某个基类,因而他会先去加载该基类。
广州天河区珠江新城富力盈力大厦北塔2706
020-38013166(网站咨询专线)
400-001-5281 (售后服务热线)
品牌服务专线:400-001-5281
长沙市天心区芙蓉中路三段398号新时空大厦5楼
联系电话/ (+86 0731)88282200
品牌服务专线/ 400-966-8830
旗下运营网站:
Copyright © 2016 广州思洋文化传播有限公司,保留所有权利。 粤ICP备09033321号