java基础-枚举、注解、单元测试、日志
13-4-1枚举
17-枚举-什么是枚举
用来表示一些固定的值,用常量有以下问题:
- 代码不够简洁。
- 不同类型的数据是通过名字区分的。
- 不安全,可能被使用的值被用来做了运算。
为了简洁表示一些固定的值,Java提供了枚举。
将变量的值一一列出,变量的值只限于列举出来的值的范围内。
18-枚举-定义格式
格式:
public enum s{
枚举项1,枚举项2,枚举项3;
}
19-枚举-枚举的特点
所有枚举都是
Enum
的子类可以通过
枚举名称.枚举项名称
访问指定的枚举项每个枚举项是该枚举的一个对象
public class EnumDemo { public static void main(String[] args) { Season spring = Season.SPRING; System.out.println(spring instanceof Season); Class<? extends Season> springClass = spring.getClass(); Constructor<?>[] constructors = springClass.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("constructor = " + constructor); } } }
枚举是类,可以定义成员变量
枚举类的第一行必须是枚举项,最后一个枚举项的分号可以省略,如果后面还有代码则不能省略
枚举可以有构造器,必须是private、默认也是private。枚举项的用法比较特殊:
枚举("")
public enum Season { // 每一个枚举项,其实就是一个枚举的对象,枚举项后面什么都不写,默认调用空参构造,也可以指定调用有参构造 SPRING(),SUMMER,AUTUMN,WINTER; private String name; /** * 空参构造 */ private Season(){ } /** * 构造函数只能是私有的,默认也是私有的 * * @param name 名字 */ private Season(String name) { this.name = name; } }
枚举也可以有抽象方法,但枚举项必须重新该方法
public enum Season { // 每一个枚举项,其实就是一个枚举的对象,枚举项后面什么都不写,默认调用空参构造,也可以指定调用有参构造 SPRING(){ // 如果枚举类中有抽象方法,那么枚举项中必须重写 @Override public void show() { System.out.println(this.name); } },SUMMER{ @Override public void show() { } },AUTUMN{ @Override public void show() { } },WINTER{ @Override public void show() { } }; public String name; /** * 空参构造 */ private Season(){ } /** * 构造函数只能是私有的,默认也是私有的 * * @param name 名字 */ private Season(String name) { this.name = name; } public abstract void show(); }
20-枚举-枚举的方法
13-4-2-注解
21-注解-注解的优势
在配置servlet
时,需要配置很多:
使用注解以后,就不需要写这么多了:
22-注解-注解的概述
这就是一个注解:
注解的主要作用:对我们的程序进行标注和解释。
Java自带的注解举例:
23-注解-自定义注解
格式:
public @interface 注解名称{
public 属性类型 属性名称() default 默认值;
}
注解类型可以是:
- 基本数据类型
- String
- Class
- 注解
- 枚举
- 以上类型的一位数组
例子:
public @interface Anno1 {
// 定义一个基本数据类型
public int a() default 1;
// 定义一个String类型
public String name();
// 定义一个Class类型
public Class clazz() default Anno2.class;
// 定义一个注解类型
public Anno2 anno() default @Anno2;
// 定义一个枚举类型
public Season season() default Season.SPRING;
// 定义一个一位数组
public int[] ints() default {1,2,3};
}
public @interface Anno2 {
}
/**
* 在使用注解时,如果注解中的属性没有给定默认值,需要手动传参,给定值,不然会报错
*
* @author lzc
* @date 2023/07/12
*/
@Anno1(name="lzc")
public class AnnoDemo {
public static void main(String[] args) {
}
}
21-注解-特殊属性value
在使用注解时,如果我们只需要给注解的value属性赋值,那么value可以省略。
如:其他属性都赋了默认值,那么在使用注解时,可以不指定注解属性名称,默认就是给value
属性赋值
25-注解-自定义注解练习
需求:
自定义一个注解,用于指定类的方法上,如果某一个类的方法上使用了该注解,就执行该方法。
自定义注解:
/**
* 自定义注解,加了该注解的方法会被执行
* @Retention(RetentionPolicy.RUNTIME)表示该注解的生命周期
* @author lzc
* @date 2023/07/12
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface LzcTest {
}
类:
public class UserTest {
public void show(){
System.out.println("show 运行");
}
@LzcTest
public void method01(){
System.out.println("method01 运行");
}
@LzcTest
public void method02(){
System.out.println("method02 运行");
}
}
启动类:
public class AnnoDemo02 {
public static void main(String[] args) throws Exception {
// 获取class
Class<?> clazz = Class.forName("com.lzc.enums.annotation.annodemo02.UserTest");
// 调用空参构造创建对象
Object instance = clazz.newInstance();
// 获取注解上的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
// 遍历方法
for (Method declaredMethod : declaredMethods) {
// 判断方法上是否有该注解
if (declaredMethod.isAnnotationPresent(LzcTest.class)){
declaredMethod.setAccessible(true);
declaredMethod.invoke(instance);
}
}
}
}
运行结果:
26-注解-元注解
元注解:描述注解的注解。
@Target
可以写如下参数:
@Retention
如果不写,默认是源码阶段:
@Inherited
该注解可以被继承:子类会继承父类的该注解。
验证:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited()
public @interface Anno03 {
}
@Anno03
public class Person {
}
public class Student extends Person{
}
public class AnnoDemo03 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.lzc.enums.annotation.annodemo03.Student");
System.out.println("clazz.isAnnotationPresent(Anno03.class) = " + clazz.isAnnotationPresent(Anno03.class));
}
}
13-5-1-单元测试
01-单元测试-概述
之前是把所有代码写完再进行测试,并不是很好,单元测试可以更早定位问题,也避免了由于代码多无法准确定位错误代码的问题。
Junit特点:
- 开放源代码的测试工具
- 提供注解来识别测试方法
- 编写代码更快,还能提高质量
- 代码简洁,花费时间少
- 有显示进度条,绿色运行良好,红色运行失败
02-单元测试-基本使用
基本流程:
- 导入jar包
- 测试方法必须是无参无返回值的非静态方法
- 测试方法加
@Test
注解标注该方法是测试方法 - 右键通过Junit运行该方法
导包:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
public class TestDemo01 {
public static void main(String[] args) {
}
@Test
public void test1(){
System.out.println(1);
}
}
03-单元测试-常用注解
public class TestDemo01 {
public static void main(String[] args) {
}
@After
public void testBefore(){
System.out.println("testBefore");
}
@Before
public void testAfter(){
System.out.println("testAfter");
}
@Test
public void test1(){
System.out.println(1);
}
}
13-5-2-日志技术
04-日志技术与输出语句的区别
日志的作用:
记录程序运行的详细信息,并永久存储
类似输出语句,但是也有区别。
输出语句有如下弊端:
- 想取消记录的信息需要修改代码才可以完成
- 信息只能展示在控制台,不能记录到其他位置(文件,数据库)
对比:
05-日志技术-体系结构和Log4j
06-日志技术-Log4j入门案例
开发流程
- 导如Log4j包
- 编写Log4j配置文件
- 代码中获取日志对象
- 按照级别设置日志记录信息
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
配置文件:文件名必须是log4j.properties
log4j.rootLogger=debug,my,fileAppender
### direct log messages to my ###
log4j.appender.my=org.apache.log4j.ConsoleAppender
log4j.appender.my.ImmediateFlush = true
log4j.appender.my.Target=System.out
log4j.appender.my.layout=org.apache.log4j.PatternLayout
log4j.appender.my.layout.ConversionPattern=%d %t %5p %c{1}:%L - %m%n
# fileAppenderʾ
log4j.appender.fileAppender=org.apache.log4j.FileAppender
log4j.appender.fileAppender.ImmediateFlush = true
log4j.appender.fileAppender.Append=true
log4j.appender.fileAppender.File=D:/log4j-log.log
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern=%d %5p %c{1}:%L - %m%n
public class LogDemo {
/**
* 获取日志对象 可以根据log4j自己的api来获取日志对象
* 弊端:以后更换日志框架,代码也要跟着修改
* 不推荐使用,一般使用sl4f的api获取
*/
private static final org.apache.log4j.Logger log4jLogger = org.apache.log4j.Logger.getLogger(LogDemo.class);
/**
* 推荐使用日志门面 这样更换日志实现类时不需要修改代码
*/
private static final org.slf4j.Logger sl4jLogger = org.slf4j.LoggerFactory.getLogger(LogDemo.class);
public static void main(String[] args) {
log4jLogger.debug("你好 debug");
log4jLogger.info("你好 info");
log4jLogger.warn("你好 warn");
log4jLogger.error("你好 error");
sl4jLogger.debug("sl4jLogger你好 debug");
sl4jLogger.info("sl4jLogger你好 info");
sl4jLogger.warn("sl4jLogger你好 warn");
sl4jLogger.error("sl4jLogger你好 error");
}
}
运行结果:(这里由于没有找到对应的slf4j-lo4j.jar),所以使用日志门面进行记录日志时报错。后面使用spring框架后会集成,不纠结了。
07-日志技术-Log4j三个核心
- Loggers 记录器 --- 日志的级别
- Appenders 输出源 --- 日志要输出的地方
- Layouts 布局 --- 日志输出的格式
Loggers
Loggers组件在此系统中常见的五个级别:DEBUG、INFO、WARN、ERROR和FATAL
Log4j有个规则:只输出不低于设定级别的日志信息
日志级别:DEBUG<INFO<WARN<ERROR<FATAL
Appenders
把日志输出到不同的地方,如控制台、文件等
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
Layout
根据自己的喜好指定日志输出的格式。
常见的布局管理器
org.apache.log4j.PatternLayout(可以灵活的指定布局模式)
org.apache.log4j.SimpleLayout(包含日志的级别和信息字符串)
org.apache.log4j.TTCCLayout (包括日志的产生时间、线程、类别等信息)
08-日志技术-配置文件详解
配置Loggers:
配置Appender:
其中如果使用ConsoleAppender
:
如果使用FileAppender
:
配置Layout:
如果是使用PatternLayout
: