1. 注解
1.1 认识注解
Annotation,JDK1.5 提供的新技术
作用:
- 编译检查:比如 @SuppressWarnings, @Deprecated 和 @Override,分别代表压制警告信息、定义方法或类为过时的、重写标记
- 替换配置文件:使用反射来读取注解信息
- 目前大部分框架(如Spring)都使用了注解简化代码并提高编码的效率(使用注解之前使用的是xml进行配置)
@SuppressWarnings("all") // 压制警告信息
public class Student implements Comparable<Student> {
@Override // 实现方法
public int compareTo(Student o) {
return 0;
}
@Override // 重写方法
public String toString() {
return super.toString();
}
@Deprecated // 定义方法为过时的
public void method1() {
}
}
1.2 内置注解
主要有三个:
- @Override:检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中没有该方法时,会报编译错误。
- @Deprecated:标记过时方法。如果使用该方法,会报编译警告
- @SuppressWarnings:指示编译器去忽略注解中声明的警告
Java 7 之后,额外增加了 3 个注解:
- @SafeVarargs:Java 7开始,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告
- @FunctionalInterface:Java 8开始,标识一个匿名函数或函数式接口
- @Repeatable:Java 8开始,标识某注解可以在同一个声明上使用多次
1.3 元注解
是指注解的注解,在 JDK1.5 中提供了 4 个标准的,用来对注解类型进行注解的注解类
-
@Retention:用来约束注解的生命周期,分别有源码级别 (source),类文件级别 (class),运行时级别 (runtime)
若没有 @Retention,则默认是 RetentionPolicy.CLASS (类文件级别)
@Retention(RetentionPolicy.CLASS)
- SOURCE:源代码 (.java) 中有,到了 class 文件中就被丢弃了
- CLASS:源代码中有,class文件中有,但是运行时,不会加载到虚拟机中
- RUNTIME:注解在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息
-
@Target:用来约束注解可以应用的地方(如方法、类或字段),如果没有 @Target,则该 Annotation 可以用于任何地方
@Target(ElementType.METHOD)
/** Since: 1.5 */ public enum ElementType { /** 标明该注解可以用于类、接口(包括注解类型)或enum声明 */ TYPE, /** 标明该注解可以用于字段(域)声明,包括enum实例 */ FIELD, /** 用于方法 */ METHOD, /** 用于参数 */ PARAMETER, /** 用于构造函数 */ CONSTRUCTOR, /** 用于局部变量 */ LOCAL_VARIABLE, /** 可以用于注解(应用于另一个注解上) */ ANNOTATION_TYPE, /** 用于包 */ PACKAGE, /** * 用于类型参数 * @since 1.8 (1.8新加入) */ TYPE_PARAMETER, /** * 类型使用声明 * @since 1.8 (1.8新加入) */ TYPE_USE }
-
@Documented:标记这些注解是否包含在用户文档中
-
@Inherited:指示注解类型被自动继承
1.4 自定义注解
- 定义注解的关键字 @interface
- 注解内可以定义多个配置参数
数据类型 参数名()
- 如果只有一个配置参数,一般命名为 value,使用时可以省略
@Retention(RetentionPolicy.RUNTIME) // 生命周期
@Target({ElementType.METHOD, ElementType.TYPE}) // 在什么位置生效
public @interface MyAnnotation {
int id() default 0; // 配置参数
String name();
double[] source() default {};
String value(); // 默认配置参数
}
注意:
- 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,但是实现细节是由编译器完成的
- 通过 @interface 定义注解后,该注解不能继承其他注解或接口
1.5 使用反射读取注解
ORM:对象关系映射,即 Java的实体类与数据库表进行对应
- 类 ==》 表结构
- 属性 ==》 表的字段
- 对象 ==》 一条记录
模拟实现 MyBatis 的注解并使用反射读取
-
定义 @Table 注解
@Retention(RetentionPolicy.RUNTIME) // 一定要定义为 RUNTIME 时,不然反射无法读取到 @Target(ElementType.TYPE) public @interface Table { String name(); }
-
定义 @Column 注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Column { String name() default ""; // 使用时可以不用写 name,但是用反射读取时,需要判读,如果为空的,那么就用实体类的名字 String type(); int length(); int precision() default 0; }
-
在 实体类 上使用注解
/** * Mybatis * 1. 定义注解: Table、 Column * 2. 使用反射读取用户书写的注解 * * 程序员 * 1. 使用注解 */ @Table(name = "tb_student") public class Student { @Column(name = "sno", type = "int", length = 10) private int sno; @Column(name = "sname", type = "varchar", length = 20) private String name; @Column(name = "credit", type = "double", length = 5, precision = 2) private double score; }
-
使用反射读取注解的内容
// 读取注解!!!! // 1. 读取 Table 注解,定义在类上的 Class<Student> studentClass = Student.class; Table table = studentClass.getAnnotation(Table.class); // 通过类的class获取 System.out.println(table.name()); // 2. 读取 Column 注解 (name的),定义在字段上的,需要先获得字段 Field name = studentClass.getDeclaredField("name"); // 获取私有的属性 Column column = name.getAnnotation(Column.class); // 通过字段的获取 System.out.println(column.length()); // 后续就可以 根据读取的注解信息去创建数据库表 // 根据读取的注解信息对数据库表进行 CRUD 操作
2. JDK 新特性
2.1 JDK8 新特性
2.1.1 Lambda 表达式
可以取代大部分的匿名内部类,简化代码,尤其在集合的遍历和其他集合的操作中
// 使用线程执行一个任务【之前的方式】
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("+++++++++++++++++");
}
}).start();
// 使用 Lambda 表达式, () 里面为参数
new Thread(() -> System.out.println("+++++++++++++++++")).start();
// 使用TreeSet存储多个分数(逆序排列)
TreeSet<Integer> set = new TreeSet<>((o1, o2) -> {
// TODO 其他语句
return o2 - o1;
});
Collections.addAll(set,20, 30, 40, 70, 67, 25, 10, 80);
System.out.println(set);
Lambda 表达式是一种匿名函数(不是匿名内部类),简单地说,它是没有声明的方法,实质属于函数式编程的概念
注意
: Lambda 规定接口中只能有一个需要被实现的抽象方法,但是可以有其他方法,称为函数式接口
2.1.2 函数式接口
接口中,只能有一个抽象方法
,其他的可以有 default、static、Object里public方法等
JDK8 中,专门提供了 @FunctionalInterface 注解,用来进行编译检查(主要用在 Lambda 表达式上)
@FunctionalInterface
public interface FunInterface {
/**
* 抽象方法
*/
void method1();
/**
* JDK 8提供
*/
default void method2() { }
/**
* JDK 8提供
*/
static void method3() { }
/**
* Object类的
* @return
*/
@Override
int hashCode();
}
JDK 已经提供了大量的内置函数式接口,4个需要特别注意:
Consumer<T>
:消费型接口( void accept(T t) )。有参数,无返回值Supplier<T>
:供给型接口( T get() )。没有参数,有返回值Function<T, R>
:函数式接口( R apply(T t) )。有参数,有返回值。两种类型可相同、也可不同Predicate<T>
:断言型接口( boolean test(T t) )。有参数,返回一个 boolean 类型的值
List<String> list = new ArrayList<>();
Collections.addAll(list, "Java", "HTML", "MySQL", "SSM");
for (String s : list) {
System.out.println(s);
}
// 使用函数式接口!!!
Consumer consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
list.forEach(consumer); // 函数编程
==》 函数式接口结合 Lambda 接口: list.forEach((s) -> { System.out.println(s); });
Predicate filter = new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() == 4;
}
};
list.removeIf(filter);
// 使用 Lambda表达式的形式
list.removeIf((s) -> {return s.length() == 4; }); // 删除元素长度为 4 的数据
2.1.3 Stream API
Stream是对 List 等集合进行操作的,提高了编程效率,还提供了串行和并行两种模式,并行模式可以充分利用多核处理器的优势,使用 fork/join 框架,拆分处理过程
使用 Stream 的三大步骤:
- 创建 Stream:从一个数据源创建,如集合、数组中获取流
- 中间操作:对数据源的数据进行多种操作,产生一个中间操作链,此时所有的操作都不会执行
- 终止操作:执行中间操作链,产生结果
// 创建一个 Stream
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 60, 34, 32, 45, 84, 56, 96, 78);
Stream<Integer> stream = list.stream();
// 中间操作
stream.filter((source) -> {return source >= 60;}) // 过滤60分以下的
.sorted((source1, source2) -> { return source2 - source1; }) // 排序
.limit(3) // 只取前 3 个
.forEach((source) -> { System.out.println(source); }); // 执行中间操作,输出结果 【终止操作】
2.1.4 新的日期类
*属性* | *含义* |
---|---|
Instant | 代表的是时间戳 |
LocalDate | 代表日期,比如2020-01-14 |
LocalTime | 代表时刻,比如12:59:59 |
LocalDateTime | 代表具体时间 2020-01-12 12:22:26 |
ZonedDateTime | 代表一个包含时区的完整的日期时间,偏移量是以UTC/ 格林威治时间为基准的 |
Period | 代表时间段 |
ZoneOffset | 代表时区偏移量,比如:+8:00 |
Clock | 代表时钟,比如获取目前美国纽约的时间 |
LocalDate.now(); // 2022-03-20
LocalTime.now(); // 15:21:26.654
LocalDateTime.now(); // 2022-03-20 15:21:26.654
2.2 其他版本新特性
2.2.1 JDK9 新特性
-
模块化系统:如果一个项目有30个模块系统进行开发,某一个模块运行的时候,JVM只会启动和它有依赖的模块,并不会加载所有的模块到内存中(Java 9提供)
成员的作用范围,在当前包和当前项目之间又增加了一个层次:模块。
-
String 类的底层由 char数组 变为 byte数组,同时通过 coder 成员变量作为编码格式的标识,StringBuffer和StringBuilder也改变了
-
接口中可以定义 private 的非抽象方法:便于将接口中多个方法中的冗余代码进行提取,并且不对外公开,只在接口中使用。减少冗余、也实现了代码隐藏
2.2.2 JDK10 新特性
局部变量
类型推断:将前端思想 var 关键字,引入 Java 后端,自动检测所属类型
// int num = 10;
var num = 10;
// Scanner sc = new Scanner(System.in);
var sc = new Scanner(System.in);
// List<String> list = new ArrayList<String>();
var list = new ArrayList<String>(); // 类型推断时,后面的泛型不能省略
// Map<Integer,String> map = new HashMap<>();
var map = new HashMap<>();
map.put(1, "lw");
// Set<Map.Entry<Integer, String>> entries = map.entrySet();
var entries = map.entrySet();
// for ( Map.Entry<Integer, String> e : entries ) {
for( var e : entries ) {
System.out.println(e.getKey() + "\t" + e.getValue());
}
// int [] arr = new int[]{1,2,3};
var arr = new int[] {1,2,3};
for(var i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
2.2.3 JDK11 新特性
引入了两种新的垃圾收集器,包括也许是跨时代意义的 ZGC
-
Epsilon (A No-Op Garbage Collector)
回收工作不回收任何垃圾,只要保证内存足够大,不溢出,效率立马就高了
-
ZGC(A Scalable Low-Latency Garbage collector(Experimental))
- ZGC : 平均时间:1.091ms左右 最大时间:1.681ms
- GC: 平均时间 :156.806ms=0.15s 最大时间:543.846ms=0.5s
强调
:GC在清除垃圾的时候,其余所有线程都要停下来,这样GC才可以真正工作,以免造成混乱,这个过程就叫STW(stop the world),STW越长,就越影响应用的响应时间。启用ZGC的配置:
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
2.2.4 JDK12 新特性
switch 语句的变化:不再使用 break 关键字。 使用 case 条件 -> 语句
,表示如果条件匹配,则只执行后面的语句
String grade = "";
switch (score / 10) {
case 9, 10 -> grade = "A";
case 8 -> grade = "B";
case 7 -> grade = "C";
case 6 -> grade = "D";
case 0, 1, 2, 3, 4, 5 -> grade = "E";
default -> grade = "error";
}
3. 数据库建模
使用 PowerDesigner 软件进行操作
3.1 CDM
利用 实体 - 关系 图创建“概念数据模型” CDM
注意
:一对多可以使用外键来实现,多对多引出一张中间表然后结合外键实现
3.2 PDM
根据 CDM 产生基于特定数据库的“物理数据模型” PDM
3.3 生成SQL语句
根据 PDM 产生为 SQL 语句并可以文件形式存储
3.4 逆向生成
根据SQL文件,使用 power Designer 逆向生成 PDM,再由 PDM 逆向到 CDM
生成 PDM 文件后,再由 PDM 文件生成对应的 CDM 文件
生成为 CDM 文件后,再按照步骤生成对应数据库的 PDM 即可
3.5 三大范式
-
第一范式
- 最基本的范式
- 数据库表每一列都是不可分割基本数据项,同一列中不能有多个值(每列保持原子性)
-
第二范式
- 确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)
- 即在一个数据库表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中
错误示例:
应该提取出一张表来
-
第三范式
-
确保数据表中的每一列数据都和主键直接相关,而不能间接相关
优化之后的结构
-
属性不依赖于其他非主属性
-
4. UML建模
4.1 认识 UML
- Unified Modeling Language(UML)统一建模语言
- 一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持
- UML定义了 10 种模型图,对应软件设计开发的不同阶段
用例图
- 静态图:
类图
,包图,对象图 - 行为图:状态图和活动图
- 交互图:
顺序图
和协作图 - 实现图:组件图、部署图
4.2 类图—类和类的六种关系
-
继承关系
-
语法:extends
-
-
实现关系
-
语法: implements
-
-
依赖关系
-
语法:类B作为类A的方法的参数(或者局部变量)存在
-
-
关联关系 单向关联
双向关联-
语法:类B作为成员变量形成存在于类A中
-
比依赖关系强,必然的,长期的,强烈的
-
-
聚合关系
-
语法:类B作为成员变量形成存在于类A中
-
关联关系的一种特例(整体、部分可分离,整体的生命周期和部分的生命周期不同,has-a的关系)
-
计算机与CPU、公司与员工的关系
-
-
组合关系
-
语法:类B作为成员变量形成存在于类A中
-
整体和部分关系、整体部分不可分离、比聚合更强 ,contains-a的关系
-
人和大脑的关系
-
关系的强弱:组合 > 聚合 > 关联 > 依赖
4.3 用例图
用例图是指由参与者Actor(用小人表示)、用例Use Case(用椭圆表示),边界(每个系统的边界,用方框表示)以及它们之间的关系(关联、实现、包含、扩展)构成的用于描述系统功能的视图。展示了一个外部用户(参与者)能够观察到的系统功能模型图。
4.4 时序图
Sequence Diagram,又名序列图、顺序图,通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作
涉及的主要元素有:角色(Actor)、对象(Object)、生命线(LifeLine)、控制焦点(Activation)、消息(Message)、自关联消息
添加部门的时序图:
5. 业务流程图
业务流程图是一种描述业务管理系统内各单位、人员之间的业务关系,作业顺序和管理信息流向的图表,是相关业务流程的直观展示。
直白的说,业务流程图显示了数据或信息从一个任务传递到下一个任务直到完成时整个过程会发生的一切事情