泛型 & 注解 & Log4J日志组件

掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例)

泛型

  • 概述 : 泛型是JDK1.5以后才有的, 可以在编译时期进行类型检查,且可以避免频繁类型转化
// 运行时期异常 
    @Test
    public void testGeneric() throws Exception {
        // 集合的声明
        List list = new ArrayList();
        list.add("China");
        list.add(1);
        // 集合的使用
        String str = (String) list.get(1);
    }
    // 使用泛型
    @Test
    public void testGeneric2() throws Exception {
        // 声明泛型集合的时候指定元素的类型
        List list = new ArrayList();
        list.add("China");
//      list.add(1);// 编译时期报错   
        String str = list.get(1); 
    }
  • 泛型擦除 : 泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!
//泛型擦除实例
public void save(List p){
}
public void save(List d){    // 报错: 与上面方法编译后一样
}
  • 泛型写法:
// 泛型写法
    @Test
    public void testGeneric3() throws Exception {
        // 声明泛型集合,集合两端类型必须一致
        List list = new ArrayList();
        List list1 = new ArrayList();
        List list2 = new ArrayList();
        List list3 = new ArrayList();
        
        // 错误
        //List list4 = new ArrayList();
        // 错误: 泛型类型必须是引用类型,不能为基本类型
        List list5 = new ArrayList();
    }
 
 
  • 泛型方法 / 泛型类 / 泛型接口 :
    • 作用 :
      a> 设计公用的类、方法,对公用的业务实现进行抽取!
      b> 使程序更灵活!
    • 泛型方法 :
public class GenericDemo {
    // 定义泛型方法
    public  T save(T t,K k) {
        return null;
    }

    // 测试方法
    @Test
    public void testMethod() throws Exception {
        // 使用泛型方法:  在使用泛型方法的时候,确定泛型类型
        save(1.0f, 1);
    }
}
  • 泛型类 :
public class GenericDemo {

    // 定义泛型方法
    public  T save(T t,K k) {
        return null;
    }
    
    public void update(T t) {

    }
    
    // 测试方法
    @Test
    public void testMethod() throws Exception {
        
        // 泛型类:  在创建爱泛型类对象的时候,确定类型
        GenericDemo demo = new GenericDemo();
        demo.save("test", 1);
    }
}
  • 泛型接口 :
// 泛型接口
public interface IBaseDao {
    void save(T t );
    void update(T t );
}
  • 泛型接口类型确定 :
    a> 实现泛型接口的类也是抽象,那么类型在具体的实现中确定或创建泛型类的时候确定 : public class BaseDao implements IBaseDao {}
    b> 泛型接口类型确定: 在业务实现类中直接确定接口的类型 : public class PersonDao implements IBaseDao{}

  • 泛型关键字

    • ? : 指定只是接收值
//泛型, 涉及到一些关键字 
// Ctrl + shift + R   查看当前项目中类
// Ctrl + shift + T   查看源码jar包中的类
public class App_extends_super {
        //只带泛型特征的方法
        public void save(List list) {
                // 只能获取、迭代list;  不能编辑list
        }

        @Test
        public void testGeneric() throws Exception {
                // ?  可以接收任何泛型集合, 但是不能编辑集合值; 所以一般在方法参数中用
                List list = new ArrayList();
                //list.add("");// 报错
        }
}
  • extends : 元素的类型必须继承自指定的类
public class App_extends_super {
    /**
     * list集合只能处理 Double/Float/Integer等类型
     * 限定元素范围:元素的类型要继承自Number类  (上限)
     * @param list
     */
        public void save(List list) {
        }

        @Test
        public void testGeneric() throws Exception {
                List list_1 = new ArrayList();
                List list_2 = new ArrayList();
                List list_3 = new ArrayList();
        
                List list_4 = new ArrayList();
        
                // 调用
                save(list_1);
                save(list_2);
                save(list_3);
                //save(list_4);
        }
}
  • super : 元素的类型必须是指定的类的父类
public class App_super {
    /**
     * super限定元素范围:必须是String父类   【下限】
     * @param list
     */
        public void save(List list) {
        }

        @Test
        public void testGeneric() throws Exception {
                // 调用上面方法,必须传入String的父类
                List list1 = new ArrayList();
                List list2 = new ArrayList();
        
                List list3 = new ArrayList();
                //save(list3);
        }
}
 
 
  • 泛型的反射
// 所有dao的公用的方法,都在这里实现
public class BaseDao{

    // 保存当前运行类的参数化类型中的实际的类型
    private Class clazz;
    // 表名
    private String tableName;
    // 构造函数: 1. 获取当前运行类的参数化类型; 2. 获取参数化类型中实际类型的定义(class)
    public BaseDao(){
        //  this  表示当前运行类  (AccountDao/AdminDao)
        //  this.getClass()  当前运行类的字节码(AccountDao.class/AdminDao.class)
        //  this.getClass().getGenericSuperclass();  当前运行类的父类,即为BaseDao
        //                                           其实就是“参数化类型”, ParameterizedType   
        Type type = this.getClass().getGenericSuperclass();
        // 强制转换为“参数化类型”  【BaseDao】
        ParameterizedType pt = (ParameterizedType) type;
        // 获取参数化类型中,实际类型的定义  【new Type[]{Account.class}】
        Type types[] =  pt.getActualTypeArguments();
        // 获取数据的第一个元素:Accout.class
        clazz = (Class) types[0];
        // 表名  (与类名一样,只要获取类名就可以)
        tableName = clazz.getSimpleName();
    }
    // 主键查询
    public T findById(int id){
        /*
         * 1. 知道封装的对象的类型
         * 2. 表名【表名与对象名称一样, 且主键都为id】
         * 
         * 即,
         *    ---》得到当前运行类继承的父类  BaseDao
         *   ----》 得到Account.class
         */
        
        String sql = "select * from " + tableName + " where id=? ";
        try {
            return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler(clazz), id);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 查询全部
     * @return
     */
    public List getAll(){
        String sql = "select * from " + tableName ;
        try {
            return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler(clazz));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

反射复习

  • 反射,可以在运行时期动态创建对象;获取对象的属性、方法;
  • 反射技术实例 :
// 反射技术
public class App {

    // 1. 创建对象
    @Test
    public void testInfo() throws Exception {
        // 类全名
        String className = "cn.itcast.c_reflect.Admin";
        // 得到类字节码
        Class clazz = Class.forName(className);
        
        // 创建对象1: 默认构造函数简写
        //Admin admin = (Admin) clazz.newInstance();
        
        // 创建对象2: 通过带参数构造器创建对象
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        Admin admin = (Admin) constructor.newInstance("Jack");
        
    }
    @Test
    //2. 获取属性名称、值
    public void testField() throws Exception {
        
        // 类全名
        String className = "cn.itcast.c_reflect.Admin";
        // 得到类字节码
        Class clazz = Class.forName(className);
        // 对象
        Admin admin =  (Admin) clazz.newInstance();
        
        // 获取所有的属性名称
        Field[]  fs =  clazz.getDeclaredFields();
        // 遍历:输出每一个属性名称、值
        for (Field f : fs) {
            // 设置强制访问
            f.setAccessible(true);
            // 名称
            String name = f.getName();
            // 值
            Object value = f.get(admin);
            
            System.out.println(name + value);
        }
    }
    
    @Test
    //3. 反射获取方法
    public void testMethod() throws Exception {
        
        // 类全名
        String className = "cn.itcast.c_reflect.Admin";
        // 得到类字节码
        Class clazz = Class.forName(className);
        // 对象
        Admin admin =  (Admin) clazz.newInstance();
        
        // 获取方法对象    public int getId() {
        Method m = clazz.getDeclaredMethod("getId");
        // 调用方法
        Object r_value = m.invoke(admin);
        
        System.out.println(r_value);
    }   
}

注解

  • 概述
    • 注解与注释 :
      • 注解 : 告诉编译器如何运行程序!
      • 注释 : 给程序员阅读,对编译、运行没有影响;
    • 注解的作用 :
      1. 告诉编译器如何运行程序;
      2. 简化(取代)配置文件 【案例后再看】
    • 常用的注解 :
// 重写父类的方法
    @Override
    public String toString() {
        return super.toString();
    }
    
    // 抑制编译器警告
    @SuppressWarnings({"unused","unchecked"})
    private void save() {
        List list = null;
    }
    
    // 标记方法以及过时
    @Deprecated
    private void save1() {
    }
  • 自定义注解
    a. 注解基本写法
/**
 * 自定义注解  (描述一个作者)
 *
 */
public @interface Author {

    /**
     * 注解属性
     *    1. 修饰为默认或public
     *    2. 不能有主体
     */
    String name();
    int age();
}
// 使用
@Author(name = "Jet", age = 30)
    public void save() {

    }

b. 带默认值的注解

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

c. 默认名称的注解

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})
        a> TYPE->类
        b> FIELD->字段
        c> METHOD->方法
        d> PARAMETER->参数
        e> CONSTRUCTOR->构造器
        f> LOCAL_VARIABLE->局部变量
      • 指定注解的声明周期, 例 : @Retention(RetentionPolicy.SOURCE)
        • @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());
    }

Log4J日志组件

  • 程序中为什么用日志组件?简单来说,为了项目后期部署上线后的维护、错误排查!Log4j, log for java, 开源的日志组件!
  • 使用步骤:
    1. 下载组件,引入jar文件 : log4j-1.2.11.jar
    2. 配置 : src/log4j.properties
    3. 使用
  • code :
# 通过根元素指定日志输出的级别、目的地: 
#  日志输出优先级: debug < info < warn < error 
log4j.rootLogger=info,console,file
############# 日志输出到控制台 #############
# 日志输出到控制台使用的api类
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 指定日志输出的格式: 灵活的格式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 具体格式内容
log4j.appender.console.layout.ConversionPattern=%d %p %c.%M()-%m%n
############# 日志输出到文件 #############
log4j.appender.file=org.apache.log4j.RollingFileAppender
# 文件参数: 指定日志文件路径
log4j.appender.file.File=../logs/MyLog.log
# 文件参数: 指定日志文件最大大小
log4j.appender.file.MaxFileSize=5kb
# 文件参数: 指定产生日志文件的最大数目
log4j.appender.file.MaxBackupIndex=100
# 日志格式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %c.%M()-%m%n

你可能感兴趣的:(泛型 & 注解 & Log4J日志组件)