概念
interface 定义了一些空的方法,如果要实现这个 interface,就要实现这些方法。
抽象方法 规定它的子类必须有这样一个方法。
注解 ?
封装 继承 多态 接口
5 - Java程序的基本结构
类与包
- 每个类都处在一个包中,包名由路径名决定。
- src/main/java 是默认包。
- java 最小的结构单元是类,类必须放在和它同名的.java文件中。
包的意义
- 区分同名,但是不同的类。
- 避免类的命名冲突,将同名类放入不同的包中。
- 全限定类名
package com.github.hcsp;
public class home {
com.github.hcsp.pet1.Cat cat1;
com.github.hcsp.pet1.Cat cat2;
}
package com.github.hcsp;
import com.github.hcsp.pet1.Cat;
public class home {
Cat cat1;
com.github.hcsp.pet2.Cat cat2; // 由于类名相同,所以这里不能再用简单类名。
}
在Java中引用第三方包
- java.lang 中的类不用导入包,可以直接使用。
- 第三方包需要在 pom.xml 中声明,然后下载包,再导入和使用。
方法、静态方法与静态成员变量
- 静态方法可以直接调用,不用通过实例对象。
- 静态成员变量是属于类的,独立于任何对象。
对象、构造器、成员变量
假如没有声明 constructor,则编译器会自动生成一个。
实例方法与空指针异常
在类中使用成员变量,在不引起歧义的情况下,可以省略 this。
包、类、静态方法、实例方法、静态成员、实例成员总结
包可以看做包裹类的文件夹。
类中没有用 static 声明的方法和变量是实例方法和实例变量。
对象与引用
字符串是引用类型。
6 - IDEA/Maven/调试器的基本使用
IDEA生产力翻倍的快捷键
万⽤键:Alt+Enter
Search everywhere:双击Shift
查看定义:Declaration
查看⽂件:Navigate - File
⾼级查找:Find in Path
快速⽣成:Generate
格式化:Reformat Code
优化导⼊语句:Optimize imports
导航:Navigate - Back/Forward
谁调⽤了这个⽅法:Call Hierarchy
所有的实现类:Implementation
⽂件⼤纲:File Structure
下⼀处错误:Next Highlighted Error
⾼级重命名:Rename
调试器快捷键:F5/F6/F7/F8
在IDEA中使用Git工具查找背锅侠
查找背锅侠:Annotate/Blame
查看当前⽂件的历史版本
⾼级筛选⽅式查找commit记录
显示差异:show diff
Open in GitHub
调试器入门与详解
- 条件断点(在断点处右键设置条件)
resume program: 全速运行到下一个断点。
10 - 对象系统基础
构造函数
- 新建对象的唯⼀途径。
- 如果没有任何构造器,编译器会暗中帮你⽣成⼀个。
- 新建过程:
在堆上分配空间
执⾏必要的初始化⼯作
执⾏构造器函数
⽅法的重载
- 如何区分同名的不同重载⽅法?
根据参数类型。 - 参数属于多种类型如何区分?
类型最匹配优先。 - 参数为null时可能导致匹配程度一致,如何处理?
将null强制类型转换。 - 如何为⽅法提供默认值?
只能通过重载实现。
构造函数的重载
用 this() 调用构造函数。
public class Cat {
int age = 1;
String name = "";
Cat() {
this("mimi");
}
Cat(String name) {
this(1, name);
}
Cat(int age, String name) {
this.age = age;
this.name = name;
}
}
对象的初始化
- 必要的初始化⼯作
静态成员的初始化
静态初始化块
成员的初始化
初始化块
对象的生命周期
- 如果⼀直新建对象,内存会不会爆?
可能会 - 那对象的内存什么时候被回收?
谁也不知道(内存充足的时候回收得慢,内存不足的时候回收得快) - 对象的内存如何被回收?
不⽤管,垃圾回收器帮你⼲ - JVM怎么知道哪个对象没有被⽤到?
通过引⽤链(GC Roots)。最常见的 roots 是方法栈中的方法里的局部变量,以这些变量为起点的引用链中的东西都不是垃圾,其余的是垃圾。
11 - 面向对象:封装与访问控制
封装及其必要性
- 什么是封装?
封装隐藏了内部实现细节,只暴露出接⼝。 - 不封装会怎么样?
暴露细节的结果就是⽆法变化。
软件的演进栗⼦:为原先的属性增加限制。
软件的演进栗⼦:修改某些属性。
封装的实现
- 访问控制符
public 任何⼈都能访问
protected 只有⼦类可以访问和同⼀个包的可以访问
package private 只有同⼀个包的类可以访问
private 只有⾃⼰可以访问 - JavaBean约定
所有属性为private
提供 getter 和 setter 等
设计模式实战:⼯⼚⽅法
- 使⽤静态⼯⼚⽅法代替构造器
- 将构造器私有化
类的访问限定符
- public 任何类都可以访问
- package private 同⼀个包的类可以访问
- 包之间是没有⽗⼦关系的
- private inner class 只能在同⼀个类中访问
- 了解:Java Platform Module System
设计模式实战:builder模式
函数参数过多时,在传入参数值时可以声明参数名字。
12 - 面向对象:组合与继承
- 继承的本质是提炼出公⽤代码,避免重复
- java 是单根继承的
类的结构与初始化顺序
- ⼦类拥有⽗类的⼀切数据和⾏为
- ⽗类先于⼦类
- 必须拥有匹配的构造器
- super关键字
实例⽅法的重写/覆盖
- 永远使⽤@Override注解来防⼿残
- 举个栗⼦
- String.equals
设计模式实战:模板方法
提供⼀个“模板”,实现可以覆盖模板的全部或者部分
向上/向下转型
- ⼀个⼦类类型的对象永远是⼀个⽗类类型的对象
- 正如⼀只猫同时也是⼀只动物,同时也是⼀个对象
- instanceof 判断类型
- null instanceof ? == false
- 因此,当需要⼀个⽗类型时,总可以传递⼀个⼦类型
- 但是,有的时候你必须进⾏⼀些转型
- 转型是不安全的
- 可能会失败
final关键字
- final声明变量,变量成为不可变的(必须初始化)
- 局部变量/⽅法参数
- 成员变量
- 常量与单例
- final在⽅法上的声明:禁⽌继承/覆盖/重写此⽅法
- final在类声明上的使⽤:禁⽌继承此类
- 继承提供了灵活性,也埋下了隐患
- 栗⼦:为什么String/Integer等类是final的?
组合
- 继承:is-a
- 组合:has-a
- 实际中,⼆者的界限有时候很难区分
- 如何操作:不继承,而是直接拿来其它类的方法去用。
13 面向对象:多态
什么是多态
- 实例⽅法默认是多态的
- 在运⾏时根据this来决定调⽤哪个⽅法
- 静态⽅法没有多态
- 参数静态绑定,接收者动态绑定
- 换句话说,多态只对⽅法的接收者⽣效
- ⼜换句话说,多态只选择接受者的类型,不选择参数的类型
设计模式实战:策略模式
- 策略模式栗⼦:打折策略
- JDK线程池中的策略ThreadPoolExecutor
多态实战
炒不同的菜的例子,将相同代码写在父类中实现复用。
14 面向对象:接口与抽象类
抽象类与接口入门
- 什么时候用抽象类?
需要复用代码。
抽象类与接口详解与实战
抽象类
- 不可实例化
- 可以实例化的东⻄⼀定要补全所有的⽅法体。
- 可以包含抽象⽅法(不需要方法体) - ⾮private/static(因为抽象方法就是要被继承、被子类实现)
- 可以包含普通类的任何东⻄
接⼝
- 接⼝部分的实现了多继承
- 接⼝不是类
- 接⼝的扩展
- 接⼝只代表⼀种功能
- ⼀个类只能继承⼀个类,但是却能实现若⼲的接⼝
接⼝可以包含什么
- 若⼲个⽅法(默认public)
- 若⼲个常量(默认public static final)
- extends 接⼝
- 默认⽅法
- Since Java 8
- 是⼀种妥协的产物
- 可以⽤来实现mixin
- 菱形继承
补充
- 抽象类继承一个接口,可以不实现接口的方法,留给子类去实现。
- 对接口中的方法,public、static、final 这些关键字都是多余的(必须是 puclic 非 static 非 final)。
- 对接口中的成员变量,public、static、final 这些关键字都是多余的(必须是 puclic、static、final)。
- 接口的默认方法可以在需求变化时给接口新增方法,不影响之前的代码。
- 抽象类和接口的共同点:
- 抽象,不可实例化
- 都可以包含抽象方法
- 抽象类和接口的不同点:
- 抽象类可以包含类的一切,接口只能包含受限的成员和方法
- 抽象类只能单一继承,接口可以多继承,甚至继承多次
- 实现一个接口代表着一种承诺,承诺这个类有这个接口定义的能力。
- 继承和接口都体现了多态。
实现一个文件过滤器
内部类详解
- ⽤途:实现更加精细的封装
- 可以访问外围类的实例⽅法
- ⾮静态内部类
- 和⼀个外围类实例相绑定
- 可以访问外围类实例的⽅法
- 静态内部类
- 不和外围类实例相绑定
- 不可以访问外围实例的⽅法
- 原则:永远使⽤静态内部类,除⾮编译报错
匿名内部类
- 直接通过new的⽅式创建的⽆名类