黑马程序员JAVA笔记4--继承

来源:互联网 发布:网络用语大全及解释88 编辑:程序博客网 时间:2024/06/06 13:14

继承

一、继承的描述

    通过 extends 关键字让类与类之间产生继承关系。

    多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。

注释:

    1、子类可以直接访问父类中的非私有的属性和行为。

    2、子类无法继承父类中私有的内容。

3、父类怎么来的?共性不断向上抽取而来的。

 

好处:
    继承的出现提高了代码的复用性。
    继承的出现让类与类之间产生了关系,提供了多态的前提。

二、继承的特点
    Java只支持单继承,不支持多继承。
    一个类只能有一个父类,不可以有多个父类。
原因:
    因为多继承容易出现问题。两个父类中有相同的方法,子类到底要执行哪一个是不确定的。
    那么创建类C的对象,调用show方法就不知道调用类A中的show方法还是类B中的show方法。所以java不支持多继承,但将这种机制换了另一个安全的方式来体现,也就是多实现(后面会详细说明)。


    Java支持多层继承(继承体系)
    C继承BB继承A,就会出现继承体系。
    多层继承出现的继承体系中,通常看父类中的功能,了解该体系的基本功能,建立子类对象,即可使用该体系功能。
    定义继承需要注意:
    不要仅为了获取其他类中某个功能而去继承,类与类之间要有所属( "is a")关系。

 

三、super关键字&函数覆盖

在子父类中,成员的特点体现:
    1)成员变量
        thissuper的用法很相似。
        this代表本类对象的引用。
        super代表父类的内存空间的标识。

        当本类的成员和局部变量同名用this区分。
        当子父类中的成员变量同名用super区分父类。


    2)成员函数
        当子父类中出现成员函数一模一样的情况,会运行子类的函数。
        这种现象,称为覆盖操作,这是函数在子父类中的特性。
        在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。

    函数两个特性:
    1. 重载,同一个类中。
    2. 覆盖,子类中,覆盖也称为重写,覆写,override


    什么时候使用覆盖操作?
    当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
注释:

1、父类中的私有方法不可以被覆盖。
    2、父类为static的方法无法覆盖。
    3、覆盖时,子类方法权限一定要大于等于父类方法权限。
    

3)构造函数
        子父类中构造函数的特点:
        在子类构造函数执行时,发现父类构造函数也运行了。
        原因:在子类的构造函数中,第一行有一个默认的隐式语句:super();
        注意:如果使用super(4);语句调用父类的其他构造函数,那么默认的父类构造函数将不会再被调用。


四、子类的实例化过程

    子类中所有的构造函数默认都会访问父类中空参数的构造函数。
    因为每一个构造函数的第一行都有一条默认的语句super();
    子类会具备父类中的数据,所以要先明确父类是如何对这些数据初始化的。

    为什么子类实例化的时候要访问父类中的构造函数呢?
    那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,要先看父类是如何对自己的内容进行初始化的。
注释:
    1、当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。
    2、子类构造函数中如果使用this调用了本类构造函数,那么默认的super();就没有了,因为superthis都只能定义在第一行,所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
    3super语句必须要定义在子类构造函数的第一行!因为父类的初始化动作要先完成。
    总结:

    一个对象实例化过程,以Person p = new Person();为例:
    1. JVM会读取指定的路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接的父类的情况下)。
    2. 在内存中开辟空间,并分配地址。
    3. 并在对象空间中,对对象的属性进行默认初始化。
    4. 调用对应的构造函数进行初始化。
    5. 在构造函数中,第一行会先到调用父类中构造函数进行初始化。
    6. 父类初始化完毕后,再对子类的属性进行显示初始化。
    7. 再进行子类构造函数的特定初始化。
    8. 初始化完毕后,将地址值赋值给引用变量。

 

五、final关键字
    final可以修饰类,方法,变量。
    final修饰的类不可以被继承。
    final修饰的方法不可以被覆盖。
    final修饰的变量是一个常量,只能被赋值一次。

    为什么要用final修饰变量,其实在程序中如果一个数据是固定的。
    那么直接使用这个数据就可以了,但是这种阅读性差,所以应该给数据起个名称。
    而且这个变量名称的值不能变化,所以加上final固定。
    写法规范:常量所有字母都大写,多个单词,中间用_连接。

 

六、抽象类

(1)抽象类概述
    抽象定义:
    抽象就是从多个事物中将共性的,本质的内容抽取出来。
    例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。

    抽象类:
    Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。

    抽象方法的由来:
    多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
    例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。

2)抽象类的特点
    抽象类和抽象方法必须用abstract关键字来修饰。
    抽象方法只有方法声明,没有方法体,定义在抽象类中。
    格式:修饰符 abstract 返回值类型 函数名(参数列表) ;
    抽象类不可以被实例化,也就是不可以用new创建对象。
    原因如下:
    1. 抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。
    2. 而且抽象类即使创建了对象,调用抽象方法也没有意义。
    3. 抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。


3)抽象类举例代码讲解  
    需求:
   公司中程序员有姓名,工号,薪水,工作内容。
   项目经理除了有姓名,工号,薪水,还有奖金,工作内容。

    分析:
    在这个问题领域中,通过名词提炼法:
    程序员:
    属性:姓名,工号,薪水。
    行为:工作。
    经理:
    属性:姓名,工号,薪水,奖金。
    行为:工作。

    程序员和经理不存在着直接继承关系。
    但是,程序员和经理却具有共性内容,可以进行抽取,因为他们都是公司的雇员。
    可以将程序员和经理进行抽取,建立体系。

4)抽象类相关问题
    抽象类中是否有构造函数?
    答:有,用于给子类对象进行初始化。

    抽象关键字abstract不可以和哪些关键字共存?
    答:privatestaticfinal

    抽象类中可不可以没有抽象方法?
    答:可以,但是很少见。目的就是不让该类创建对象,AWT的适配器对象就是这种类。通常这个类中的方法有方法体,但是却没有内容。

    抽象类和一般类的区别?
    答:
    相同点:
    抽象类和一般类都是用来描述事物的,都在内部定义了成员。

    不同点:
    1. 一般类有足够的信息描述事物。
        抽象类描述事物的信息有可能不足。
    2. 一般类中不能定义抽象方法,只能定义非抽象方法。
       抽象类中可定义抽象方法,同时也可以定义非抽象方法。
    3. 一般类可以被实例化。
       抽象类不可以被实例化。

    抽象类一定是个父类吗?
    答:是的,因为需要子类覆盖其方法后才可以对子类实例化。

 

七、接口

    当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口。
    格式:interface {}

    接口中的成员修饰符是固定的:
    成员常量:public static final
    成员函数:public abstract
    由此得出结论,接口中的成员都是公共的权限。

    接口是对外暴露的规则。
    接口是程序的功能扩展。
注释:
    1、虽然抽象类中的全局变量和抽象方法的修饰符都可以不用写,但是这样阅读性很差。所以,最好写上。
    2、类与类之间是继承关系,类与接口直接是实现关系。
    3、接口不可以实例化,只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。否则,这个子类就是一个抽象类。
    接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。

    java中不直接支持多继承,因为会出现调用的不确定性。
    所以,java将多继承机制进行改良,在java中变成了多实现,一个类可以实现多个接口。
    接口的出现避免了单继承的局限性。

    一个类在继承另一个类的同时,还可以实现多个接口。

抽象类和接口的异同点?
    相同点:
    都是不断向上抽取而来的。
    不同点:
    1. 抽象类需要被继承,而且只能单继承。
        接口需要被实现,而且可以多实现。
    2. 抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。
        接口中只能定义抽象方法,必须由子类去实现。
    3. 抽象类的继承,是is a关系,定义该体系的基本共性内容。
        接口的实现是like a关系。  

 

八、多态

定义:某一类事物的多种存在形态。
   例:动物中猫,狗。
    猫这个对象对应的类型是猫类型:猫 x = new ();
    同时猫也是动物中的一种,也可以把猫称为动物:动物  y = new ();
    动物是猫和狗具体事物中抽取出来的父类型。
    父类型引用指向了子类对象。
    多态性简单说就是一个对象对应着不同类型。
    体现:
    父类或者接口的引用指向或者接收自己的子类对象。
    作用:
    多态的存在提高了程序的扩展性和后期可维护性。
    前提:
    1. 需要存在继承或者实现关系。
    2. 需要有覆盖操作。    
    好处:
    提高了代码的扩展性,前期定义的代码可以使用后期的内容。
    弊端:
    前期定义的内容不能使用(调用)后期子类的特有内容。

    多态时,成员的特点:
    1. 成员变量
       编译时:参考引用型变量所属的类中是否有调用的成员变量。有,编译通过,没有,编译失败。
       运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
       简单说:编译和运行都参考等号的左边。

    2. 成员函数(非静态)

       编译时:参考引用型变量所属的类中是否有调用的函数。有,编译通过。没有,编译失败。
       运行时:参考的是对象所属的类中是否有调用的函数。
       简单说:编译看左边,运行看右边。

3. 静态函数
       编译时:参考的是对象所属的类中是否有调用的函数。
       运行时:参考的是对象所属的类中是否有调用的函数。
       简单说:编译和运行看左边。

 

九、内部类

定义:
    将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)。
访问特点:
    内部类可以直接访问外部类中的成员,包括私有成员。
    而外部类要访问内部类中的成员必须要建立内部类的对象。
    内部类的位置:

    内部类定义在成员位置上,可以被privatestatic成员修饰符修饰。被static修饰的内部类只能访问外部类中的静态成员。
注释:      

    1、如果内部类中定义了静态成员,该内部类也必须是静态的!

    2、为什么内部类能直接访问外部类中的成员呢?

         那是因为内部类持有了外部类的引用,外部类名.this  

    3、内部类定义在局部位置上,也可以直接访问外部类中的成员。
         同时可以访问所在局部中的局部变量,但必须是被final修饰的。

     匿名内部类
定义:
    就是内部类的简化写法。
前提:
    内部类可以继承或实现一个外部类或者接口。
格式:
    new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}
简单理解:
    就是建立一个带内容的外部类或者接口的子类匿名对象。

    什么时候使用匿名内部类呢?
    通常使用方法是接口类型参数,并且该接口中的方法不超过三个,可以将匿名内部类作为参数传递。
    好处:
    增强阅读性。

十、异常

1)异常的体系

    异常:是在运行时期发生的不正常情况。
    java中用类的形式对不正常情况进行了描述和封装对象。描述不正常的情况的类,就称为异常类。
    1. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问题处理代码分离,提高阅读性。
    2. 其实异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述。
    3. 不同的问题用不同的类进行具体的描述。比如角标越界、空指针异常等等。
    4. 问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系。

不正常情况分成了两大类:
    Throwable:无论是error,还是异常、问题,问题发生就应该可以抛出,让调用者知道并处理。
    该体系的特点就在于Throwable及其所有的子类都具有可抛性。
    可抛性到底指的是什么呢?怎么体现可抛性呢?
    其实是通过两个关键字来体现的。
    throws throw,凡是可以被这两个关键字所操作的类和对象都具备可抛性。

    1. 一般不可处理的:Error
       特点:是由jvm抛出的严重性问题。
       这种问题发生,一般不针对性处理,直接修改程序。
    2. 可以处理的:Exception

    该体系的特点:
    子类的后缀名都是用其父类名作为后缀,阅读性很强。

    Throwable中的方法:
    1. getMessage():获取异常信息,返回字符串。
    2. toString():获取异常类名和异常信息,返回字符串。
    3. printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置,返回值void
    4. printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。

2)自定义异常
    可以自定义出的问题称为自定义异常。
    对于角标为负数的情况,准备用负数角标异常来表示,负数角标这种异常在java中并没有定义过。
    那就按照java异常的创建思想,面向对象,将负数角标进行自定义描述,并封装成对象。
    这种自定义的问题描述称为自定义异常。
注释:
    如果让一个类成为异常类,必须要继承异常体系,因为只有成为异常体系的子类才有资格具备可抛性,才可以被两个关键字所操作,throwsthrow
    自定义类继承Exception或者其子类,通过构造函数定义异常信息。
    通过throw将自定义异常抛出。

    throwsthrow的区别:
    1. throws用于标识函数暴露出的异常类,并且可以抛出多个,用逗号分隔。
    2. throw用于抛出异常对象。
    3. thorws用在函数上,后面跟异常类名。
    4. throw用在函数内,后面跟异常对象。

    定义功能方法时,需要把出现的问题暴露出来让调用者去处理,那么就通过throws在函数上标识。
    在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

    异常的分类:
    1. 编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。
        这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。
        这样的问题都可以针对性的处理。

    2. 编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。
        这种问题的发生,无法让功能继续,运算无法运行,更多是因为调用的原因导致的或者引发了内部状态的改变导致的。
        那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行调整。
        所以自定义异常时,要么继承Exception,要么继承RuntimeException
注释:
    RuntimeException是那些可能在Java虚拟机正常运行期间抛出的异常的超类。
    可能在执行方法期间抛出但未被捕获的RuntimeException的任何子类都无需在throws子句中进行声明。

    异常处理的捕捉形式:
    可以对异常进行针对性处理的方式。

    具体格式是:
    try{
         //需要被检测异常的代码。
    }
    catch(异常类 变量) //该变量用于接收发生的异常对象
    {
         //处理异常的代码。
    }
    finally{
         //一定会执行的代码;
    }
注释:
    finally代码块只有一种情况不会被执行,就是在之前执行了System.exit(0)

    处理过程:
    try中检测到异常会将异常对象传递给catchcatch捕获到异常进行处理。
    finally里通常用来关闭资源。比如:数据库资源,IO资源等。
    需要注意:try是一个独立的代码块,在其中定义的变量只在该变量块中有效。
    如果在try以外继续使用,需要在try外建立引用,在try中对其进行初始化。IOSocket就会遇到。

    异常处理的原则:
    1. 函数内容如果抛出需要检测的异常,那么函数上必须要声明。
        否则,必须在函数内用try/catch捕捉,否则编译失败。

    2. 如果调用到了声明异常的函数,那么try/catch,要么throws,否则编译失败。

    3. 什么时候catch,什么时候throws呢?
        功能内容可以解决,用catch
        解决不了,用throws告诉调用者,由调用者解决。

    4. 一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性处理。
       内部有几个需要检测的异常,就抛几个异常,抛出几个,就catch几个。

    try catch finally 代码块组合特点:
    1. try catch finally
    2. try catch(多个)当没有资源需要释放时,可以不用定义finally
    3. try finally 异常无法直接catch处理,但是资源必须关闭。

异常的注意事项:    
    1. RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明。
    2. 子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。
    3. 如果父类抛出多个异常,那么子类只能抛出父类异常的子集。
    简单说:子类覆盖父类只能抛出父类的异常或者子类的子集。

注释:
    如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛,就只能try

 

十一、Object

    Object:所有类的根类。
    Object是不断抽取而来,具备着所有对象都具备的共性内容。
注释:
    ==以及Object类的equals方法默认都是根据对象的哈希值判断两个对象是否相等。
    可以通过覆盖Objectequals方法来重写比较规则。

Object类的toString方法默认返回的内容是“对象所属的类名+@+对象的哈希值(十六进制)”。

十二、包

 对类文件进行分类管理。
    给类提供多层命名空间。
    写在程序文件的第一行。
    类名的全称的是:包名.类名。
    包也是一种封装形式。

    创建mypack文件夹,并且将PackageDemo.class放入其中,然后再次执行。

 也可以通过javac命令直接创建mypack文件夹,然后执行。

注释:
    包与包之间的类进行访问,被访问的包中的类必须是public的,被访问的包中的类的方法也必须是public的。

包之间的访问:    被访问的包中的类权限必须是public的。
    类中的成员权限:public或者protected
    protected是为其他包中的子类提供的一种权限。

    四种权限:

public 同一类中、同一包中、子类、不同包中

Protected:同一类中、同一包中、子类

default   同一类中、同一包中

private   同一类中

 

Import:
     一个程序文件中只有一个package,但可以有多个import
注释:
    用来导包中的类,不导入包中的包。
示例:
    有两个类:DemoADemoAbc
    所在文件目录如下:
    packa\DemoA.class
    packa\abc\DemoAbc.class


    导包语句如下:
    import packa.*;
    import packa.abc.*;

   

 Jar
    Java的压缩包。
    方便项目的携带。
    方便于使用,只要在classpath设置jar路径即可。
    数据库驱动,SSH框架等都是以jar包体现的。

    Jar包的操作:
    通过jar.exe工具对jar的操作。
    创建jar包:
    jar  -cvf  mypack.jar  packa packb
    查看jar
    jar  -tvf  mypack.jar   [>定向文件]

    解压缩
    jar  -xvf  mypack.jar

    自定义jar包的清单文件
    jar –cvfm  mypack.jar  mf.txt  packa packb

 

0 0
原创粉丝点击