zoukankan      html  css  js  c++  java
  • java深入探究11-基础加强

    1. ? extends String:String 子类;? super String:String 父类

    2.反射-》参数化类型表示

      ParameteredType:参数化类型表示,就是获得对象类参数如Base<T>;获取T类型

      Type:所有类型接口:参数化类型,引用类型,原始类型

      如何获得T类型通过反射:

        Type type=this.class().getGenricSuperclass();//获得运行类的父类即”参数类型“;

          ParameteredType pt=(ParameteredType)type;//强制转化为参数类型

        type[] types=pt.getActualTypeArgument();//获得参数类型的实际类型的定义:具体到具体T类型

        Class class=types[0]:就是指代具体T参数实际类

        -->之后就可以对这个实际类做处理了

      一般运用在BaseDao<T>想要处理T时用反射来做的

    3.注解

      1)让编译器知道怎么做

      2)自定义注解

        步骤:1.创建注解

            public @interface Author{

              String name;

              int age;

            }

            注意:注解属性,修饰为默认或者public,不能有主体,如果属性名为value,使用时不需要value="",直接写“”

            2.使用注解

            @Author(name="Jet",age=23);@Author(23)

            当注解属性为数组,使用方法:@Author({"",""})

            3.原注解:对注解的注解

              1)设置注解的可以范围

                @Target({

                  Type,Filed,method,parameter,costrutor,local_variable

                })

              2)注解的生命周期

                @Rentention(RententionPolicy.SOURCE);//源码级别有效

                @Rentention(RententionPolicy.CLASS);//字节码有效

                @Rentention(RententionPolicy.RUNTIME);运行时有效

          4获取方法上的注解

              getAnnotation(Author.class)

      3).例子:在使用BaseDao<T>时,当T类型的Bean对象,属性名和表名字不一样时,BaseDao<T>中方法 T findById(int id),就不能简单的用DbUtil中BeanHandler<T>(class,id)来封住结果集了

        解决方法:给T 添加注解:TableName,Id ,Column三个注解-》BaseDao<T>中通过反射的方式获得T中的注解信息,再进行封装返回实例对象

    /**
     * 解决优化的问题:
     *       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);
            }
        }
        
    }
    View Code

    4.日志log4j:开源日志组件

      使用步骤:

        1.下载组件:log4j-1.2.11.jar
        2.配置src/log4.properties
          日志输出优先级:debug<info<warn<error
        3.使用
          Log log=LogFactory.getLog(App.class);
          log.info("信息提示");log.debug("调试信息");
          log.warn("警告提示");log.error(“异常提示”)
        4.log4.properties的配置详解
          1)通过根元素指定日志输出级别、目的地
            log4j.rootLogger=info,console,file
          2)日志输出到console配置
            //日志输出到控制台使用的api
            log4j.appender.console==org.apache.log4j.ConsoleAppender
            //日志输出格式:灵活的格式
            log4j.appender.console.layout=org.apache.log4j.PatterLayout
            //具体的格式内容
            Log4.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进行日志操作

     

    Log4J简介

     

    Log4JApache的一个开放源代码项目,它是一个日志操作包,通过使用Log4J,可以指定日志信息输出的目的地,如控制台、文件、CUI组件、NT的事件记录器;还可以控制每一条日志输出格式。此外,通过定义日志信息的级别,能够非常细致地控制日志的输出,最令人感兴趣的是,这些功能可以通过一个配置文件来灵活进行配置,而不需要修改应程序代码。

    在应用程序中输出日志有3个目的:

    l 监视代码中变量的变化情况,把数据周期性记录到文件中供其他应用进行统计分析工作

    l 跟踪代码运行时轨迹,作为日后审计的依据

    l 担当集成开发环境中的调试器的作用,向文件和控制台打印代码的调试信息

    要在程序中输出日志,最普通的做法就是在代码中嵌入语句,这些打印语句可以把日志输出到控制台或文件中,比较好的做法就是构造一个日志操作类来封装此类操作,而不是让一系列的打印语句充斥代码的主体。

     

    在强调可重用组件的今天,除了自己从头到尾开发一个可重用的日志操作类名,Apache为我们提供了一个强有力的现成的日志操作包Log4J

    Log4J主要由三大组件构成:

    l Logger:负责生成日志,并能够对日志信息进行分类筛选,通俗地讲就是决定什么日志信息应该输出,什么日志信息应该被忽略

    l Appender:定义了日志信息输出的目的地,指定日志信息应该被输出到什么地方,这些地方可以是控制台、文件、网络设备等

    l Layout: 指定日志信息的输出格式

    这个3个组件协同工作,使得开发者能够依据日志信息类别记录信息,并能够在程序运行期间,控制日志信息的输出格式以及日志存放地点。

    一个Logger可以有多个Appender,这意味着日志信息可以同时输出到多个设备上,每个Appender都对应一种Layout,Layout决定了输出日志信息的格式。

    假定根据实际需要,要求程序中的日志信息既能输出到程序运行的控制台下,又能输出到指定的文件中,并且当日志信息输出到控制台时SimplLayout布局,当日志信息输出到文件时PatternLayout布局,此时LoggerAppenderLayout3个组件的关系如图  

     

     

    Appender组件 (指定输出目的)
    Log4JAppender组件决定将日志信息输出到什么地方。日前Log4J的Appender支持将日志信息输出到以下的目的:

    控制台(Console)

    文件

    GUI组件

    一个logger可以同时对应多个Appender,也就是说,一个Logger的日志信息可以同时输出到多个目的地,例如:要为rootLogger配置两个Appender; 一个是file,一个是console,则可以采用如下配置代码:
       

    log4j.rootLogger =WARN,file,console          rootLogger  配置日志级别、输出目的;

    log4j.appender.file=org.apache.log4jRollingFileAppender
        log4j.appender.file=log.txt

    log4j.appender.console=org.apache.log4j.ConsoleAppender

     Layout组件
    Layout组件用来决定日志的输出格式,它有以下几种类型

    l org.apache.log4j.HTMLLayout(以HTML表格形式布局)

    l org.apache.log4j.PatternLayout(可以灵活地指定布局模式)

    l org.apache.log4j.SimpleLayout(包含日志信息级别和信息字符串)

    l org.apache.log4j.TTCCLayout(包含日志产生的时间、线程和类别等信息)

    Log4j的基本使用方法

    在应用程序中使用Log4J,首先在一个配置文件中配置Log4j的各个组件,然后就可以在程序中通过Log4API来操作日志

    定义配置文件
    Log4J由3个重要的组件构成:LoggerAppenderlayoutLog4J支持在程序中以编程的方式设置这些组件,还支持通过配置文件来配置组件,后一种方式更为灵活。

    Log4J支持两种配置文件格式,一种是XML格式,一种是Java属性文件,


    1. 配置Logger组件
    其语法为:
          log4j.rootLogger = [ level ] , appenderName1, appenderName2, …

    举例:

    log4j.rootLogger =WARN,file,console


           level : 是日志记录的优先级,分为OFFFATALERRORWARNINFODEBUGALL或者您定义的级别。

    Log4j建议只使用四个级别,优先级从高到低分别是ERROR>WARN>INFO>DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

    appenderName:就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。

    All:打印所有日志。

    Off:关闭所有的日志。
         例如:log4j.rootLoggerinfo,A1,B2,C3

    2. 配置Appender组件

     

    其语法为:
         log4j.appender.appenderName =fully.qualified.name.of.appender.class.

    举例:

    log4j.appender.console=org.apache.log4j.ConsoleAppender


        "fully.qualified.name.of.appender.class" 可以指定下面五个目的地中的一个
              1.org.apache.log4j.ConsoleAppender(控制台)
              2.org.apache.log4j.FileAppender(文件) 【只能把日志输出一个文件,不推荐】
              3.org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
              4.org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
              5.org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

     

    A.ConsoleAppender选项
        Threshold=WARN:指定日志消息的输出最低层次。
         ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
         Target=System.err:默认情况下是:System.out,指定输出控制台
    B.FileAppender 选项

    Threshold=WARN:指定日志消息的输出最低层次。

    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。

    File=mylog.txt:指定消息输出到mylog.txt文件。
         Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖

    指定的文件内容。
    C.DailyRollingFileAppender 选项
          Threshold=WARN:指定日志消息的输出最低层次。
           ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
           File=mylog.txt:指定消息输出到mylog.txt文件。
           Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定 

    的文件内容。
          DatePattern='.'yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。当然也可

    以指定按月、周、天、时和分。即对应的格式如下:
                        1)'.'yyyy-MM: 每月
                        2)'.'yyyy-ww: 每周
                        3)'.'yyyy-MM-dd: 每天
                        4)'.'yyyy-MM-dd-a: 每天两次
                        5)'.'yyyy-MM-dd-HH: 每小时
                        6)'.'yyyy-MM-dd-HH-mm: 每分钟
    D.RollingFileAppender 选项
               Threshold=WARN:指定日志消息的输出最低层次。
                ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
                File=mylog.log:指定消息输出到mylog.txt文件。
                Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指

    定的文件内容。
                MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小

    时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
                MaxBackupIndex=2:指定可以产生的滚动文件的最大数。

    3、配置日志信息的格式

    其语法为:
      1)log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
             "fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个

    举例:log4j.appender.console.layout=org.apache.log4j.PatternLayout

          log4j.appender.console.layout.ConversionPattern=%d %p %c.%M()-%m%n


                   1.org.apache.log4j.HTMLLayout(以HTML表格形式布局)包含选项:

    LocationInfo=true:默认值是false,输出java文件名称和行号
                          Title=my app file: 默认值是 Log4J Log Messages.

             2.org.apache.log4j.PatternLayout(可以灵活地指定布局模式)包含选项:

    ConversionPattern=%m%n :指定怎样格式化指定的消息。

             3.org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
             4.org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
            2)log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
          日志信息格式中几个符号所代表的含义:
       X: X信息输出时左对齐;
             %p: 输出日志信息优先级,即DEBUGINFOWARNERRORFATAL,
             %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:  %d{yyy MMM dd HH:mm:ss,SSS},输出类似:20021018221028921
             %r: 输出自应用启动到输出该log信息耗费的毫秒数
            %c: 输出日志信息所属的类目,通常就是所在类的全名
             %t: 输出产生该日志事件的线程名
             %l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程, 以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
             %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
            %%: 输出一个"%"字符
            %F: 输出日志消息产生时所在的文件名称
            %L: 输出代码中的行号
            %m: 输出代码中指定的消息,产生的日志具体信息
            %n: 输出一个回车换行符,Windows平台为" "Unix平台为" "输出日志信息换行

    %M  代表方法的名字
             可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
             1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20
              2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
              3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
               4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。

    在程序中访问Log4J,需要用到Log4J的JAR文件。
    在程序中使用Log4J包含以下过程:

    l 获得日志记录器

    读取配置文件,配置Log4J环境

    l 输出日志信息

    在进入学习Log4J之前,我们要了解通用日志包中的两个常用接口LogFactoryLog,下面分别介绍它们的用法。

    Log接口

    通用日志包把日志消息分为6种级别:FATAL(致命的)ERROR(错误)WARN(警告)INFO(信息)DEBUG(调试)TRACE(细节)。其中FATAL级别最高,TRACE级别最低。通用日志包采用日志级别机制,可以灵活的控制输出的日志内容。

    org.apache.commons.logging.Log接口代表日志器,它提供了一组输出日志的方法:

    l fatal(Object message): 输出FATAL级别的日志消息。

    l error(Object message): 输出ERROR级别的日志消息。

    l ……

    l trace(Object message): 输出TRACE级别的日志消息。

        对于以上输出日志的方法,只有当它输出日志的级别大于或等于为日志其配置的日志级别时,这个方法才会被真正执行。例如,如果日志器的日志级别为WARN,那么在程序中,它的fatal()error()warn()方法会被执行,而info()debug()trace()方法不会被执行

    Log接口还提供了一组判断是否允许输出特定级别的日志消息的方法:

    l isFatalEnabled()

    l isErrorEnabled()

    l ……

    l isTraceEnabled()

    在程序输出某种级别的日志消息之前,提倡先调用以上方法来判断该级别的日志是否允许输出,这有助于提高应用的性能。例如以下代码先把日志消息添加到StringBuffer中,最后在调用日志器的debug()方法输出日志:

    StringBuffer buf = new StringBuffer();

    buf.append(“Login Successsul - ”);

    buf.append(“Name:”);

    buf.append(username);

    log.debug(buf.toString());

    对于以上代码,如果日志器实际上不允许输出DEBUG级别的日志,那么执行日志器的debug()方法不会输出任何消息,此时向StringBuffer中添加消息的一大串操做都将是多余的。为了提高性能,可以合理的使用isDebugEnabled()方法,避免应用执行多余的操作:

    if(log.isDebugEnabled){

    StringBuffer buf = new StringBuffer();

    buf.append(“Login Successsul - ”);

    buf.append(“Name:”);

    buf.append(username);

    log.debug(bug.toString());

    }

    ()LogFactory接口

    org.apache.commons.logging.LogFactory接口提供了获得日志器实例的两个静态方法:

    public static Log getLog(String name)throws LogConfigurationException;

    public static Log getLog(Class class) throws LogConfigurationException;

    第一个getLog()方法以name参数作为日志器的名字;第二个getLog()方法以class参数指定的类的名字作为日志器的名字,以下是第二个getLog()方法的一种实现方式:

    public static Log getLog(Class class) throws LogConfigurationException{

    getLog(class.getName);     //call getLog(String name)

    }

    小结

    Log4J主要由3大组件构成:LoggerAppenderLayoutLogger控制日志信息的输出;Appender决定日志信息的输出目的地;Layout决定日志信息的输出格式。Log4J允许用户在配置文件中灵活地配置这些组件。在程序中使用Log4J非常方便,只要先取得日志记录器,然后读取配置文件并配置Log4J环境,接下来就可以在程序中任何需要输出日志的地方,调用Logger类的适当方法来生成日志。 

      

  • 相关阅读:
    BZOJ5311,CF321E 贞鱼
    POJ3208 Apocalypse Someday
    POJ1037 A decorative fence
    POJ1737 Connected Graph
    CF559C Gerald and Giant Chess
    NOI2009 诗人小G
    Problem 2726. -- [SDOI2012]任务安排
    POJ1821 Fence
    HDU5542 The Battle of Chibi
    POJ2376 Cleaning Shifts
  • 原文地址:https://www.cnblogs.com/xiaoping1993/p/6884483.html
Copyright © 2011-2022 走看看