【Java】基础知识加强

🌟个人博客:www.hellocode.top🌟
⭐所有文章均在上方博客首发,其他平台同步更新
🔥本文专栏:Java零基础指南
🌞更多相关内容请点击前往 Java零基础指南 查看
⚡如有问题,欢迎指正,一起学习~~



类加载器&反射

类加载器

概述:负责将.class文件(存储的物理文件)加载到内存中

加载时机

  • 创建类的实例(对象)
  • 调用类的类方法(静态方法)
  • 访问类或者接口的类变量,或者为该类变量赋值(静态变量)
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

用到就加载,不用不加载

加载过程:加载—验证—准备—解析—初始化

又将验证—准备—解析这三步称为链接

  • 加载

通过一个类的全限定名来获取定义此类的二进制字节流(包名+类名;用流进行传输)
将这个字节流所代表的静态存储结构转化为运行时数据结构(将这个类加载到内存中)

在内存中生成一个代表这个类的java.lang.Class对象,任何类被使用时,系统都会为之建立一个java.lang.Class对象(加载完毕创建一个class对象)

  • 链接
    • 验证:确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全(文件中的信息是否符合虚拟机规范、有没有安全隐患)
    • 准备:负责为类的类变量(静态变量)分配内存,并设置默认初始化值(初始化静态变量)
    • 解析:将类的二进制数据流中的符号引用替换为直接引用(本类中用到了其他类,此时就要找到对应的类)
  • 初始化:根据程序员通过程序制定的主观计划去初始化类变量和其他资源(静态变量赋值以及初始化其他资源)

分类

  • 启动类加载器(Bootstrap ClassLoader):虚拟机内置的类加载器
  • 平台类加载器(Platform Classloader):负责加载JDK中一些特殊的模块(继承启动类加载器)
  • 系统类加载器(System Classloader):负责加载用户类路径上所指定的类库(继承平台类加载器)(用的最多)
  • 自定义类加载器(UserClassloader):自定义的类加载器(继承系统类加载器)(用的不多

双亲委派模型

  • 当使用最下层的类加载器加载字节码文件时,首先会把加载任务逐层委派给父类加载器,直到最顶层的启动类加载器中
  • 这些加载器都有各自的加载范围,当父类加载器无法完成加载请求时,就会一层层往下返回

ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();:可以获得系统类加载器

systemClassLoader.getParent():得到父类加载器

常用方法

方法名说明
loadClass(String name, boolean resolve)加载指定名称(包括包名)的二进制类型
findClass(String name)当loadClass方法中父类加载失败时,调用自己的findClass方法来完成类加载
defineClass(byte[] b, int off, int len)将byte字节流解析成JVM能够识别的Class对象
resolveClass(Class<?> c)让使用类的Class对象创建完成也同时被解析
反射

Java反射机制

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象,都能够调用它的任意属性和方法
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制

利用反射调用它类中的属性和方法时,无视修饰符。反射操作,程序比较灵活,动态的

先获取配置文件中的信息,动态获取信息并创建对象和调用方法

获取Class对象

以前调用一个类中的方法反射调用一个类中的方法
创建这个类的对象(new)反射方式:创建对象(利用Class对象)
用对象调用方法反射方式:调用方法
  • 源代码阶段:Class.forName(String className) 通过Class类静态方法传递全类名获取Class对象
  • Class对象阶段:类名.class
  • Runtime运行时阶段:对象.getClass()

获取Constructor对象

方法名说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组(包括私有)
Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造方法对象(包括私有)

利用Constructor创建对象

  • T newInstance(Object...initargs):根据指定的构造方法创建对象
package fanshe;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo1 {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
        // 获取字节码文件
        Class clazz = Class.forName("fanshe.Student");

        // 获取构造方法
        Constructor constructor = clazz.getConstructor(String.class, int.class);

        // 利用newInstance 创建对象
        Student student = (Student) constructor.newInstance("张三", 11);
        System.out.println(student);

    }
}

在Class类中,有一个newInstance 方法,可以利用空参直接创建一个对象

Class clazz = Class.forName("fanshe.Student");

Student stu = (Student)clazz.newInstance();

不过这个方法现在已经过时了,了解即可

// 获取一个私有的构造方法并创建对象
package fanshe;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo2 {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
        // 获取字节码文件
        Class clazz = Class.forName("fanshe.Student");

        // 获取构造方法
        Constructor constructor = clazz.getConstructor(String.class, int.class);

        // 被private修饰的成员,不能直接使用
        // 如果用反射强行获取并使用,需要临时取消访问检查
        constructor.setAccessible(true);

        // 利用newInstance 创建对象
        Student student = (Student) constructor.newInstance("张三", 11);
        System.out.println(student);

    }
}

在获取到的构造方法创建对象时,如果是public,可以直接创建对象

如果是非public的,需要临时取消检查,然后再创建对象setAccessible(boolean)(暴力反射)

反射获取成员变量

  • 步骤
    • 获得class对象
    • 获得Field对象
方法名说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组(包括私有)
Field[] getField(String name)返回单个公共成员变量对象
Field[] getDeclaredField(String name)返回单个公共成员变量对象(包括私有)

赋值或者获取值
void set(Object obj, Object value):给指定对象的成员变量赋值
Object get(Object obj):返回指定对象的Field的值

代码实现

package fanshe;

import java.lang.reflect.Field;

public class Demo2 {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        // 获取class对象
        Class clazz = Class.forName("fanshe.Student");
        // 获取Field对象
        Field field = clazz.getDeclaredField("name");
        // 赋值
        // 创建一个对象
        Student stu = (Student) clazz.newInstance();
        // 关闭访问检查(私有变量)
        field.setAccessible(true);
        // 赋值
        field.set(stu, "张三");
        System.out.println(stu);
    }
}

获取Method对象

  • 步骤
    • 获取class对象
    • 获取Method对象
方法名说明
Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的,包括私有的
Method[] getMethod(String name, Class<?>…parameterTypes)返回单个公共成员方法对象
Method[] getDeclaredMethod(String name, Class<?>…parameterTypes)返回单个成员方法对象(包括私有)

运行方法
Object invoke(Object obj, Object...args):运行方法

参数一:表示用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(没有就不写)

代码演示

package fanshe;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo3 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        // 获取class对象
        Class clazz = Class.forName("fanshe.Student");
        // 获取Method对象
        Method method = clazz.getDeclaredMethod("function", String.class, int.class);
        // 创建对象
        Student stu = (Student) clazz.newInstance();
        // 运行
        method.setAccessible(true);
        method.invoke(stu, "张三", 23);
    }
}

xml

概述
  • 由万维网联盟(W3C)推出

是Web领域最具权威和影响力的国际中立性技术标准机构

  • 可扩展的标记语言XML(标准通用标记语言下的一个子集)

标记语言:通过标签来描述数据的一门语言(标签也称为元素)
可扩展:标签的名字是可以自己定义的

  • 作用
    • 用于进行存储数据和传输数据
    • 作为软件的配置文件
规则

标签规则

  • 标签由一对尖括号和合法的标识符组成
  • 标签必须成对出现
  • 特殊标签可以不成对,但是必须要有结束标记
  • 标签中可以定义属性,属性和标签名空格隔开;属性值必须用引号引起来
  • 标签需要正确的嵌套

语法规则

  • 文件后缀名为:xml
  • 文档声明必须是第一行第一列
    <?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?>

version:该属性是必须存在
encoding:该属性不是必须的,声明打开当前xml文件的时候应该使用什么字符编码表
standalone:该属性不是必须的,描述XML文件是否依赖其他的xml文件,取值为yes/no

  • 必须存在一个根标签,有且仅有一个
  • XML文件中可以定义注释信息
  • XML文件中可以存在特殊字符(&lt; &gt;…)
  • XML文件中可以存在CDATA区
    <![CDATA[...内容...]]>

演示

<?xml version="1.0"encoding="UTF-8"?>
<!--根标签-->
<students>
<!--第一个学生信息-->
<student id="1">
<name>张三</name>
<age>23</age>
<info>学生&lt;&gt;信息</info>
<!--CDATA区内的内容都会原样输出,大于号和小于号等不用使用特殊字符转义-->
<message><![CDATA[内<>容]]></message>
</student>
<!--第二个学生信息-->
<student id="2">
<name>李四</name>
<age>24</age>
<info></info>
</student>
</students>
解析

解析就是从xml中获取到数据

DOM(Document Object Model)文档对象模型:就是把文档的各个组成部分看做成对应的对象
会把xml文件全部加载到内存。在内存中形成一个树形结构,再获取到对应的值

常见的解析工具

  • JAXP:SUN公司提供的一套XML的解析的API
  • JDOM:开源组织提供了一套XML的解析的API-jdom
  • DOM4J:开源组织提供了一套XML的解析的API-dom4j(全称:Dom For Java)
  • pull:主要应用在Android手机端解析XML

DOM4J
下载地址:https://dom4j.github.io/

常用方法

方法名说明
SAXReader saxReader = new SAXReader();获取一个解析器对象
Document document = saxReader.read(new File(“xml文件路径”))利用解析器把xml文件加载到内存中,并返回一个文档对象
Element rootElement = document.getRootElement()获取到根标签
List list = rootElement.elements()获取调用者所有的子标签,并加入到集合,最终返回这个集合
List list = rootElement.elements(“标签名”)获取调用者所有的指定的子标签,会把这些子标签放到一个集合中并返回
Attribute attribute = element.attribute(“属性名”)获取标签对应的属性
String id = attribute.getValue()获取对应属性的值
Element nameElement = element.element(“标签名”);获取调用者指定的子标签
String name = nameElement.getText()获取这个标签的标签体内容

代码

package MyXml;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class Demo {

    public static void main(String[] args) throws DocumentException {
        // 获取一个解析器对象
        SAXReader saxReader = new SAXReader();
        // 利用解析器把xml文件加载到内存中
        Document document = saxReader.read(new File("src\\MyXml\\Students.xml"));
        // 获取到根标签
        Element rootElement = document.getRootElement();
        // 获取子标签
        List<Element> list = rootElement.elements("student");
        // 遍历获取每个student信息
        ArrayList<Student> s = new ArrayList();
        for (Element element : list) {
            // 获取属性
            Attribute attribute = element.attribute("id");
            String id = attribute.getText();
            // 获取name
            Element nameElement = element.element("name");
            String name = nameElement.getText();
            // 获取age
            Element ageElement = element.element("age");
            int age = Integer.parseInt(ageElement.getText());
            Student stu = new Student(id, name, age);
            s.add(stu);
        }
        System.out.println(s);
    }
}

DTD&schema

约束

用来限定xml文件中可使用的标签以及属性

分类

  • DTD
  • schema
DTD约束

步骤

  • 创建一个文件,这个文件的后缀名为.dtd
  • 看xml文件中使用了哪些元素 <!ELEMENT>可以定义元素:`<!ELEMENT persons>`
  • 判断元素是简单元素还是复杂元素

简单元素:没有子元素<!ELEMENT name (#PCDATA)>
复杂元素:有子元素的元素<!ELEMENT person (name,age)>

  • 引入DTD

引入DTD约束的三种方法

  • 引入本地dtd:<!DOCTYPE 根标签名 SYSTEM 'DTD文件路径'>
  • 在xml文件内部引入:<!DOCTYPE 根标签名 [DTD文件内容]>
  • 引入网络dtd:<!DOCTYPE 根标签名 PUBLIC "dtd文件名称" "dtd文档的URL">

DTD语法规则

  • 定义一个元素:<!ELEMENT 元素名 元素类型>
  • 元素类型

简单元素:
EMPTY:表示标签体为空

ANY:表示标签体可以为空也可以不为空

PCDATA:表示该标签的内容部分为字符串

复杂元素:
直接写子元素名称
多个子元素可以用","或者’|'隔开;
","表示定义子元素的顺序
"|“表示子元素只能出现任意一个
(?表示零次或多次;”+“表示一次或多次;”*"表示零次或多次;如果不写默认表示出现一次)

  • 定义一个属性:<!ATTLIST 元素名称 属性名称 属性类型 属性约束>

属性类型:CDATA类型(普通的字符串)

属性约束
#REQUIRED:必需的
#IMPLIED:属性不是必需的
#FIXED value:属性值是固定的

schema约束

schema和DTD的区别

  • schema约束文件也是一个xml文件,符合xml语法,后缀名为.xsd
  • 一个xml中可以引用多个schema约束文件,多个schema使用名称空间区分(名称空间类似于java包名)
  • dtd里面元素类型的取值比较单一常见的是PCDATA类型,但是在schema里面可以支持很多个数据类型
  • schema语法更加复杂

schame文件用来约束一个xml文件,因为其自身也是一个xml文件,所以同时也被别的文件约束着

步骤

  • 创建一个文件,这个文件后缀名为.xsd
  • 定义文档声明
  • schema文件的根标签为:<schema>
  • 在中定义属性:
    xmlns=http://www.w3.org/2001/XMLSchema(声明这个schema文件是一个约束文件,同时也被约束)
  • 在中定义属性:
    targetNamespace=唯一的url地址(指定当前这个schema文件的名称空间)
  • 在中定义属性:
    elementFormDefault="qualified"(表示当前schema文件是一个质量良好的文件)
  • 通过element定义元素
  • 判断当前元素是简单元素还是复杂元素

代码实现

<? xml version="1.0"encoding="UTF-8"?>
<schema
  	xmlns="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.baidu.com/javase"
            elementFormDefault="qualified"
            >
<!--定义persons复杂元素-->
<element name="persons">
<complexType><!--复杂元素-->
<sequence><!--里面元素必须按顺序-->
<!--定义person复杂元素-->
<element name="person">
<complexType>
<sequence>
<!--定义name和age简单元素-->
<element name="name"type="string"></element>
<element name="age"type="int"></element>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>

引入schema文件约束

  • 在根标签上定义属性

xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"(表示当前文件被别人约束)

  • 通过xmlns引入约束文件的名称空间

xmlns = "约束文件的名称空间"

  • 给某一个xmlns属性添加一个标识,用于区分不同的名称空间

格式为xmlns:标识 = "名称空间地址"
标识是可以任意的,但是一般取值都是xsi

  • 通过xsi:schemaLocation指定名称空间所对应的约束文件路径

格式为:xsi:schemaLocation = "名称空间url 文件路径"

Schema定义属性
<attribute name="id" type="string" use="required"></attribute>

use中两个选项:requried(必需的)、optional(可选的)


枚举&注解

  • 用常量表示季节的弊端

代码不够简洁
不同类型的数据是通过名字区分的
不安全,由于是数字类型,就有可能使用这几个值做一些运算操作;

为了间接的表示一些固定的值,Java提供了枚举

枚举格式

枚举:是指将变量的值一一列出来,变量值只限于列举出来的值的范围内

格式

public enum s{
	枚举项1,枚举项2,枚举项3;
}
// 定义一个枚举类,用来表示春、夏、秋、冬
public enum Season{
	SPRING,SUMMER,AUTUMN,WINTER;
}
枚举特点
  1. 所有枚举类都是Enum的子类
  2. 可以通过"枚举类名.枚举项名称"去访问指定的枚举项
  3. 每一个枚举项其实就是该枚举的一个对象
  4. 枚举也是一个类,也可以去定义成员变量
  5. 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
  6. 枚举类可以有构造器,但必须是private的,它默认的也是private的。
  7. 枚举类也可以有抽象方法,但是枚举项必须重写该方法
public enum Season{
    SPRING("春"){
       // 枚举类中有抽象方法,必须重写
        public void show(){
            System.out.println(this.name);
        }
    },
    SUMMER("夏"){
        public void show(){
            System.out.println(this.name);
        }
        
    },
    AUTUMN("秋"){
        public void show(){
            System.out.println(this.name);
        }
        
    },
    WINTER("冬"){
        public void show(){
            System.out.println(this.name);
        }
        
    };
    // 成员变量
    public String name;
    // 有参构造
    private Season(String name){
        this.name = name;
    }
    // 抽象方法
    public abstract void show();
}
枚举的方法
方法名说明
String name()获取枚举项的名称
int ordinal()返回枚举项在枚举类中的索引值
int compareTo(E o)比较两个枚举项,返回的是索引值的差值
String toString()返回枚举常量的名称
static T valueOf(Class type, String name)获取指定枚举类中的指定名称的枚举值
values()获得所有的枚举项
注解

主要作用:对程序进行标注和解释

注解名说明
@Override概述子类重写父类的方法
@Deprecated概述方法过时
@SuppressWarnings压制警告
@Retention(value = RetentionPolicy.RUNTIME)表示这个注解的存活时间

注释和注解

  • 注释:给程序员看
  • 注解:给编译器看(让虚拟机看到程序中的注解,注解代表程序的一些特殊功能)

自定义注解

public @interface 注解名称{
	public 属性类型 属性名 () default 默认值;		//这里只能是public,可省略
}

属性类型可以为基本数据类型、String、Class、注解、枚举以及以上类型的一维数组

在使用注解的时候如果注解里面的属性没有指定默认值,那么就需要手动给出注解属性的设置值

特殊属性value:在使用注解时如果只给value赋值,那么可以直接设置

  • isAnnotationPresent(Class<? extends Annotation> annotationClass)

判断当前方法上是否有指定的注解
参数:注解的字节码文件对象
返回值:布尔结果 true存在;false不存在

元注解

概述:就是描述注解的注解

元注解名说明
@Target指定了注解能在哪里使用
@Retention可以理解为保留时间(生命周期)
@Inherited表示修饰的自定义注解可以被子类继承
@Documented表示该自定义注解,会出现在API文档里面

@Target:成员变量(ElementType.FIELD),类(ElementType.TYPE),成员方法(ElementType.METHOD)

@Retention:不写默认只能存活在java文件(不能存活在class文件中),括号写上RetentionPolicy.RUNTIME就可以存活到字节码中


单元测试&日志技术

Junit概述:Junit是一个Java编程语言的单元测试工具。Junit是一个非常重要的测试工具

Junit特点
  • 是一个开放源代码的测试工具
  • 提供注解来识别测试方法
  • 可以让编写代码更快,并提高质量
  • 优雅简洁、简单
  • 在一个条中显示进度,如果运行良好是绿色;运行失败为红色
基本使用
  • 将junit的jar包导入到工程中
  • 编写测试方法,该测试方法必须是公共的无参数无返回值的非静态方法
  • 在测试方法上使用@Test注解标注该方法是一个测试方法
  • 选中测试方法右键通过junit运行该方法
常用注解
注解含义
@Test表示测试该方法
@Before在测试的方法前运行
@After在测试的方法后运行
日志技术

日志:程序中的日志可以用来记录程序在运行时的点点滴滴,并可以进行永久存储

区别

输出语句日志技术
取消日志需要修改代码,灵活性比较差不需要修改代码,灵活性比较好
输出位置只能是控制台可以将日志信息写入到文件或者数据库中
多线程和业务代码处于一个线程中多线程方式记录日志,不影响业务代码的性能

体系结构

在这里插入图片描述

Log4j

是Apache的一个开源项目,通过Log4j,可以控制日志信息输送的=目的地是控制台、文件等位置
也可以控制每一条日志输出格式

通过定义每一条日志信息的级别,能够更细致的控制日志的生成过程
这些可以通过一个配置文件来灵活的进行配置,不需要修改应用的代码

Log4j开发流程

  • 导入log4j的相关jar包
  • 编写log4j配置文件(log4j.properties/log4j.xml)
  • 在代码中获取日志的对象

log4j自己的api(不推荐使用)

弊端:如果以后要更换日志的实现类,那么下面的代码就要跟着改

private static final Logger LOGGER = Logger.getLogger(.class字节码文件);

使用slf4j里面的api来获取日志的对象

好处:如果更换日志的实现类,下面的代码不需要更改

private static final Logger LOGGER = LoggerFactory.getLogger(clss字节码文件)

按照级别设置记录日志信息

Log4j组成

  • Loggers(记录器):日志的级别

常用级别:
DEBUG:打印基本信息
INFO:打印重要信息
WARN:打印可能出现问题的信息
ERROR:出现错误的信息,不影响程序运行
FATAL:重大错误,程序可以停止

DEBUG<INFO<WARN<ERROE<FATAL

Log4j有一个规则:只输出级别不低于设定级别的日志文件

  • Appenders(输出源):日志要输出的地方,如控制台(Console)、文件(Files)等。

org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)

log4j.appender.ca = org.apache.log4j.ConsoleAppender
log4j.appender.ca.设置1 = 值1
log4j.appender.ca.设置2 = 值2
...........
  • Layouts(布局):日志输出的格式

常用布局管理器:
org.apache.log4j.PatternLayout(可以灵活的指定布局模式)【最常用】
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)

log4j.appender.ca.layout = org.apache.log4j.PatternLayou
log4j.appender.ca.layout.设置1 = 值1
log4j.appender.ca.layout.设置2 = 值2
...........

配置文件详解

  • 配置根Logger

格式:log4j.rootLogger = 日志级别, appenderName1, appenderName2, ...
日志级别:OFF FATAL ERROR WARN INFO DEBUG ALL或者自定义的级别
appenderName1:就是指定日志信息要输出到哪里。可以同时指定多个输出目的地,用逗号隔开
例如:log4j.rootLogger = INFO, ca, fa

  • 配置文件

ConsoleAppender常用的选项

ImmediateFlush = true 表示所有消息都会被立即输出,设置为false则不输出,默认为true
Target = System.err 默认值是System.out

FileAppender常用的选项

ImmediateFlush = true 表示所有消息都会立即被输出。设为false则不输出,默认值是true
Append = false true表示将消息添加到指定文件中,原来的消息不覆盖
false则将消息覆盖指定的文件内容,默认值为true
File = D:/logs/logging.log4j 指定消息输出到logging.log4j文件中

  • 配置Layout

PatternLayout常用的选项
ConversionPattern=%m%n 设定以怎样的格式显示消息
【格式化符号说明可以查看网上的资料做一个了解】

Log4j应用

  • 导入相关的依赖(jar)
  • 将资料中的properties配置文件复制到src目录下
  • 在代码中获取日志的对象
  • 按照级别设置记录日志信息

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九思のJava之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值