一. 注解基本使用
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
使用@interface的方式新建注释,与创建接口类似
@Target指定注释的所修饰的对象范围
取值(ElementType)有:
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention描述注解的生命周期
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在class文件中有效(即class保留)
- RUNTIME:在运行时有效(即运行时保留)
@Inherited
@Inherited阐述了某个被标注的类型是被继承的。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface Anno {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Anno2 {
}
@Anno
@Anno2
class Parent {
}
public class Children extends Parent {
public static void main(String[] args) {
Annotation[] annos = Children.class.getAnnotations();
for (Annotation anno : annos) {
System.out.println(anno.toString());
}
}
}
输出结果
@Anno()
即未标识@Inherited的注解未被子类继承
@Repeatable
@Repeatable注解以及其相关特性,是在JDK 8中提供的,简单而言,我们可以设计一种风格的annotation,可以被多次修饰在符合要求的@Target上,在此前一个类型的注释是不能重复修饰在相同地方。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Anno {
Anno2[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Anno.class)
@interface Anno2 {
String value();
}
@Anno2("1")
@Anno2("2")
class Parent {
}
@Anno({@Anno2("1"), @Anno2("2")})
class Parent2 {
}
public class Children {
public static void main(String[] args) {
Annotation[] annos = Parent.class.getAnnotations();
for (Annotation anno : annos) {
System.out.println(anno.toString());
}
Annotation[] annos2 = Parent2.class.getAnnotations();
for (Annotation anno : annos2) {
System.out.println(anno.toString());
}
}
}
- Parent @Anno2("1")与@Anno({@Anno2("1")})这两种注解效果是一致的
- Anno.class中必须存在value()方法,并且返回值Anno2数组,否则会报错
- 上述输出结果为@Anno(value=[@Anno2(), @Anno2()]);表示虽然我们类上注解标注的是Anno2,但是实际上的注解是Anno的数组
- 根据规范,@Scheduled元注解,不能与@Schedules容器注解同时修饰在同一个Target,否则会编译错误
使用方式
@Test
private int i = 0;
二. 注解中可包含方法
- 创建方式,和定义接口基本一至,不同的是定义注解可以指定默认值
如果不指定默认值的话,在使用注解时,必须指定参数值
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
public String id() default "-1";
public String name() defaule "轶名";
}
- 使用方式,在使用注解时,指定注解属性的值,若不指定则取默认值,并且元素值必须为常量,不可使用变量
@Test(id="1",name="我是测试")
private int i = 0;
- 如果只创建注解,使用效果有限,最多只能对字段等进行描述,可对注解创建相应的注解处理器
三. 注解处理器
public class TestAnno {
private String str = "我是测试2";
@Test(id="1",name="我是测试")
private int i = 0;
public static void main(String []args){
Field[] fs = TestAnno.class.getDeclaredFields();
for(Field f : fs){
Test tAnno = f.getAnnotation(Test.class);
if(tAnno != null){
System.out.println("id:"+tAnno.id()+";name:"+tAnno.name());
}else{
System.out.println("无注解");
}
}
}
}
通过getAnnotation可以获得方法或字段等域上的注解,获得该注解后,可取得注解时的属性,对根据不同的属性进行不同的操作。
四. 使用java注解时不写属性名会给哪个属性赋值
- 如果注解只有一个属性,那么肯定是赋值给该属性。
- 如果注解有多个属性,而且前提是这多个属性都有默认值,那么你不写注解名赋值,会赋值给名字为“value”这属性。
- 如果注解有多个属性,其中有没有设置默认值的属性,那么当你不写属性名进行赋值的时候,是会报错的。
附件
1. 注解的定义
package net.xinshi.jemall.psh.util.logUtil;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Json {
/**
* 是否需要编码
* @return
*/
public boolean urlEncode() default false;
/**
* 是否需要添加前缀
* @return
*/
public String prefix() default "";
/**
* 是否为id
* @return
*/
public boolean id() default false;
/**
* 将该字段存日志的时候以key赋值的形式存储
* @return
*/
public String key() default "";
}
2. 注解的注释
/*
* 该类使用CodeGen代码生成器生成
* 生成时间: 2016-10-09 11:37:50.938
* 生成要求:数据库的主键统一命名为id,int类型
*/
package net.xinshi.jemall.psh.pshKeyWord.bean;
import java.sql.Timestamp;
import net.xinshi.jemall.psh.util.logUtil.Json;
/**
*搜索词命中率表
*/
public class PSHKeyWord implements java.io.Serializable{
private int id;
//返回结果条数
private String count;
//分站id
private int mid;
//城市id
private int cityid;
//搜索时间
private Timestamp searchtime;
//团类型 0-多品团 1-单品团
private int type;
//用户的userid
private int userid;
//备注
private String remark;
//搜索词
private String keyword;
//solr查询语句
private String searchQ;
//渠道信息
private String channel;
@Json(id=true)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
/**
* 返回结果条数
*/
@Json
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
/**
* 分站id
*/
@Json
public int getMid() {
return mid;
}
public void setMid(int mid) {
this.mid = mid;
}
/**
* 城市id
*/
@Json
public int getCityid() {
return cityid;
}
public void setCityid(int cityid) {
this.cityid = cityid;
}
/**
* 搜索时间
*/
@Json(key="JsonTime")
public Timestamp getSearchtime() {
return searchtime;
}
public void setSearchtime(Timestamp searchtime) {
this.searchtime = searchtime;
}
/**
* 团类型 0-多品团 1-单品团 2-跨境购
*/
@Json
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
/**
* 用户的userid
*/
@Json
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
/**
* 备注
*/
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
/**
* 搜索词
*/
@Json(urlEncode=true)
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
@Json
public String getSearchQ() {
return searchQ;
}
public void setSearchQ(String searchQ) {
this.searchQ = searchQ;
}
@Json(prefix="PSH")
public String getChannel() {
return channel;
}
public void setChannel(String channel) {
this.channel = channel;
}
/* 主键相同即认为对象相等. */
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || !(obj instanceof PSHKeyWord))
return false;
PSHKeyWord bean = (PSHKeyWord) obj;
if (bean.getId() !=this.getId())
return false;
return true;
}
@Override
public int hashCode() {
String clazzName = this.getClass().toString();
clazzName = clazzName + "_" + this.getId();
return clazzName.hashCode();
}
}
3. 注解的使用
package net.xinshi.jemall.psh.util.logUtil;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.util.Date;
import org.json.JSONObject;
import net.xinshi.jemall.base.Environment;
import net.xinshi.jemall.commons.StringUtil;
import net.xinshi.jemall.commons.Util;
import net.xinshi.jemall.paymode.util.wechatutil.MD5Util;
import net.xinshi.jemall.psh.pshKeyWord.bean.PSHKeyWord;
/**
* 用于程序运行期间输出一些运行信息到文件中,如:执行时间、耗时、错误等,可方便的查看程序执行的效率、及正确性与否。
* 对于调试一些程序执行效果要较长期才能看出,或大数据量处理的有用。
* 注意:输出信息完后,一定要关闭掉
*/
public class LoggerUtil {
private PrintWriter myFile; //文件输出流
private String logFileNameKeyword;//文件名关键字
private String logFileSrc;//完整的日志目录+日志名称
private String logFileDir;//日志存放的根目录
private File logFile;//日志文件
private StringBuffer strf;//日志内容
private String dirSub;//子文件夹
private String defaulePath = "d:\\RunLog";
public LoggerUtil(String fileNameKeyword, String dirSub) {
try {
this.logFileNameKeyword = fileNameKeyword;
if (dirSub != null) {
this.dirSub = dirSub;
}
String webAppPath = Environment.getEnv().getWebAppPath();
if(webAppPath != null){
this.logFileDir = webAppPath;
}else{
this.logFileDir = defaulePath;
}
this.initLogger();
} catch (Exception e) {
e.printStackTrace();
}
}
//创建一个PrintWriter对像,用于写数据,第一次创建的时间同时写入操作文件的信息
private PrintWriter getPrintWriter() throws Exception {
try {
logFile = new File(this.logFileSrc);
if (!logFile.exists()) {
logFile.createNewFile();
}
FileWriter fileWriter = new FileWriter(logFile, true);
myFile = new PrintWriter(fileWriter);
//文件不存在则创建文件,并记录操作文件信息
if (!logFile.exists()) {
logFile.createNewFile();
myFile.println("当前日志文件:" + logFile.getAbsolutePath());
}
return myFile;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 关闭之前打印日志,,创建文件和流
*/
private String loggering() {
try {
//判断是否存在日志
if(strf != null && strf.length() ==0){
return null;
}
String path = this.logFileDir;
File file = new File(path);
if (!file.exists() || !file.isDirectory()) {
file.mkdirs();
}
String dirSubTmp = this.dirSub;
if (dirSubTmp != null && dirSubTmp.trim().length() != 0) {
path = path + File.separator + dirSubTmp;
this.logFileDir = path;
File file2 = new File(path);
if (!file2.exists() || !file2.isDirectory()) {
file2.mkdirs();
}
}
String shortDataString = Util.getShortDateFormatByTimestamp(new Timestamp(System.currentTimeMillis()));
String fileName = this.logFileNameKeyword + "_" + shortDataString + ".log";
this.logFileSrc=this.logFileDir + "/" + fileName;
this.myFile = this.getPrintWriter();
} catch (Exception e) {
e.printStackTrace();
}
return "success";
}
/**
* new DebugLogger 时候创建StringBuffer
*/
private void initLogger() {
try {
strf = new StringBuffer();
} catch (Exception e) {
e.printStackTrace();
}
}
//记录一条log记录
public void log(String content) {
try {
strf.append(content);
} catch (Exception e) {
}
}
//关闭文件
public void closeLogger() {
try {
String str = this.loggering();
if(!StringUtil.isBlank(str)){
this.myFile.println(strf.toString());
this.myFile.println();
this.myFile.flush();
this.myFile.close();
}
} catch (Exception e) {
}
}
public <T> String obj2Json(T t){
JSONObject jsonObject = new JSONObject();
try {
Class clazz = t.getClass();
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods){
String fieldValue = getFieldValue(method, t);
String key = method.getName();
if(key.indexOf("get") == 0){
key = key.replaceFirst("get", "");
}
key = String.valueOf(key.charAt(0)).toLowerCase()+key.substring(1);
jsonObject.put(key, fieldValue);
}
} catch (Exception e) {
e.printStackTrace();
}
return jsonObject.toString();
}
private <T> String getFieldValue(Method method,T t){
String fieldValue = null;
try {
Json log = method.getAnnotation(Json.class);
if(log == null){
return null;
}
if(method.invoke(t) == null){
fieldValue = "";
}else{
fieldValue = String.valueOf(method.invoke(t));
}
if(log.id()){
fieldValue = t.getClass().getPackage()+"."+t.getClass().getName()+"."+fieldValue.toString();
fieldValue = MD5Util.MD5Encode(fieldValue, "utf-8");
}
if(log.prefix()!=null && !"".equals(log.prefix())){
fieldValue = log.prefix()+fieldValue;
}
if(log.urlEncode()){
fieldValue = URLEncoder.encode(fieldValue);
}
} catch (Exception e) {
e.printStackTrace();
}
return fieldValue;
}
public static void main(String[] args) {
LoggerUtil util = new LoggerUtil("", "");
PSHKeyWord pshKeyWord = new PSHKeyWord();
pshKeyWord.setCityid(31000);
pshKeyWord.setCount("10");
pshKeyWord.setKeyword("牛奶");
pshKeyWord.setMid(0);
pshKeyWord.setSearchtime(new Timestamp(new Date().getTime()));
pshKeyWord.setType(0);
pshKeyWord.setUserid(8542344);
pshKeyWord.setSearchQ("q");
pshKeyWord.setChannel("H5");
String result = util.obj2Json(pshKeyWord);
System.err.println(result);
}
}