目录
1. final关键字
1). final修饰范围
2). final修饰成员变量
1.抽象类(abstract class)
1). 抽象方法和抽象类产生的背景
2). 抽象类的特点
3). 特殊的抽象类 (没有抽象方法)
4). 多个类的功能向上抽取之后,如何确定方法是否该是抽象的
3.接口(interface)
1). 接口中成员格式的特点
2). 接口和实现类中的方法
3). 多个接口和一个类的关系
4). 接口的语义
5). 设计时:抽象类和接口中功能定义
6). 接口与接口之间的关系
final可以修饰的元素:类、函数、变量
(1). 被final修饰的类不可以被继承;
(2). 被final修饰的函数不可以被重写;
(3). 被final修饰的变量不可以被修改值(常量)。
被final修饰的变量是一个常量,只能被赋值一次。final即可以修饰成员变量,又可以修饰局部变量。
【代码规范】如果是常量。常量的名字要求全部大写,单词之间用下划线“_”隔开。
【1】. 成员常量:final修饰成员变量的时候,此时这个成员变量就是成员常量。因为只能赋值一次,所以所有的对象的这个成员常量的值都是一样的。为了节省内存,成员常量中的final通常也配合static一起修饰这个成员常量。“final static ….”
【2】. 全局常量:当在“final static ….”前面的访问修饰符public之后,这个常量的访问权限也是足够大的。有了public,自然可以直接访问,所以不用对这个常量设置读取方法Getter。由于也不能赋值,所以,也没有Setter。当构成“public final static XX”这个时候就是全局成员常量。
当多个类(dog、cat)出现相同的功能(奔跑、跳跃),但是功能的主体(一个是dog,一个是cat)不一样,这时候,可以对多个类的相同功能向上抽取=>抽取到仅仅定义功能抽象类(animal)。
[1]. 此时就可以用 abstract 这个关键字来修饰这个方法(功能)=>抽象方法
[2]. 抽象方法必须定义在抽象类中=>抽象类
[1]. 抽象方法必须定义在抽象类中;
[2]. 抽象方法和抽象类必须都被abstract关键字来修饰;
[3]. 抽象类不可以通过new来建立实体;
[4]. 抽象类中的方法要被调用,必须子类重写抽象类中的全部抽象方法之后,建立子类对象才能调用这个抽象类的方法;
[5]. 继承抽象类的子类如果没有完全覆盖所有的抽象方法,那么这个子类仍然是抽象类。
抽象类中没有定义任何抽象方法,目的是不让建立子类对象。
例: Java核心类库中的WindowAdapter是一个抽象类,他全部重写了WindowEvent接口中的七个抽象方法,但是这些抽象方法在WindowAdapter中的实现体全部是空实现体。原因就是用户直接构建实现WindowEvent的子类的话,要重写全部的七个抽象方法。但是这些抽象方法未必都能用得上。所以,为了方便用户使用WindowEvent,特意定义了WindowAdapter以全部的空实现体来实现接口WindowEvent。但是,空的实现体所在的WindowAdapter如果实例化成相应的对象的话,是没有意义的,因为所有的成员方法都是空的实现体。所以这个没有抽象方法的WindowAdapter类被定义成抽象类,抽象类不能被new。但是继承这个WindowAdapter之后的子类,可以根据自己的需求来重写七个方法中的自己所需的部分,便简化了开发。
[1]. 如果功能相同,但是功能的实现不同 ===>定义成抽象方法
[2]. 如果功能相同,功能的实现也相同 ===>定义成普通具体方法
[1]. 接口中可以定义常量和抽象方法;
[2]. 接口中的成员都有固定的修饰符(少什么,编译时就会补全什么):
{1}. 接口中常量默认修饰符:public final static ===>默认是全局常量
{2}. 接口中方法默认修饰符:public abstract===>默认是公共抽象方法
[1]. 接口中的方法的默认访问修饰符是 public;
[2]. 接口的实现类对应的方法的访问修饰符必须是 public。
PS:子类重写父类的方法的访问权限 >= 父类/接口中的方法的访问权限
[1]. 一个子类可以实现多个接口;
[2]. 当多个接口存在共同的抽象方法的时候并且都被同一个实现类实现,那么这个实现类对多个接口的共同的抽象方法仅仅实现一次即可。
[1]. class A extends B: 继承的语义 => A is a B
[2]. class A implements C: 实现的语义 => A is like a C
[1]. 基本功能定义在抽象类/类中;
[2]. 扩展功能定义在接口中。
(1). 接口与接口之间可以是继承关系;
(2). 接口之间支持多继承;
interface A{ void methodA(); } interface B{ void methodB(); } interface C extends A,B{ void methodC(); }
(3). 接口在多继承的时候,要保证如果多个接口中存在同名的方法的时候,必须保证返回值一致,否则编译报错。
{1}. 错误案例1:
interface A{ void methodA(); } interface B{ void methodB(); } interface C extends A,B{ void methodC(); int methodA();//编译报错 }
PS:编译报错,因为是继承,并且同方法名和参数列表一致,JavaC认为是重写但是返回值类型不一样,所以编译报错。
{2}. 错误案例2
interface A{ void methodA(); } interface B{ void methodB(); int methodA(); } interface C extends A,B{//编译报错 void methodC(); }
PS:接口C报错,C继承两个接口中的方法,这说明C中存在两个方法,void methodA(){…}
和int methodA(){…},同方法名,同参数列表,java认为C继承到的一个方法是对继承到的另一
个方法的重写,但是由于返回值类型不一致,所以编译报错。
【面试题】Java支持多继承么?
Java是支持多继承的,但是这种多继承仅仅是存在Java中的接口之间,除此之后,Java没有直接的多继承,Java类之间是通过一个类实现多个接口来体现多继承的思想。