1.名词解释
JVM(Java Virtual Machine):java虚拟机,用于支持java程序的运行。
JRE(Java Runtime Environment):java运行时环境 JVM 和java的核心类库(J2SE ),要想运行一个java程序,只需要安装公共JRE就行了。
JDK(Java Development Kit): JAVA的开发工具。包含了java的开发工具(javac.exe,java.exe,jar.exe)和JRE。
JDK=JRE+JAVA开发工具
JRE=JVM+JAVA核心类库(J2SE )
2.java8大基本类型排行
boolean(1位)< byte(8位) < char(16位) < short(16位) < Int(32位) < long(64位) < float(32位) < double(64位)
3.构造函数
1.跟类名一致
2.没有返回类型
3.对象初始化被调用
4.如果不写构造函数,默认又一个没有参数的构造函数
4.static关键字
static的作用
为了实现对象之间重复属性的数据共享以及行为的共享
static的使用范围
可以使用修饰在方法上(共享行为)。
可以修饰在属性上(共享属性)。
static的使用限制
1:静态函数中不能访问非静态成员变量,只能访问静态变量(静态方法开始的时候已经被加载了,所以没法使用非静态的属性。
非静态的属性是根据new对象后才动态分配的)。
2:静态方法不可以定义this,super关键字(因为对象没有被new出来所以不知道此this是哪个this).
3:非静态函数中可以访问静态变量(因为静态变量公用的)
5.final关键字
final 最终的
可以修饰的: 类 函数 属性
修饰的属性就是常量,常量不可以改变(大部分情况都会搭配static关键字)
修饰的成员变量 必须给与初始化赋值,如果没有初始化也要在 对象创建对象之前对其初始化赋值
修饰的局部变量 常量
修饰的函数函数 不可以被重写
修饰的类不可以被继承
6.java 包机制
1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
静态方法不能被重写
==与object的equals判断内存地址,string的equals判断的是内容,因为string已经重写了equals
在导入的包的类里面有一个同类名,那第二个类的导入则需要全路径
java.lang底下的包不需要导入
冒泡排序
for (int j = 0; j < a.length - 1; j++) {
for (int i = 0; i < a.length - j - 1; i++) {
if (a[i] > a[i + 1]) {
int temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
}
}
}
二分查找
// 上限 中值 下限
int min, mid, max;
min = 0;
max = tmp.length - 1;
mid =( min + max) / 2;
while (tmp[mid] != search) {
if (tmp[mid] < search) {
min = mid + 1;
} else if (tmp[mid] > search) {
max = mid - 1;
}
mid = ( min + max) / 2;
}
单例设计模式
饿汉式
public class Test3 {
// 2在类中创建一个私有的本类对象 创建这个类要保证能被共享,能够被其他类使用
private static Test3 test = new Test3();
// 1将构造函数私有化 构造函数 因为实例化会调用这个构造函数来进行初始化
private Test3() {
}
//3提供一个用类名调用的公有方法获取该对象。
public static Test3 getTest3() {
//保险,预防空指针报错
if(test == null) {
test = new Test3();
}
return test;
}
}
懒汉式
public class Test3 {
// 2在类中创建一个私有的本类对象 创建这个类要保证能被共享,能够被其他类使用
private static Test3 test = null;
// 1将构造函数私有化 构造函数 因为实例化会调用这个构造函数来进行初始化
private Test3() {
}
//3提供一个用类名调用的公有方法获取该对象。
public static synchronized Test3 getTest3() {
//保险,预防空指针报错
if(test == null) {
test = new Test3();
}
return test;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QHxDUQWo-1573556590475)(E:\JKPS\FILE\快速算法.jpg)]
访问权限 | 本类 | 同包 | 子类 | 其他包 |
---|---|---|---|---|
public | Yes | Yes | Yes | Yes |
protected | Yes | Yes | Yes | No |
default(缺省) | Yes | Yes | No | No |
private | Yes | No | No | No |
只有静态的变量才可以用对象名.变量-调用
抽象方法只能在抽象类或者接口里面出现,抽象方法必须被重写,所以不能被static,final以及private修饰
在
有方法都是抽象方法,默认使用abstract以及public修饰(使用implements实现)
接口里面有的都是常量,并且没有构造器,接口可以继承接口并且可以多继承,
interface可以有default修饰的方法,然后允许他有方法体,他也可以不被重写
也可以被static修饰,但是不会被继承,也不会被重写,只能通过接口名调用,只能自己用
**instanceof 关键字:**是一个比较运算符,用于判断一个对象是否是属于指定类的对象.
使用: 对象 instanceof 类
一个编译单元(java文件)可以存在多个类,在编译时产生多个不同的.class文件,.class文件便是程序运行的数据来源。java将public类作为每个编译单元的数据接口,只能有一个,不然不能处理存在多个类的java文件。当一个编译单元(java文件)有多个非public类时,运行时需要对数据来源进行选择
抽象类
1.abstract声明的
2.抽象方法只有声明没有实现
3.抽象类不能实例化对象,如:Parent p = new Parent();//编译报错 只能通过子类取实例化
4.抽象类中可以没有抽象方法
5.抽象类中也可以有普通成员(成员变量、成员函数、代码块)除了可以有抽象方法外,其他都是一毛一样
抽象方法
1.抽象方法用abstract声明的
2.抽象方法没有方法体
3.一定会被子类重写
接口:
如果一个抽象类里面的函数都是抽象函数 、那么这个类就是接口
interface 来定义一个接口 注意:不要写class
abstract可以省略
interface Test{
default void aaa(){
}
}
细节
不能有构造函数
不能有普通变量
只能是静态常量
所有方法都是public的,而且是抽象方法,不能是static修饰
可以继承多个接口
10.接口和抽象类的区别
抽象类可以有构造函数,接口不可以有构造函数
抽象类中可以有普通成员变量,接口中没有普通成员变量,只能有常量
抽象类中的方法可以被static修饰,接口中的方法不可以被static修饰
抽象类中可以有普通方法和抽象方法,接口中的方法全是抽象方法
抽象中的方法可以被public,protected等修饰符修饰,接口中的方法全都是public abstract的方法,如果省略修饰符,则默认的也都是public abstract修饰
一个类只能继承一个抽象类,接口可以被多实现,即一个类只能继承一个类,可以实现多个接口
**String类:**一个自定义类型,而且不可变的;
**StringBuffer类:**可变的;
**内部类:**定义在类里面的类,外部类不能访问内部类,内部类可以访问外部类
**包装类:**一些自定义类型的类,如:
原始类型:boolean,char,byte,short,int,long,float,double
包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
Interger在常量池里面的取值范围为(-128–127)
**Math类:**里面封装着许多与数学相关的方法
使用:
//不用新建对象,直接Math.方法;
Math.round()
随机数
Math.ceil()
向上取整
Math,floot()
向下取整
**BigDecimal类:**当你用有限的容量装无限的数的时候回出现精度丢失(如10/3.0);—基本类型;但是BigDecimal就不会出现这样的问题,他是专门用来计算商业数字的类;
使用:
public BigDecimal add(BigDecimal augend):加
public BigDecimal subtract(BigDecimal subtrahend):减
public BigDecimal multiply(BigDecimal multiplicand):乘
public BigDecimal divide(BigDecimal divisor):除
public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode):商,几位小数,舍取模式
}
/**
* 精确加法
*/
public static double add(double value1, double value2) {
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
return b1.add(b2).doubleValue();
}
/**
* 精确减法
*/
public static double sub(double value1, double value2) {
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
return b1.subtract(b2).doubleValue();
}
/**
* 精确乘法
*/
public static double mul(double value1, double value2) {
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
return b1.multiply(b2).doubleValue();
}
/**
* 精确除法 使用默认精度
*/
public static double div(double value1, double value2) throws IllegalAccessException {
return div(value1, value2, DEF_DIV_SCALE);
}
/**
* 精确除法
* @param scale 精度
*/
public static double div(double value1, double value2, int scale) throws IllegalAccessException {
if(scale < 0) {
throw new IllegalAccessException("精确度不能小于0");
}
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
// return b1.divide(b2, scale).doubleValue();
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 四舍五入
* @param scale 小数点后保留几位
*/
public static double round(double v, int scale) throws IllegalAccessException {
return div(v, 1, scale);
}
/**
* 比较大小
*/
public static boolean equalTo(BigDecimal b1, BigDecimal b2) {
if(b1 == null || b2 == null) {
return false;
}
return 0 == b1.compareTo(b2);
}
解决随机数重复,定义一个标记,然后if判断,如果随机到标记就跳出本次循环(参考斗地主发牌)
**面向对象三大特征:**封装,继承,多态
**继承(extends)*就像人类的父子关系一样,儿子会继承父亲的所有(非private的)东西,当然,儿子也可以有自己的新特点,比如可以重写父亲的方法等等,只能继承一个父类;
**日期类:**是java中用于获取或者设置时间的类,一般可以作为,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式等;
**Date类:**代表一个特定的瞬间,以毫秒为单位(1000毫秒=1秒)
使用:
eDate date =new Date();
date.方法;
拓展:System.currentTimeMillis() 获取当前时间的毫秒数,可以通过毫秒数进行时间比较,时间转化以及时间格式化等
**SimpleDateFormat类:**是简单的日期类,可以输出你相应的日期格式,含有特定的格式化编码,一般都会使用这个类来设置时间
**使用:**需要与Date类搭配使用
Date date1=new Date();
SimpleDateFormat s1=new SimpleDateFormat("yyyy年MM月dd日");//2019年08月15日
System.out.println(s1.format(date1));
**Calendar类:**也是一个日期类,不过比较老的类,不常用
使用:
Calendar cal1 = Calendar.getInstance();
call.方法;
计算机时间从1970年1月1日0点0分0秒开始;中国在东八区,与之相差8个小时月是从0开始星期日也是
Da’y12,异常
**集合:**集合与数组都是一个容器,不同的是集合的长度是可变的,而数组的长度是固定的,而且数组中存储数据类型是单一的,集合中可以存储任意类型的对象。
Collection接口:集合只能保存对象以及自定义类型,不能保存基本类型,可以使用包装类,set, list , HashSet,ArrayList;
**集合运算:**交集,并集,补集,利用Collection接口提供的retainAll方法来实现
Collection和Collections的区别,Collection是集合的父类,而Collections是集合工具类
**List集合:**他是有序可重复的;ArrayList: 数组实现, 查找快, 增删慢,**LinkedList *链表实现, 增删快, 查找慢
使用:
List<String> list1 = new ArrayList<String>();
list1.方法
List<String> lis2 = new LinkedList <String>();
list2.方法
三种遍历的方法:
//遍历方式 增强的for循环
for (String string : list) {
System.out.println(string);
}
//索引的方式 因为是数组的方式存储方式,所以索引从0开始
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//利用迭代器的方法
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
**Set集合:**无序不可重复的,查找慢增删快;HashSet 内容无序 不可重复 支持null;TreeSet 内按字典序 不可重复 不支持null;LinkedHashSet 带存储顺序 不可重复
使用:
Set set =new HashSet();
set.方法;
**Map集合:**是一个以键值对的形式存储数值,键唯一,值不唯一;对于map集合遍历的时候,先要得到键的set集合,然后对set集合遍历,再得到相应的值
Map: 键值对 (key,value) key的特点是无序的,不可以重复的,通过唯一的key拿到唯一的value。
HashMap非线程安全,高效,key无序 key支持null
TreeMap key按按字典序 key不支持null
HashTable 线程安全,低效,key支持null
LinkedHashMap
性能 : HashMap > TreeMap > LinkedHashMap > HashTable
使用:
Map map =new HashMap();
map.方法
//键找值方式:即通过元素中的键,获取键所对应的值
//1.增强的for循环(entry集合)
for(Entry<Integer, String> entry:map.entrySet()){
System.out.println(entry);
}
//2.增强的for循环(key集合)
for(Integer key:map.keySet()){
System.out.println(key+" = "+map.get(key));
}
//3.遍历值的集合
for(String value:map.values()){
System.out.println(value);
}
**File类:**Java里面的一个文件类,用于操作文件的读写,一般配合IO流使用
使用:
File file =new File();
file.方法;
**1.字节流(8位)*IO流里面,以一个字节一个字节传输读写的一个流,他是一个万能的流,可以读写所有的数据,比如文本,音频,视频.图片;
使用步骤:
输入流
读文件
1:打开流(即创建流)
2:通过流读取内容
3:用完后,关闭流资源
输出流
写文件
1:打开文件输出流,流的目的地是指定的文件
2:通过流向文件写数据
3: 刷新缓冲区域
4: 用完流后关闭流
InputStream in = new FileInputStream(new File("路径"));
OutputStream out =new FileOutputStream(new File("路径"));
2.字符流(16位):IO流里面,只能用于操作操作纯文字的文件,但是速度比字节流快(FileReader、FileWriter),使用方法与字节流一样
**3.缓冲流:**增加读写速度,(BufferedInputStream ,BufferedOutputStream)
**使用:**一般与字节流,字符流搭配使用
BufferedReader a1=new BufferedReader(new FileReader("路径"));
BufferedWriter a2=new BufferedWriter(new FileWriter("路径"));
对象流:将对象序列化成一个流,然后写在文件里面,用于保存对象
序列化就是把对象转为方便传输的格式(字符串格式),反序列化就是把序列化的字符串转为对象
**Serializable接口:**要实现对象流就必须实现这个接口,可以理解为一个工具;
**serialVersionUID:**版本号,在对象流序列化的时候,系统会判断两个程序的序列号是否一致,要一致才可以实现序列化;
对象序列化:
1.声明类实现了Serializable接口。是一个标示器,没有要实现的方法。
2.新建对象。
3.新建字节流对象(FileOutputStream)进序列化对象保存在本地文件中。如果没有该文件,利用输入流
4.新建ObjectOutputStream对象,调用writeObject方法序列对象。
5.writeObject方法会执行两个工作:序列化对象,然后将序列化的对象写入文件中。
6.异常处理和流的关闭动作要执行。
对象流之ObjectOutputStream对象序列化
ObjectOutputStream可以将对象进行序列化的输出流。
示例代码如下:
//ObjectOutputStreamDemo类代码
public class ObjectOutputStreamDemo{
/*
* void writeObject()
* 将特定的对象转化为字节序列
*/
@Test
public void testOOS() throws Exception{
FileOutputStream fos = new FileOutputStream("boy.obj");
//构造方法ObjectOutputSteam(OutputStream out)
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person boy = new Person("Peter",12,"男");
oos.writeObject(boy);
System.out.println("完成序列化");
oos.close();
}
}
//Java对象类代码
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String gender;
public Person() {
super();
}
public Person(String name, int age, String gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "name=" + name + ", age=" + age + ", gender=" + gender ;
}
}
RandomAccessFile类,一个可以读写一体的类,而且可以随意访问文件的位置,主要用于多线程下载,用于在文章任意的位置添加或删减内容:
使用:
RandomAccessFile AccessFile = new =RandomAccessFile("文件位置","操作权限(r,rw,rws,rwd))"
AccessFile.方法;
Properties为属性文件,是用来写配置文件的
是Hashtable的子类 ,是一个特殊的建值对。保存的地方是文件
key 与 value 都是String类型
使用:
Properties ps = new Properties();
pps.load(new FileInputStream("配置文件的名字.properties"));
ps.方法;
Integer.parseInt(“String”):String转int
Java线程有两种创建方式,第一是继承Thread接口,第二种是实现Runnable接口
继承Thread类
1.继承Thread类
2.重写run方法(线程在执行的时候就是在执行线程类中的run方法中的代码)
3.创建线程对象
4.调用start 方法
一个任务一个线程就用这个Thread
实现Runnable接口
一个任务多个线程并行处理就用这个Runnable
synchronized修饰方法:代表同一时刻只能一个线程进来
synchronized(对象){}代码块:锁住的对象只能有一个线程进来,而且这个对象必须是所有线程共有的
**死锁:**有A与B,有两个线程,两个线程都要获得AB才可以完成任务,现在,线程一获得了A,线程二获得了B,而线程一要去获得B,但是B已经被线程二获得了,所有他只能等待线程二释放B,但是线程二要同时获得AB才可以释放资源,而线程二也一样,所以大家就造成了死锁.
死锁不能解决,只能避免
避免方式:
1.线程互斥:synhronized修饰在同一个类的两个或者以上的方法都会出现互斥现象
2.线程同步,互斥的基础上的,使得线程有先后顺序
wait()–等待和notify()–唤醒是成对出现的:他们都不属于Tthread类,而是属于Object类的
Socket:用于TCP客户端
ServerSocket:服务端
TCP Socket开发步骤
服务端
// 1.创建一个ServerSocket对象
// 2.调用accept()方法接受客户端请求(建立连接)
// 3.获取socket对象的输入输出流
// 4.读取客户端传过来的数据
// 5.关闭流
// 6.关闭连接
客户端
// 1.创建一个Socket对象(相当于建立了连接)
// 2.获取输出流
// 3.输出内容
// 4.关闭流
// 5.断开连接
UDP Socket开发步骤
服务端
// 1.创建DatagramSocket对象,并且声明端口
// 2.创建接受包
// 3.通过socket调用receive等待包内容
// 4.接收到包后解释包内容
// 5.关闭DatagramSocket
客户端
// 1.创建DatagramSocket对象,并且声明端口(客户端端口可以省略,对于客户端不关注端口)
// 2.把发送的内容封装到DatagramPacket并且把服务端的IP以及端口带上
// 3.发送DatagramPacket
// 4.关闭DatagramSocket
服务端代码
public class SocketSever {
public static void main(String[] args) {
try {
// 1.创建一个ServerSocket对象 传入连接端口
ServerSocket serverSocket = new ServerSocket(5500);
System.out.println("服务端启动,等待连接......");
/*
* 2.调用ServerSocket对象的accept()方法接受客户端请求(建立连接)得到一个Socket对象——第一次握手接收方
* 因为这里的服务端在等待客户端的连接,所以线程会阻塞,直到有客户端和这边连接为止,会一直等待下去
*/
Socket socket = serverSocket.accept();
System.out.println("与客户端连接成功...");
/*
* 3.获取Socket对象的输入输出流
* 因为这边预定会穿字符串,所以可是使用InputStreamReader将字节流转为字符流
* 再利用BufferedReader这个缓冲流
* */
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
/*
* 4.读取客户端传过来的数据读取
* readLine 方法直接将客户端传输过来的数字转为字符串,打印结果
* */
String content = br.readLine();
System.out.println("服务器接收到:"+content);
//5.关闭流
br.close();
//6.关闭连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
// 1.创建DatagramSocket对象,并且声明端口(客户端端口可以省略,对于客户端不关注端口)
// 2.把发送的内容封装到DatagramPacket并且把服务端的IP以及端口带上
// 3.发送DatagramPacket
// 4.关闭DatagramSocket
public class SocketClient {
public static void main(String[] args) {
try {
System.out.println("客户端准备连接服务端......");
/*
* 1.创建一个Socket对象,传入想要连接的ip地址和端口 相当于建立了连接,也就是说三次握手在执行完这个步骤的就完成了
*/
Socket socket = new Socket("127.0.0.1", 5500);
System.out.println("与服务端完成连接");
// 2.通过Socket对象获取输出流,因为打算传字符串,所以还是转为字符流
OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
// 使用缓冲流
BufferedWriter bufferedWriter = new BufferedWriter(writer);
// 3.输出内容
bufferedWriter.write("我是客户端.");
// 4.关闭流
bufferedWriter.flush();// 记得刷新
bufferedWriter.close();
// 5.断开连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
链接网络,两台电脑之间的通信,非常重要,面试有可能会要手写代码
**线程池(4种)*将若干个线程装在集合里,且线程可循环利用
XML解释
1,DOM解析
2,SAX解析
SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。
优点:
1、采用事件驱动模式,对内存耗费比较小。
2、适用于只处理XML文件中的数据时。
缺点:
1、编码比较麻烦。
2、很难同时访问XML文件中的多处不同数据。
**可变长参数(本质是一个数组,默认非null)*参数不一定,用三个逗号表现,且在调用的时候可以不传参也可以传任意个参数(无数);当时可变长参数一定要声明在最后,否则识别不了 ,而且String … args 只能有一个:
method(String a ,String ... args);正确
method1(String ... args ,String a);错误
**反射:**能够动态的获取一个类的的所有属性和方法以及构造函数,他可以在运行的时候构造任意一个类的对象,调用对象的方法以及属性,获取他所具有的所有成员变量和方法
使用:通过Class类获取对象
有三种方式:
1.通过类名获取 类名.class
2.通过对象获取 对象名.getClass()
3.通过全类名获取 Class.forName(全类名)
**DEBUG:**利用eclipse等编程工具的debug功能寻找程序的bug
**泛型:**可以理解为一种自定义类型,普遍用于集合中.
**使用:**1.自定义泛型类.
自定义泛型类的声明,是在类名后面加上 ;在类体中只能对这个 泛型进行声明,不能实现或赋值, 而且在静态成员中 都不可以使用泛型
2.泛型方法
方法上面也可以声明泛型,静态方法也可以泛型方法也可以定义多个
3.泛型的上限与下限
- 限定通配符的上边界:
extends
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
上边界只能获取不能添加。
- 限定通配符的下边界
super
接收Integer 或者Integer的父类型
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();
下边界只能添加,不能获取
**枚举:**可以理解为一种指定义类型的变量,在用enum修饰的类中声明
特性
1.枚举是1个特殊类
2.枚举默认修饰符是 public static final ;
3.枚举值是所属类的类型
4.构造方法 都是私有的
5.枚举可以实现抽象的方法,但是枚举值也要实现该方法
6.枚举的值必须要放在枚举类的第一行、
常用方法
**注解:**以@开头的字符串,例如@Overload,用于标识方法,(注解一般要配合反射一起使用),你还可以自定义注解(有四种注解@Retention、@Target、@Document、@Inherited):
public @interface MyAnnotion{
}
Log4j:日志文件