注解

**

注解

**
概述
注解与注释,
注解,告诉编译器如何运行程序!
注释, 给程序员阅读,对编译、运行没有影响;

注解作用,
1. 告诉编译器如何运行程序;
2. 简化(取代)配置文件 【案例后再看】

常用的注解,

// 重写父类的方法
    @Override
    public String toString() {
        return super.toString();
    }
// 抑制编译器警告 
@SuppressWarnings({"unused","unchecked"}) 
private void save() { List list = null; }  // 标记方法

@Deprecated private
 void save1() { }

通过自定义注解,可以给类、字段、方法上添加描述信息

/** * 自定义注解 (描述一个作者) * @author Jie.Yuan * */
public @interface Author {

/** * 注解属性 * 1. 修饰为默认或public * 2. 不能有主体 */
String name();
int age();
}

@Author(name = "Jet", age = 30)
public void save() {

}

值的注解

public @interface Author {

    /** * 注解属性 * 1. 修饰为默认或public * 2. 不能有主体 */
    String name();
    int age() default 30;   // 带默认值的注解; 使用的时候就可以不写此属性值
}

b.默认名称的注解
注解属性名称为value,这就是默认名称

public @interface Author {
    // 如果注解名称为value,使用时候可以省略名称,直接给值
    // (且注解只有一个属性时候才可以省略名称)
    String value();
}

使用

@Author("Jet")
@Author(value = "Jet")

注解属性类型为数组:

public @interface Author {

    String[] value() default {"test1","test2"};
}

使用:

@Author({“”,“”})
    public void save() {

    }

元注解
元注解,表示注解的注解!

指定注解的可用范围:

@Target({
TYPE,     类
FIELD,     字段
METHOD,  方法
PARAMETER,   参数
CONSTRUCTOR, 构造器
 LOCAL_VARIABLE  局部变量
})

// 元注解 - 2. 指定注解的声明周期

@Retention(RetentionPolicy.SOURCE)    注解只在源码级别有效
@Retention(RetentionPolicy.CLASS)      注解在字节码即别有效  默认值
@Retention(RetentionPolicy.RUNTIME)   注解在运行时期有效

注解反射

    @Id
    @Author(remark = "保存信息!!!", age = 19)
    public void save() throws Exception {
        // 获取注解信息: name/age/remark


        // 1. 先获取代表方法的Method类型;
        Class clazz = App_2.class;
        Method m = clazz.getMethod("save");

        // 2. 再获取方法上的注解
        Author author = m.getAnnotation(Author.class);
        // 获取输出注解信息
        System.out.println(author.authorName());
        System.out.println(author.age());
        System.out.println(author.remark());
    }

注解,优化BaseDao的代码
当表名与数据库名称不一致、 字段与属性不一样、主键不叫id, 上面的BaseDao不能用!
这是,
可以通过配置文件(XML) 解决!

注解:
简化XML配置, 程序处理非常方便!
(不便于维护: 例如修改字段名,要重新编译!)

XML
便于维护! 需要些读取代码!

改造例子
Admin .class

// Admin=a_admin
@Table(tableName="a_admin")
public class Admin {

    @Id
    @Column(columnName = "a_id")
    private int id;

    @Column(columnName = "a_userName")
    private String userName;

    @Column(columnName = "a_pwd")
    private String pwd;

    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;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "Admin [id=" + id + ", pwd=" + pwd + ", userName=" + userName
                + "]";
    }

}

BaseDao.class

/** * 解决优化的问题: * 1. 当数据库表名与类名不一致、 * 2. 字段与属性不一样、 * 3. 主键不叫id * */
public class BaseDao<T> {

    // 当前运行类的类型
    private Class<T> clazz;
    // 表名
    private String tableName;
    // 主键
    private String id_primary;

    // 拿到当前运行类的参数化类型中实际的类型 ( BaseDao<Admin> , Admin.class)
    public BaseDao(){
        Type type = this.getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) type;
        Type[] types = pt.getActualTypeArguments();
        clazz = (Class<T>) types[0];

        //已经拿到: Admin.class

        /*******1. 获取表名*******/
        Table table = clazz.getAnnotation(Table.class);
        tableName = table.tableName();

        /*******2. 获取主键字段*******/
        //获取当前运行类的所有字段、遍历、获取每一个字段上的id注解
        Field[] fs = clazz.getDeclaredFields();
        for (Field f : fs) {

            // 设置强制访问
            f.setAccessible(true);

            // 获取每一个字段上的id注解
            Id anno_id = f.getAnnotation(Id.class);

            // 判断
            if (anno_id != null) {
                // 如果字段上有id注解,当前字段(field)是主键; 再获取字段名称
                Column column = f.getAnnotation(Column.class);
                // 主键
                id_primary = column.columnName();
                // 跳出循环
                break;
            }
        }

        System.out.println("表:" + tableName);
        System.out.println("主键:" + id_primary);
    }


    public T findById(int id){
        try {
            String sql = "select * from " + tableName + " where " + id_primary +"=?";
            /* * DbUtils的已经封装好的工具类:BeanHandler? 属性=字段 */
            return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public List<T> getAll(){
        try {
            String sql = "select * from " + tableName;
            return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

/** * 自定义结果集:封装单个Bean对象 */
class BeanHandler<T> implements ResultSetHandler<T>{
    // 保存传入的要封装的类的字节码
    private Class<T> clazz;
    public BeanHandler(Class<T> clazz) {
        this.clazz = clazz;
    }

    // 封装结果集的方法
    @Override
    public T handle(ResultSet rs) throws SQLException {
        try {
            // 创建要封装的对象 ‘1’
            T t = clazz.newInstance(); 
            // 向下读一行
            if (rs.next()) {

                // a. 获取类的所有的Field字段数组
                Field[] fs = clazz.getDeclaredFields();

                // b. 遍历, 得到每一个字段类型:Field
                for (Field f : fs) {

                    // c. 获取”属性名称“
                    String fieldName = f.getName();

                    // e. 获取Field字段上注解 【@Column(columnName = "a_userName")】
                    Column column =  f.getAnnotation(Column.class);

                    // f. ”字段名“
                    String columnName = column.columnName();        // 数据库中字段 a_userName

                    // g. 字段值
                    Object columnValue = rs.getObject(columnName);

                    // 设置(BeanUtils组件)
                    BeanUtils.copyProperty(t, fieldName, columnValue);
                }
            }
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}


/** * 自定义结果集:封装多个Bean对象到List集合 */
class BeanListHandler<T> implements ResultSetHandler<List<T>>{

    // 要封装的单个对象
    private Class<T> clazz;
    public BeanListHandler(Class<T> clazz){
        this.clazz = clazz;
    }

    // 把从数据库查询到的没一行记录,封装为一个对象,再提交到list集合, 返回List<T>
    @Override
    public List<T> handle(ResultSet rs) throws SQLException {
        List<T> list = new ArrayList<T>();
        try {
            // 向下读一行
            while (rs.next()) {

                // 创建要封装的对象 ‘1’
                T t = clazz.newInstance(); 

                // a. 获取类的所有的Field字段数组
                Field[] fs = clazz.getDeclaredFields();

                // b. 遍历, 得到每一个字段类型:Field
                for (Field f : fs) {

                    // c. 获取”属性名称“
                    String fieldName = f.getName();

                    // e. 获取Field字段上注解 【@Column(columnName = "a_userName")】
                    Column column =  f.getAnnotation(Column.class);

                    // f. ”字段名“
                    String columnName = column.columnName();        // 数据库中字段 a_userName

                    // g. 字段值
                    Object columnValue = rs.getObject(columnName);

                    // 设置(BeanUtils组件)
                    BeanUtils.copyProperty(t, fieldName, columnValue);
                }
                // 对象添加到集合
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

AdminDao .class

public class AdminDao extends BaseDao<Admin> {

}

App.class

public class App {

    @Test
    public void testDao() throws Exception {
        AdminDao adminDao = new AdminDao();
// Admin admin = adminDao.findById(8);
// System.out.println(admin);

        System.out.println(adminDao.findById(8));
        System.out.println(adminDao.getAll());
    }
}

你可能感兴趣的:(注解)