11_Package包,抽象类,接口,多态
Java SE Package包,抽象类,接口,多态
Package包
包本质来说就是文件夹, 用来管理类文件
建包的语法格式:package 域名倒写.自定义名称。 通常小写。
导包
- 相同包下的类可以直接访问,不同包下的类必须导包,才可以使用。 格式:import 包名.类名;
- 假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。
具体:
如果有相同的两个类Student,在不同包下,此时第一次调用会导包,但是如果需要用到另一个***.***.b.Student时,就要用全类名创建对象:
1 | |
同理,如果创建类名为Scanner的类,和util中的重名,将无法正常导包使用Scanner,需要用下述的 全类名 格式
1 | |
抽象类
- 抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法。
定义格式:public abstract 返回值类型 方法名(参数列表);
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
定义格式:public abstract class 类名{}
1 | |
注意事项
1.抽象类不能实例化
如果抽象类允许创建对象, 就可以调用内部没有方法体的抽象方法,没有意义
2.抽象类存在构造方法
交给子类, 通过super进行访问,进行初始化等功能实现
3.抽象类中可以存在普通方法
子类继承来使用
4.抽象类的子类
1). 要么重写抽象类中的所有抽象方法
2). 要么成为抽象类
1 | |
abstract 关键字的冲突
- final:被 abstract 修饰的方法,强制要求子类重写,被 final 修饰的方法子类不能重写
- private:被 abstract 修饰的方法,强制要求子类重写,被 private 修饰的方法子类不能重写
- static:被 static 修饰的方法可以类名调用,类名调用抽象方法没有意义
接口
体现的思想是对规则的声明
思路: 如果发现一个类, 所有的组成, 都是抽象方法*[ 没有成员变量,没有普通方法时 ]*
这种类, 我们通常会设计为Java中的接口, 因为现在这个类存在的唯一价值, 就只是声明规则了
定义格式: interface 接口名 {}
注意: 接口不允许实例化
接口和类之间是实现关系, 通过implements关键字来完成
1 | |
实现类(接口的子类)的两种方式:
1. 重写所有抽象方法
- 将实现类变成抽象类 [此时还是不能实例化,要再继承类,一般不用]
1 | |
所有的类都会默认继承Object类;
1 | |
接口的成员特点
1.成员变量 : 只能定义常量, 因为系统会默认加入三个关键字
public static final 这三个关键字没有顺序关系
2.成员方法 : 只能是抽象方法, 因为系统会默认加入两个关键字 注:JDK8 和 JDK9 中有一些新特性 见后续补充
public abstract
3.构造方法 : 没有
即
1 | |
接口和类之间的各种关系 :
类和类之间 : 继承关系, 只支持单继承, 不支持多继承, 但是可以多层继承
类和接口之间 : 实现关系, 可以单实现, 多实现, 同时可以在继承一个类的同时, 实现多个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class Fu {
public void show() {
System.out.println("此时不需要再重写了");
}
}
interface A {
void showA();
void show();
}
interface B {
void showB();
void show();
}
class Zi extends Fu implements A, B {
@Override
public void showA() { //interface A中的方法
}
@Override
public void showB() { //interface B中的方法
}
//注:A,B接口中show()同名,那么只需要实现一个即可,已经继承fu类了,所以不需要在此再次实现
}接口和接口之间 : 继承关系, 可以单继承, 也可以多继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16interface InterA {
void show();
}
interface InterB {
void show();
}
interface InterC extends InterA, InterB {
void show();
}
class InterCImpl implements InterC {
@Override
public void show() {} //同名,实现一个就是实现所有的逻辑了; 如果方法不同名,每一个接口的抽象方法都要实现;
}
抽象类&接口 对比
抽象类 : 对事物做抽象 (描述事物)
接口 : 对行为抽象 (制定规则)
- 成员变量 :
抽象类 : 可以定义变量, 也可以定义常量
接口 : 只能定义常量
- 成员方法
抽象类 : 可以是定义具体方法, 也可以定义抽象方法
接口 : 只能定义抽象方法
- 构造方法
抽象类 : 有
接口 : 没有
注:接口可以为程序制定规则, 代码更加规范;如果有抽象方法没实现,就无法创建类
多态
同一个行为具有多个不同表现形式或形态的能力
多态的前提 :
- 有继承 / 实现关系
- 有方法重写
- 有父类引用指向子类对象
多态的好处
提高了程序的扩展性
对象多态
Animal a = new Dog();
Animal b = new Cat();
好处: 方法的形参定义为父类类型, 这个方法可以接收该父类的任意子类对象行为多态
好处: 同一个方法, 具有多种不同表现形式/形态的能力
1 | |
多态的成员访问特点
- 成员变量:编译看左边(父类),执行看左边(父类)
- 成员方法:编译看左边(父类),执行看右边(子类)
在编译的时候, 会检查父类中有没有这个方法
没有 : 编译出错
有 : 编译通过, 但是运行的时候, 一定会执行子类的方法逻辑
原因: 担心你调用的方法, 在父类中是一个抽象方法
1 | |
1 | |
- 多态创建对象, 调用静态成员时 : 看类名
静态的成员, 推荐类名进行调用
原因: 静态的成员, 可以使用对象名调用, 但这是一种假象;实际上生成字节码文件后, 会自动将对象名调用, 改成类名调用.
多态的弊端
不能使用子类的特有成员
解决方法——多态中的转型
向上转型
从子到父(父类引用指向子类对象)
1 | |
- 向下转型
从父到子(将父类引用所指向的对象, 转交给子类类型)
1 | |
问题:如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
判断工具:关键字 instanceof
使用格式: 对象名 instanceof 类型
判断一个对象是否是一个类的实例
即:判断关键字左边的对象,是否是右边的类型,返回boolean类型结果
实例:
实现支付功能,需要支持多种支付方式:支付平台支付、银行卡网银支付、信用卡快捷支付,选择支付方式和输入金额后,输出为:通过—支付了—元。
1 | |
1 | |
1 | |
1 | |
1 | |
补充:JDK 8,9对接口的新特性
JDK8版本接口特性:
1.允许定义非抽象方法, 需要加入default关键字
作用: 解决接口的升级问题[ 接口中添加新方法,实现更多功能 , 不影响之前的 ]
注意事项:
- public可以省略, 但是default不能省略
- 默认方法, 实现类是允许重写的, 但是需要去掉default关键字
- 如果实现了多个接口, 多个接口中存在相同的默认方法, 实现类必须重写默认方法 [因为不知道要实现哪一个默认方法,必须重写]
2.允许定义静态方法
理解: 既然接口已经允许方法带有方法体了, 干脆也放开静态方法, 可以类名调用
注意事项:
1.public可以省略, 但是static不能省略
2.接口中的静态方法, 只允许接口名进行调用, 不允许实现类通过对象调用
1 | |
JDK9 接口特性
接口中允许定义 private 私有方法
接口中静态方法的定义格式:
格式1:private 返回值类型 方法名(参数列表) {}
范例1:private void show() {}
格式2:private static 返回值类型 方法名(参数列表) {}
范例2:private static void method() {}
1 | |
好处:抽取log()方法为private static,这样可以在内部静态方法中使用,减少冗余代码并且不被其他调用。