黑马程序员——4.继承(接口、多态、内部类、异常、包)
来源:互联网 发布:淘宝刷手是什么意思 编辑:程序博客网 时间:2024/03/29 14:22
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
继承:
多个类之间有共性时,可以把共性部分提取出来单独创建一个类,这个类就叫父类或超类;其他的类只要继承这个类,就能拥有这些特性,而不必再单独定义,继承父类的类就叫子类。
继承的好处:
- 提高了代码的复用性
- 让类与类之间产生了关系,有了这个关系,才有了多态的特性
P.S.
- 子类可以直接访问父类中的非私有的属性和行为。
- 子类无法继承父类中私有的内容。
- 不能单单为了简化书写而定义继承关系,必须是从属关系才可以。
继承的特点:
Java只支持单继承,不支持多继承。
一个类只能有一个父类,不可以有多个父类。
原因:
因为多继承容易出现问题。两个父类中有相同的方法,子类到底要执行哪一个是不确定的(但是java保留了这种功能,并用了另外的实现方式—-多实现)。
Java支持多层继承(继承体系):
C继承B,B继承A,就会出现继承体系。
多层继承出现的继承体系中,使用体系时,查找父类的描述说明以了解体系;在创建对象时,要创建最子类的对象,一是父类可能不能创建对象,二是最子类可用的功能最多。
super关键字:
在子父类中,成员的特点体现:
成员变量
this和super的用法很相似。
this代表本类对象的引用。
super代表父类的内存空间的标识。当本类的成员和局部变量同名用this区分。
当子父类中的成员变量同名用super区分父类。成员函数
函数的特性:重写(覆盖)当子类有与父类一模一样(参数列表个数及返回值类型也要相同)的函数时,子类对象在调用该函数时,会运行子类函数而不是父类函数。在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
什么时候使用覆盖操作?
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。P.S.
- 父类中的私有方法不可以被覆盖。
- 父类为static的方法无法覆盖。
- 覆盖时,子类方法权限一定要大于等于父类方法权限。
构造函数
子类构造函数第一行默认有一句super()语句用来访问父类中空参数的构造函数。我们可以自行定义super()的参数列表以调用父类的其他构造函数,但此super调用一定要定义在子类构造函数的开头。为什么子类实例化的时候要访问父类中的构造函数呢?
那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,要先看父类是如何对自己的内容进行初始化的。P.S.
- 当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。
- 子类构造函数中如果使用this()调用了本类的其他构造函数,那么默认的super();就没有了,因为super和this都只能定义在第一行,所以只能有一个。但是可以保证的是,该this()语句会调用子类中的其他构造函数来访问父类构造函数。就是说,在子类中至少会存在一句构造函数语句用来访问父类构造函数。
- super语句必须要定义在子类构造函数的第一行!因为父类的初始化动作要先完成。
class Fu{ Fu(){ super(); //父类方法被子类覆盖,因此调用的是子类的show方法,此时其成员变量num还未进行显示初始化,因此还是默认值0 show(); //先打印“zi show...0” return; } void show(){ System.out.println("fu show" ); }}class Zi extends Fu{ int num = 8; Zi(){ super(); //通过super初始化父类内容时,子类的成员变量并未显示初始化,等super()父类初始化完毕后,才进行子类的成员变量显示初始化 return; } void show(){ System.out.println("zi show..." + num); }}class ExtendDemo{ public static void main(String[] args){ //初始化子类时先调用父类构造函数 Zi z = new Zi(); //此时子类初始化完毕,再打印“zi show...8” z.show(); }}
final关键字:
- final可以修饰类,方法,变量。
- final修饰的类不可以被继承。
- final修饰的方法不可以被覆盖。
- final修饰的变量是一个常量,只能被赋值一次。
被final修饰的变量的写法规范:常量所有字母都大写,多个单词,中间用_连接,例如:public static final double PI = 3.14。
抽象类:
Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
抽象方法的由来:
多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
抽象类和抽象方法必须用abstract关键字来修饰,抽象关键字abstract不可以和private、static、final关键字共存。
抽象方法只有方法声明,没有方法体,定义在抽象类中。
格式:修饰符 abstract 返回值类型 函数名(参数列表) ;
抽象类不可以被实例化,也就是不可以用new创建对象。
原因如下:
- 抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。
- 而且抽象类即使创建了对象,调用抽象方法也没有意义。
- 抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。
//定义抽象类abstract class Demo{ //定义抽象方法 //只有方法名,没有方法主体 abstract void show();}//定义子类继承抽象类class DemoA extends Demo{ //覆盖父类的抽象方法 void show(){ //定义抽象方法的方法主体 System.out.println("demoa show" ); }}class DemoB extends Demo{ void show(){ System.out.println("demob show" ); }}class AbstractDemo{ public static void main(String[] args){ DemoA demoA = new DemoA(); demoA.show(); DemoB demoB = new DemoB(); demoB.show(); }}
特殊:抽象类中可以不定义抽象方法,这样做仅仅是为了不让类创建实例对象,通常这个类中的方法有方法体,但是却没有内容。
接口:
当一个抽象类中的所有方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口。
格式:interface 接口名{}
接口中的成员修饰符是固定的,不可更改:
- 成员常量:public static final
- 成员函数:public abstract
由此得出结论,接口中的成员都是公共的权限。
接口是对外暴露的规则。
接口是程序的功能扩展。
P.S.
- 虽然抽象类中的全局变量和抽象方法的修饰符都可以不用写,但是这样阅读性很差。所以,最好写上。
- 类与类之间是继承关系,类与接口直接是实现关系。
- 接口不可以实例化,能由实现了接口并覆盖了接口中所有的抽象方法的子类实例化。否则,这个子类就是一个抽象类。
//定义接口interface Demo{ //接口中各成员的修饰符固定 public static final int NUM = 4; //接口中方法都是抽象的 public abstract void show1(); public abstract void show2();}//定义类实现接口class DemoImpl implements Demo{ //实现接口中的抽象方法 public void show1(){} public void show2(){}}class InterfaceDemo{ public static void main(String[] args){ DemoImpl d = new DemoImpl(); System.out.println(d.NUM); System.out.println(DemoImpl.NUM); System.out.println(Demo.NUM); }}
多实现:
接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。
在java中不直接支持多继承,因为会出现调用的不确定性。
所以,java将多继承机制进行改良,在java中变成了多实现,一个类可以实现多个接口。
接口的出现避免了单继承的局限性。
一个类在继承另一个类的同时,还可以实现多个接口。
interface A{ public void show(); } interface Z{ public void show(); } class Q{ public void method(){ } } class Test2 extends Q implements A,Z{ }
多态:
多态指的是一种事物存在的多种形态
例:动物中猫,狗。
猫这个对象对应的类型是猫类型:猫 x = new 猫();
同时猫也是动物中的一种,也可以把猫称为动物:动物 y = new 猫();
动物是猫和狗具体事物中抽取出来的父类型。
父类型引用指向了子类对象。
多态性简单说就是一个对象对应着不同类型。
体现:
父类或者接口的引用指向或者接收自己的子类对象。
作用:
多态的存在提高了程序的扩展性和后期可维护性。
前提:
- 需要存在继承或者实现关系。
- 需要有覆盖操作。
好处:
- 提高了代码的扩展性,前期定义的代码可以使用后期的内容。
弊端:
- 前期定义的内容不能使用(调用)后期子类的特有内容。
多态时,成员的特点:
- 成员变量
编译和运行都参考等号的左边。 - 成员函数(非静态)
编译看左边,运行看右边。 - 静态函数
编译和运行都看左边。
//一个抽象的动物类abstract class Animal{ //动物的共有方法吃东西,但是具体吃东西的方式不确定,所以是抽象的 abstract void eat();}//猫也是动物的一种class Cat extends Animal{ //覆盖抽象方法,定义猫的吃东西方法 void eat(){ System.out.println("吃鱼"); } //猫除了动物中都有的吃东西方法外,还有自己的特有的抓老鼠的方法 void catchMouse(){ System.out.println("抓老鼠"); }}class DuoTaiDemo{ public static void main(String[] args){ //自动类型提升,把猫对象提升到了动物类型。但是特有功能无法访问,作用就是限制对特有功能的访问。 //专业讲:向上转型,将子类型隐藏。就不能使用子类的特有方法了。 Animal a = new Cat(); a.eat(); //该对象还是猫对象,eat方法为“吃鱼” //a.catchMouse();//特有方法不能使用,报错 //如果还想用具体动物猫的特有功能。 //你可以将该对象进行向下转型。 Cat c = (Cat)a; //向下转型的目的是为了能够使用子类中的特有方法。 c.eat(); c.catchMouse(); //注意:对于转型,自始至终都是子类对象在做类型的变化。 //Animal a = new Dog(); //Cat c = (Cat)a;//但是类型不能随意转换,否则可能会报出ClassCastException的异常 } public static void method(Animal a){ a.eat(); }}
instanceof :用于判断对象的具体类型,只能用于引用数据类型判断,通常在向下转型前用于健壮性的判断。
class DuoTaiDemo{ public static void main(String[] args){ } public static void method(Animal a){ a.eat(); //如果a为猫对象 if(a instanceof Cat){ Cat c = (Cat )a; c.catchMouse(); } //如果a为狗对象 else if (a instanceof Dog){ Dog d = (Dog )a; d.lookHome(); } }}
内部类:
将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)。
访问特点:
- 内部类可以直接访问外部类中的成员,包括私有成员。
- 而外部类要访问内部类中的成员必须要建立内部类的对象。
内部类的位置:
内部类定义在成员位置上,可以被private、static成员修饰符修饰。被static修饰的内部类只能访问外部类中的静态成员。
如果内部类是静态的,内部类成员也是静态的,可以不用创建内部类对象,直接调用。
内部类被static修饰:
内部类在外部类的成员位上且被static修饰时,内部类就具有了静态的特性,只能访问外部类的静态变量,出现了访问局限,创建对象时可以直接用外部类名创建——new WaiBu.NeiBu().function()
P.S.
- 如果内部类中定义了静态成员,该内部类也必须是静态的!
- 内部类能直接访问外部类中的成员,因为内部类持有了外部类的引用,外部类名.this。
- 内部类定义在局部位置上,也可以直接访问外部类中的成员。同时可以访问所在局部中的局部变量,但必须是被final修饰的。
//定义外部类class Outer{ //外部类成员变量 int num = 3; //定义内部类 class Inner{ //内部类的成员变量 int num = 4; void show(){ //内部类的局部变量 int num = 5; //对局部变量的调用 System.out.println(num); //对内部类成员变量的调用 System.out.println(this.num); //对外部类成员变量的调用——外部类名.this System.out.println(Outer.this.num); } } //外部类成员调用内部类方法时,要创建内部类对象来调用 void method(){ new Inner().show(); }}class InnerClassDemo{ public static void main(String[] args){ //定义内部类时要通过外部类 new Outer().Inner().show(); }
匿名内部类:
就是内部类的简化写法。
前提:
内部类可以继承一个外部类或者或实现一个接口。
格式:
new 外部类名或者接口名(){覆盖类或者接口中的代码(也可以自定义内容)}
简单理解:
就是建立一个带内容的外部类或者接口的子类匿名对象。
什么时候使用匿名内部类呢?
通常使用方法是接口类型参数,并且该接口中的方法不超过三个,可以将匿名内部类作为参数传递。
好处:
增强阅读性。
abstract class Demo{ abstract void show();}class Outer{ int num = 4; void method(){ //继承一个外部类 new Demo(){ //覆盖方法 void show(){ System.out.println("show......" + num); } }.show();//使用方法 }}class InnerClassDemo{ public static void main(String[] args){ new Outer().method(); }}
interface Inter{ void show1(); void show2();}class Outer{ public void method(){ //使用匿名内部类的方法创建对象 Inter in = new Inter(){ //实现接口,实现方法 public void show1(){ System.out.println("...show1...." ); } public void show2(){ System.out.println("...show2...." ); } }; //匿名内部类对象调用方法 in.show1(); in.show2(); }}class InnerClassDemo{ public static void main(String[] args){ new Outer().method(); }}
异常的体系:
异常:是在运行时期发生的不正常情况。
在java中用类的形式对不正常情况进行了描述和封装对象。描述不正常的情况的类,就称为异常类。
- 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问题处理代码分离,提高阅读性。
- 其实异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述。
- 不同的问题用不同的类进行具体的描述。比如角标越界、空指针异常等等。
- 问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系。
不正常情况分成了两大类:
- 一般不可处理的:Error
特点:是由jvm抛出的严重性问题。
这种问题发生,一般不针对性处理,直接修改程序。 - 可以处理的:Exception
Throwable:
无论是error,还是异常、问题,问题发生就应该可以抛出,让调用者知道并处理。
该体系的特点就在于Throwable及其所有的子类都具有可抛性。
可抛性到底指的是什么呢?怎么体现可抛性呢?
其实是通过两个关键字来体现的:throws throw,凡是可以被这两个关键字所操作的类和对象都具备可抛性。
该体系的特点:
子类的后缀名都是用其父类名作为后缀,阅读性很强。
Throwable中的方法:
- getMessage():获取异常信息,返回字符串。
- toString():获取异常类名和异常信息,返回字符串。
- printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置(jvm默认异常处理机制),返回值void。
- printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。
通过throw将异常抛出。
throws和throw的区别:
- throws用于标识函数暴露出的异常类,并且可以抛出多个,用逗号分隔。throw用于抛出异常对象。
- thorws用在函数上,后面跟异常类名。throw用在函数内,后面跟异常对象。
定义功能方法时,需要把出现的问题暴露出来让调用者去处理,那么就通过throws在函数上标识。
在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
class Demo{ //在可能会发生异常的类的main函数上标明可能出现的异常 public static int method(int[] arr, int index)throws NullPointerException,ArrayIndexOutOfBoundsException{ if(arr == null){ //数组为空时,抛出空参数异常,通过字符串传入异常描述 throw new NullPointerException("数组的引用不能为空!"); } if(index >= arr.length ){ //角标越界,抛出角标越界异常,通过通过字符串传入异常描述 throw new ArrayIndexOutOfBoundsException("数组的角标越界:" + index); } return arr[index]; }}class ExceptionDemo{ public static void main(String[] args){ int[] arr = new int[3]; //异常发生时,会出现特定的异常信息 Demo.method(arr,30); }}
自定义异常:
可以自定义出现的问题
对于角标为负数的情况,可以用负数角标异常来表示,负数角标这种异常在java中并没有定义过。
那就按照java异常的创建思想,面向对象,将负数角标进行自定义描述,并封装成对象。
这种自定义的问题描述称为自定义异常。
P.S.
如果让一个类成为异常类,必须要继承异常体系,因为只有成为异常体系的子类才有资格具备可抛性,才可以被两个关键字所操作:throws、throw。
自定义类继承Exception或者其子类,通过构造函数定义异常信息。
//自定义类继承Exception类 Class DemoException extends Exception { //通过构造函数传入异常信息 DemoException(String message) { //Exception类中已有构造方法,直接父类完成构造方法就可以 super(message); } }
异常的分类:
编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。
这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。
这样的问题都可以针对性的处理。编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。
这种问题的发生,无法让功能继续,运算无法运行,更多是因为调用的原因导致的或者引发了内部状态的改变导致的。
那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行调整。
所以自定义异常时,要么继承Exception,要么继承RuntimeException。
异常处理:
try{ 可能会出现异常的代码}catch(异常类 变量){ 异常的处理方式}finally{ 一定会执行的代码}
P.S.
- finally代码块只有一种情况不会被执行,就是在之前执行了System.exit(0)。
- try是一个独立的代码块,在其中定义的变量只在该变量块中有效。
处理过程:
- try中检测到异常会将异常对象传递给catch
- catch捕获到异常进行处理。
- finally里通常用来关闭资源。比如:数据库资源,IO资源等。
异常处理的原则:
函数内容如果抛出需要检测的异常,那么函数上必须要声明。
否则,必须在函数内用try/catch捕捉,否则编译失败。如果调用到了声明异常的函数,要么try/catch,要么throws,否则编译失败。
什么时候catch,什么时候throws呢?
功能内容可以解决,用catch。
解决不了,用throws告诉调用者,由调用者解决。一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性处理。
内部有几个需要检测的异常,就抛几个异常,抛出几个,就catch几个。
try catch finally 代码块组合特点:
- try catch finally
- try catch(多个):当没有资源需要释放时,可以不用定义finally。
- try finally:异常无法直接catch处理,但是资源必须关闭。
class Demo{ public int show(int index)throws ArrayIndexOutOfBoundsException{ if(index < 0) throw new ArrayIndexOutOfBoundsException("越界啦!"); int[] arr = new int[3]; return arr[index]; }}class ExceptionDemo{ public static void main(String[] args){ Demo d = new Demo(); //try中存放可能出现异常的语句 try{ int num = d.show(-3); System.out.println("num = " + num); } //try中出现异常时,catch会捕捉相应异常进行处理 catch(ArrayIndexOutOfBoundsException e){ //打印异常信息 System.out.println(e.toString()); //退出jvm System.exit(0); } //通常用于关闭(释放)资源 finally{ //由于前面执行了System.exit(0);,故不会执行此语句。 System.out.println("finally"); } System.out.println("over"); }}
异常的注意事项:
- RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明。
- 子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。
- 如果父类抛出多个异常,那么子类只能抛出父类异常的子集。简单说:子类覆盖父类只能抛出父类的异常或者子类的子集。
- 如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛,就只能try。
包:
- 对类文件进行分类管理。
- 给类提供多层命名空间。
- 写在程序文件的第一行。
类名的全称的是:包名.类名。
包也是一种封装形式。
//包名,写在程序的开头,这时候编译出来的class文件会放在mypack文件夹下package mypack;class PackageDemo{ public static void main(String[] args){ System.out.println("Hello Package!"); }}
包之间的访问:
使用到另外的包中的类时,需要写类名的全称:包名.类名(packa.DemoA)。
- 被访问的包中的类权限必须是public的。
- 类中的成员的权限:public或者protected。
protected是为其他包中的子类提供的一种权限,不同包中的子类可以访问父类中被protected修饰的成员
包之间可以被访问的成员: public protected default private同一类中的成员 ok ok ok ok同一包中的成员 ok ok ok 不同包中的子类 ok ok 不同包中成员 ok
import:
导入:将某个包下类导入进来,为了简化类名的书写而产生,写在package下面,导入的类在调用时不用再写包名(如果各包中类有重名时,调用该类时就必须使用包名区别开)
导包语句如下:
import packa.test.java; //导入某个类
import packa.*; //导入包中的所有类(不包括多级目录下的)
import packa.abc.*; //导入二级目录下的所有类
Jar包:
Java的压缩包。
- 方便项目的携带。
- 方便于使用,只要在classpath设置jar路径即可。
数据库驱动,SSH框架等都是以jar包体现的。
Jar包的操作:
通过jar.exe工具对jar的操作。
DOS命令行操作:
创建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
- 黑马程序员——4.继承(接口、多态、内部类、异常、包)
- 黑马程序员——java-面向对象二(继承,多态,抽象,接口,包,内部类)
- 黑马程序员----继承3(内部类、异常、包)
- 黑马程序员——Java基础---继承,抽象,多态,接口,包,内部类
- 黑马程序员——继承、多态、内部类和接口
- 黑马程序员——继承、抽象、接口、多态、内部类
- 黑马程序员——java基础--抽象类、接口、多态、内部类、异常、包
- 黑马程序员——Java多态、内部类、异常、包
- 黑马程序员--Java基础--继承、抽象类、接口、内部类、异常、包
- 黑马程序员---多态,内部类,异常,包
- 黑马程序员——面向对象(多态,内部类、异常、包)
- 黑马程序员--内部类、包、异常、多态(Java)
- 黑马程序员——Java基础:内部类、异常、包
- 黑马程序员——内部类、异常、包
- 黑马程序员—面向对象(static,封装,继承,多态,内部类,抽象类,接口)总结
- 继承--抽象类/内部类/接口/多态/异常/包
- 黑马程序员——Java基础---多态、内部类、异常、包
- 黑马程序员——Java基础---多态、内部类、异常、包
- Bootstrap CSS——导航
- 抽象类与接口
- Bootstrap CSS——导航条
- Android常见分辨率及屏幕适配注意事项
- <PY>kNN
- 黑马程序员——4.继承(接口、多态、内部类、异常、包)
- JavaScript 模块
- sencha touch 在新版谷歌浏览器中painted事件无法触发解决方案以及carousel 控件、togglefield控件、滚动条失效
- C#学习之多线程开发技术(十)
- 一段好玩的程序
- 对某个Android应用的某一功能测试
- UVA11971 - Polygon
- 项目33.1利用循环求和
- hibernate单边的一对一关系