实训第三天:注解
注解:提供一种为程序元素设置元数据的方法。
1:定义一个新的注解使用@interface关键字:如public @interface Table{}
使用注解:只需要在类,接口,方法或者属性前面加上@注解名。比如我们常见的@override就是注解。
2:注解只有成员变量,没有成员方法,和一般类的定义方式的差别是注解的属性后面要跟一个小括号。
定义成员变量有两种方式:1)无形参的形式。即直接定义一个参数,不带任何值
2)default形式,即在定义参数的时候用default带上一个默认的值。
区别:无形参的定义方式在使用注解的时候需要显示的为注解里面的属性赋值,如果不赋值就会报错。而有默认值的就不用显示的赋值了。
3:注解按照是否包含成员变量分为两类:
1)标记annotation:没有成员变量的annotation,仅用于自身的存在与否为我们提供信息。
2)元数据annotation:包含成员变量的annotation,可以接受更多的元数据,因此称为元数据annotation。
4:jdk提供四种元注解,我们自定义的注解必须经过这四种元注解再次注解之后才能被有效使用。
1)@Retention:用于指定annotation可以保留的时间。
RentationPolicy.SOURCE:annotation值保留在源码中,编译器编译时直接丢弃这个annotation。只在源文件中有效。
RentationPolicy.CLASS:编译器会把annotation保存在class文件中,当运行程序时,JVM不再保留该annotation,即在class文件中有效
RentationPolicy.RUNTIME:编译器会吧annotation记录在class文件中,程序运行时,会保留该annotation,程序可以通过反射获取该annotation的信息
即运行时保留。
2)@Target:指定annotation用于修饰哪些程序,包含一个名为value的成员变量,该成员变量的类型为ElementType[],ElementType为枚举类型
1)ElementType.TYPE:能修饰类,接口,或者枚举类型
2)ElementType.FIELD:能修饰成员变量
3)ElementType.METHOD:能修饰方法
4)ElementType.PARAMETER:能修饰参数
5)ElementType.CONSTRUCTOR:能修饰构造器
6)ElementType.ANNOTATION_TYPE:能修饰注解
3)@Document:在使用javadoc命令生成的文档后,被该元注解修饰的类将会进行一个编译生成一个javadoc文档,有一个相应的说明
4)@Inherited:指定annotation具有继承性
5:基本annotation:
1)@override:限定重写父类方法
2)@Deprecated
3)@SuppressWarning
4)@SafeWarning
6:jdk主要提供两个类来完成注解的提取。
1)java.lang.annotation.Annotation接口:此接口是所有annotation类型的父接口
2)java.lang.reflect.Annotation接口:
7:我每次在练习注解的一些方法的时候,总是想打印但是没有结果,后来才发现,自己根本没有使用哪个注解,好傻啊。
8:今天课上对于注解的练习,包括获取类,方法,属性上的注解,以及以上三者的注解上的内容。
注解类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//作用于方法
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
public @interface MethodDemo
{
String name();
int age() default 22;
}
测试类:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@MethodDemo(name="haha")
public class TableTest
{
@MethodDemo(name="fieldDemo")
String name;
public static void main(String[] args) throws Exception
{
// TODO Auto-generated method stub
//创建class对象,因为speak方法写在当前类中,所以类路径为当前类路径
Class<?> clazz=Class.forName("com.xishiyou.khl.annotation.TableTest");
//通过class对象获取类注解
Annotation [] annotations=clazz.getAnnotations();
for(Annotation ans:annotations)
{
System.out.println(ans);
}
//获得类上的注解的内容
if(clazz.isAnnotationPresent(MethodDemo.class))
{
MethodDemo md=clazz.getAnnotation(MethodDemo.class);
}
//通过class类的对象获取方法的注解
Method m=clazz.getMethod("speak");
Annotation [] annotationss=m.getAnnotations();
for(Annotation an:annotationss)
{
System.out.println(an);
}
//通过反射获取方法注解的内容
//1:判断方法的注解是否存在
if(m.isAnnotationPresent(MethodDemo.class))
{
//2:通过注解类的class对象获取到方法的注解的对象
// 此处需要的是注解类的class对象
MethodDemo md=m.getAnnotation(MethodDemo.class);
//3:获得注解的内容
String name=md.name();
System.out.println(name);
}
//通过class对象获取属性的注解
Field [] fields=clazz.getDeclaredFields();
for(int i=0;i<fields.length;i++)
{
Annotation[] ann=fields[i].getAnnotations();
System.out.println(ann[i]);
}
//获得属性注解上的内容
//1:获得全部属性放入一个数组中
for(Field field:fields)
{
//2:判断属性是否拥有注解
if(field.isAnnotationPresent(MethodDemo.class))
{
//3:获得属性的注解
MethodDemo md=field.getAnnotation(MethodDemo.class);
String name=md.name();
int age=md.age();
System.out.println(field.getName()+" = "+name+" = "+age);
}
}
}
@MethodDemo(name="methodDemo")
public void speak()
{
System.out.println("语言");
}
}
9:课上要求使用注解拼接一个sql语句并打印。
表名注解类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table
{
String value();//表名
}
ID注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//主键
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {
String name() default "0";
boolean isAutoIncreament() default true;//是否自增长
}
列名注解类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Colunm
{
String name();
用户信息Javabean:
@Table("user")
public class User
{
@ID(name="id",isAutoIncreament=false)
private int id;
@Colunm(name="userName")
private String userName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
测试类:
import java.lang.reflect.Field;
public class BaseDao
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
insert(new User());
}
public static void insert(User obj)
{
//创建class对象
Class<?> clazz=obj.getClass();
//拼接insert into
StringBuffer sb=new StringBuffer();
sb.append("insert into").append(" ");
//拼接表名
Table table=clazz.getAnnotation(Table.class);
sb.append(table.value()).append("(");
//拼接列名
Field [] f=clazz.getDeclaredFields();
for(Field fd:f)
{
ID id=null;
Colunm c=null;
if(fd.isAnnotationPresent(ID.class))
{
id=fd.getAnnotation(ID.class);
sb.append(id.name()).append(",");
}
if(fd.isAnnotationPresent(Colunm.class))
{
c=fd.getAnnotation(Colunm.class);
sb.append(c.name()).append(")").append(" values ").append("(");
}
}
Class<?> clazz1=obj.getClass();
Field idField=null;
Field userNameField=null;
try
{
obj=(User) clazz1.newInstance();
idField=clazz1.getDeclaredField("id");
idField.setAccessible(true);
idField.set(obj, 22);
sb.append(idField.get(obj)).append(",");
userNameField=clazz1.getDeclaredField("userName");
userNameField.setAccessible(true);
userNameField.set(obj, "孔海海");
sb.append(userNameField.get(obj)).append(");");
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(sb.toString());
}
}
这个题我之前没有任何的思路,后来老师讲思路才跟着老师写出来了,叫我自己写,估计用注解那部分还是会有点小问题。
记一下老师的思路:
1)一个sql语句,包含三个内容,表名,主键,列名。这三个都是固定的,所以我们分别定义不同的注解类来获取。
2)定义一个javabean来暂时存放数据信息,javabean的名字就是表名,里面的属性包括需要的主键和列名。javabean的名字上使用表名注解类的注解,主键上使用主键的注解类,列名使用的是列名的注解类。
3)接下来就是在测试类中使用方法把我们需要的sql语句进行一个拼接打印。
4)要打印的语句是 insert into 表名(主键,列名) value (主键值,列值),括号里面的内容是需要我们去获取的,括号外面的东西是固定的,直接在定义的StringBuffer里面append就可以了。
5)拼接表名的时候,就是要获取表名类的注解内容,拼接主键和列名的方法是一样的。
6)在拼接value里面的内容时,就要用到之前学过的反射,获取到用户信息Javabean的属性,对其进行存取操作,然后进行拼接。
在为sql语句设置值的时候,用到了之前的反射,获取类中的私有属性并操作属性,不看笔记竟然写不出来,看来知识点还是不够熟悉。