类的继承
继承的特点
单继承
class A{}
class B extends A{} ️
class C extends A,B{} ️
多级继承
-
Java.long.Object
class A{}
class B extends A {} ️
class C extends B {} ️
多子类
抽象类 (abstract)
-
- 子类就是一个父类,所以是继承关系。
- 子类中共有的方法,但是所有子类都不一样
格式
含有抽象方法的类,必须是抽象类
public abstract class Animal{
//抽象方法定义
public abstract void eat();
//普通方法定义
public void move (){
}
}
- 不能直接使用new关键字
- 必须用子类继承抽象父类
- 子类必须实现父类中所有的抽象方法
- 创建子类对象进行使用
public class Cat extends Animal{
@Override
public void eat(){
sout("猫吃鱼!");
}
}
Cat cat = new Cat;
cat.eat();
注意
- 抽象类不能创建对象
- 抽象类中,可以有构造函数,是供子类创建对象时,初始化父类成员使用的。
- 如果构造函数是抽象的,则子类中用 supper()调用
- 先创建父类
- 后创建子类
- 抽象类不一定有抽象方法,没有抽象方法的抽象类,也不能直接创建对象
- 抽象类的子类,必须实现父类所有的抽象方法,否则依然是一个抽象类
发红包案例
分析
红包分为普通红包和运气红包
- 群主有钱
- 成员收红包,余额增加
- 类: 群主、普通成员、用户类
- 共性:姓名、余额
- 独有:
- 群主: 发红包
- 成员: 收红包
- 发红包
- 返回值类型: ArrayList
- 方法名称: send
- 参数列表:
- 总金额: int totalMoney
- 分数: int count
public ArrayList <Integer> send (int totalMoney,int count){
...
}
- 收红包
- 返回值类型:void
- 方法名:receive
- 参数列表:ArrayList
public void receive (ArrayList <Integer> list){
...
}
接口(interface)
接口就是一个 公共的规范接口
符合标准 -> 通用
关键字 interface -> .class 文件
- 包含的内容
- 常量
- 抽象方法
- 默认方法 JDK8
- 静态方法 JDK8
- 私有方法 JDK9
接口是引用类型
public interface 接口名称{
//接口内容
}
- 定义
- 注意:
- 接口不能直接使用,必须使用一个实现类来实现接口
public class 实现类名 implements 接口名称{ }
- 实现类必须重写 接口中所有的抽象类
- 创建实现类使用接口
- 如果有抽象方法没有重写,那么该类就是一个抽象类
- 接口不能直接使用,必须使用一个实现类来实现接口
默认方法
-
从JDK8 允许默认方法
-
可以解决接口升级问题
- 如果接口添加抽象方法,就会导致所有子类全部实现
- 使用default 方法,在接口中实现方法体
-
使用
public default 返回值 方法名称(方法参数){
//可以有方法体
//public 可以省略
}
- 默认方法会被实现类所继承
- 也可被实现类重写
静态方法
static :共享方法
public static void test(){
//带有方法体
}
- 接口名称可以直接 . 调用
- 不能通过实现类调用静态方法
- 实现多个接口,静态方法可能发生冲突
- 不需要创建实现类对象
私有方法
一种安全机制
- 普通
- 多个默认方法之间重复代码问题
private void test(){
}
- 静态
- 多个静态方法之间重复代码问题
private static void test(){
}
常量
接口中够可以定义成员"变量" public static final (省略依旧)
不可修改
public static final int x = 1;
共有、接口名称 . 访问
- 常量必须赋值
- 完全大写
- 下划线连接单词
小结
- 在Java 9+ 版本中,接口的内容有:
- 成员变量其实是称量,格式:
- [public] [static] [final] 数据类型 常量名 = 数据值;
- 注意:
- 常量必须进行赋值,且不可改变
- 常量名完全大写,用下划线分割
- 接口中最重要的是抽象方法,格式:
- [public] [abstract] 返回值类型 方法名称 (参数列表);
- 注意:
- 实现类必须实现所有的抽象方法
- 从Java8 开始 ,允许定义默认方法,格式:
- [public] default 返回值类型 方法名称(参数列表){ 方法体 }
- 注意:
- 默认方法也可以被覆盖重写
- 从Java8 开始, 允许定义静态方法,格式:
- [public] static 返回值类型 方法名称(参数列表) { 方法体 }
- 注意:
- 通过接口名称直接调用,不能通过实现类进行调用
- 从Java9 开始, 允许定义私有方法,格式:
- 普通私有方法:private 返回值类型 方法名称(参数列表){ 方法体 }
- 静态私有方法:private static 返回值类型 方法名称(参数列表){ 方法体 }
- 注意:
- private 的方法只能在接口内调用,不能被实现类和别人使用。
注意
接口不能有静态代码块和构造方法 抽象类有构造方法
一个类的直接父类只有一个,但是可以实现多个接口
public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB{}
两个抽象方法重名,只需覆盖重写一次即可
重名的默认方法,实现类一定对重复的覆盖重写
一个类如果直接父类中的方法,和接口中的方法发生冲突,直接使用父类的方法
继承 优先于 接口实现
-
类与类是单继承的
-
类与接口是多实现的
-
接口与接口之间是多继承的
- 多个父接口当中的抽象方法冲突可以
- 多个父接口当中的默认方法冲突,那么子接口必须进行默认方法覆盖,【必须带着 default 关键字】
函数式接口
-
有且只有一个抽象方法的接口,称之为函数式接口
可以包含其他的方法(默认方法、静态方法、私有方法)
函数式编程 Lambda
/**
@FunctionalInterface
可以监测是否是一个函数式接口
*/
@FunctionalInterface
public interface MyFocationInterface{
}
public abstract void method();
使用
一般可以作为参数和返回值来使用
参数
//定义一个方法,参数使用函数式接口
public static void test (MyFunctionInterface myInter){
myInter.method();
}
main(){
//调用 show 方法,参数使用函数式接口的实现类对象
show (new MyFunctionInterfaceImpl());
//调用show方法 ,参数使用 匿名内部类
show(new MyFunctionInterface(){
@Override
public void method(){
sout("使用匿名内部类重写接口中的抽象方法!");
}
});
//调用show方法 ,参数使用 Lambda 表达式
show(()-> sout("Lambda实现接口的抽象方法!"));
}
匿名内部类生成 .class 文件
Lambda表达式不会生成 .class 文件
函数式编程
Lambda 的延迟执行
日志可以快速定位问题
package Demo4.Lambda;
/*
日志案例
性能浪费的问题:
调用 showLog 传递的第二个参数是一个拼接后的字符串
先拼接 后调用方法
showLog 如果等级不是 1 级,不会输出,字符串白 拼接了,浪费
使用Lambda 特性进行 优化
使用前提:必须存在函数式接口
延迟加载
*/
public class Demo01Logger {
//定义一个根据日志等级,显示日志信息
public static void showLog(int level,String message) {
if(level == 1){
System.out.println(message);
}
}
public static void main(String[] args) {
//定义三个日志信息
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
//调用showLog 方法,传递参数
showLog(1,msg1+msg2+msg3);
//========================
//Lambda 优化
showLog2(1,()->msg1+msg2+msg3);
}
//传递等级 和 接口
public static void showLog2(int level ,MessageBuilder builder){
if(level == 1){
System.out.println(builder.builderMessage());
}
}
}
@FunctionalInterface
public interface MessageBuilder {
public abstract String builderMessage();
}
使用 Lambda 表达式 作为参数传递,仅仅把参数传递到showLog 中
只有满足条件,日志的等级为1
才会调用接口 MessageBuilder 中的方法 BuilderMessage
才会进行字符串的拼接
如果条件不满足 level != 1
MessageBuilder 中的方法不会调用
资源不会浪费
Runable 是一个 函数式接口
public class RunnableLambda {
public static void threadRun (Runnable run){
new Thread(run).start();
}
public static void main(String[] args) {
//匿名内部类
threadRun(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +"--> 线程启动!");
}
});
//Lambda 表达式
threadRun(()-> System.out.println(Thread.currentThread().getName() +"--> 线程启动!"));
new Thread(()->System.out.println(Thread.currentThread().getName() +"--> 线程启动!")).start();
}
}
返回值
Comparator 也是一个 函数式借口