**
**
概述
注解与注释,
注解,告诉编译器如何运行程序!
注释, 给程序员阅读,对编译、运行没有影响;
注解作用,
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());
}
}