java知识总结——面向对象(二)
说明
本文仅仅为了博主面试时方便查阅与梳理相关知识,如果有错误与不到位的地方,欢迎大佬指点改正,谢谢!
阅读书籍:《java程序员面试笔试宝典》
一、多态的实现机制是什么?
多态是面向对象程序设计中代码重用的一个重要机制,它表示当同一个操作作用在不同对象时,会有不同的语义,从而会产生不同的结果。
多态的表现方式
1、方法的重载(overload)
重载是指同一个类中有多个同名的方法,但这些方法有着不同的参数,因此在编译时就可以确定到底调用哪个方法,它时一种编译时多态。重载可以被看作一个类中的方法多态性。
2、方法的覆盖(override)
子类可以覆盖父类的方法,因此同样的方法在会在父类与子类中有着不同的表现形式。
在java语言中,父类的引用变量不仅可以指向父类的实例对象,也可以指向其子类的实例对象。同样,接口的引用变量也可以指向其实现类的实例对象。
程序调用的方法在运行期才动态绑定(绑定指的是将一个方法调用和一个方法主体连接到一起),就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
通过动态绑定的方式实现了多态。由于只有在运行时才能确定调用哪个方法,因此通过方法覆盖实现的多态也被称为运行时多态。
类中的方法才有多态的概念,类中成员变量没有多态的概念。
成员变量的值取父类还是子类并不取决于创建对象的类型,而是取决于所定义变量的类型,这是在编译期间确定的。
java提供了哪两种用于多态的机制?
编译时多态和运行时多态。
编译时多态是通过方法的重载实现的,运行时多态是通过方法的覆盖(子类覆盖父类方法)实现的。
二、重载(overload)和覆盖(override)?
重载和覆盖是java多态性的不同表现方式。
1、概念
重载
是在一个类中多态性的体现,是指在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型。
覆盖
是指子类函数覆盖父类函数,覆盖一个方法并对其重写,以达到不同的作用。
2、注意事项
使用
重载
时,需要注意:
(1)重载是通过不同的方法参数(参数个数、参数类型、参数顺序)来区分的。
(2)不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。
(3)在继承时,如果父类方法的访问权限为private,那么就不能在子类对其重载;如果子类也定义了一个同名的函数,这只是一个新的方法,不会达到重载的效果。
使用
覆盖
时,需要注意:
(1)子类中的覆盖方法必须要和父类中被覆盖的方法有相同的函数名和参数。
(2)子类中的覆盖方法的返回值必须和父类中被覆盖的方法的返回值相同。
(3)子类中的覆盖方法所抛出的异常必须和父类中被覆盖的方法所抛出的异常一致。
(4)父类被覆盖的方法不能为private,负责其子类只是定义了一个方法,并没有对其覆盖。
3、重载与覆盖的区别
(1)覆盖是子类和父类的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。
(2)覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
(3)覆盖要求参数列表相同;重载要求参数列表不同。
(4)覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定;而重载关系是根据调用时的实参表与形参表来选择方法体的。
三、抽象类与接口
1、概念
抽象类
:如果一个类中包含抽象方法,那么这个类就是抽象类。
在Java语言中,可以通过把类或者类中的某些方法声明为abstract来表示一个类是抽象类。(abstract只能用来修饰类或者方法,不能用来修饰属性)
只要包含一个抽象方法的类的就必须被声明为抽象类,,抽象类可以声明方法的存在而不去实现它,被声明为抽象的方法不能包含方法体。在实现抽象类时,必须包含相同的或者更低的访问级别(public →protected→private)。抽象类在使用的过程中不能被实例化,但是可以创建一个对象使其指向具体子类的一个实例。抽象类的子类为父类中的所有方法提供具体的实现,否则他们也是抽象类。
接口
:就是指一个方法的集合,接口中的所有方法都没有方法体。
在Java语言中,接口是通过关键字interface来实现的。
接口可以看做是抽象类的变体。接口中的所有方法都是抽象的,可以通过接口来间接地实现多重继承。接口中的成员变量都是static final类型。
抽象类与接口都是支持抽象类定义的两种机制。抽象类表示的是一个实体,接口表示的是一个概念。
由于抽象类可以包含部分方法的实现,因此,在一些场合下抽象类比接口存在更多的优势。
2、接口与抽象类的相同点
(1)都不能被实例化;
(2)接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法才能被实例化。
3、接口与抽象类的不同点
(1)Java8之前,接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。
(2)接口需要实现(用implements),抽象类只能被继承(用extends)。一个类可以实现多个接口,但一个类只能继承一个抽象类,因此使用接口可以间接地达到多重继承的目的。
(3)接口强调特定功能的实现,其设计理念是“has-a”关系;而抽象类强调所属关系,其设计理念是“is-a”关系。
(4)接口中定义的成员变量默认为public static final,只能够有静态的不能被修改的数据成员,而且必须给其赋初值,其所有成员变量的方法都是public、static的,而且只能被这两个关键字修饰。而抽象类可以有自己的数据成员变量,也可以有非抽象的成员方法,而且抽象类中的成员变量默认为default(本报可见),也可以被定义为private、protected、public,这些成员变量可以在子类中被重新定义,也可以被重新赋值,抽象类中的抽象方法(用abstract修饰),不能用private、static、synchronized、native等访问修饰符修饰,同时方法必须以分号结尾,并且不带花括号。当功能需要积累时,用抽象类;不需要积累时,用接口。
(5)接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。
接口是一种的特殊形式的抽象类,使用接口完全有可能实现与抽象类相同的操作。
4、用途
抽象类多用于在同类事物中有无法具体描述的方法符场景,所以当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类;
接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。
接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的main方法。
四、Java内部类
1、概念
内部类:在java语言中,可以把一个类定义到另外一个类的内部,在类里面的这个类就叫做内部类,外面的类叫做外部类。
2、分类
(1)静态内部类
指被声明为static的内部类,它可以不依赖于外部类实例而被实例化,通常的内部类需要在外部类实例化后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法(包括私有类型)。
(2)成员内部类
去掉“static”关键字的静态内部类,就是成员内部类。可以自由地引用外部类的属性和方法,无论这些属性和方法是静态的还是非静态的。但是成员内部类与一个实例绑定在了一起,不可以定义静态的属性和方法。只有在外部的类被实例化后,这个类才能被实例化。
注意:非静态内部类中不能有静态成员。
(3)局部内部类
局部内部类指的是定义在一个代码块内的类,它的作用范围为其所在的代码块,是内部类中最少使用的一种的类型。局部内部类像局部变量一样,不能被public、protected、private以及static修饰,只能访问方法中定义为final类型的局部变量。对一个静态内部类,去掉其声明中的“static”关键字,将其定义移入其外部类的静态方法或静态初始化代码中就成为了局部静态内部类。
注意:局部静态内部类与静态内部类的基本特性相同;局部内部类与内部类的基本特性相同。
(4)匿名内部类
匿名内部类是一种没有类名的内部类,不是用关键字class、extends、implements,没有构造函数,它必须继承(extends)其他类或实现其他接口。匿名内部类的好处是代码更加简洁,紧凑,但带来的问题是易读性下降。一般用于GUI(图形用户界面)编程中实现事件处理。
使用匿名内部类的几个原则:
①匿名内部类中不能有构造函数;
②匿名内部类不能定义静态成员、方法和类;
③匿名内部类不能是public、protected、private、static;
④只能创建匿名内部类的一个实例;
⑤一个匿名内部类一定是在new的后面,这个匿名内部类必须继承一个父类或实现一个接口;
⑥因为匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
五、this与super
1、this
this用来指向当前实例对象,它的主要作用用来区分对象的成员变量与方法的形参(当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量)。
2、super
super用来访问父类的方法或成员变量。当子类的方法或成员变量与父类有相同名字时也会覆盖父类的方法与成员变量,想要访问父类的方法或成员变量只能通过super关键字来访问。
注意:当子类构造函数需要显式调用父类构造函数时,super()必须为构造函数中的第一条语句。