博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(27)回复泛型,注解、日志组件、枚举在实际项目中的使用
阅读量:7066 次
发布时间:2019-06-28

本文共 36766 字,大约阅读时间需要 122 分钟。

---恢复内容开始---

1、泛型

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

  a、概述:泛型是JDK1.5以后才有的, 可以在编译时期进行类型检查,且可以避免频繁类型转化!

1 // 运行时期异常  2     @Test 3     public void testGeneric() throws Exception { 4         // 集合的声明 5         List list = new ArrayList(); 6         list.add("China"); 7         list.add(1); 8          9         // 集合的使用10         String str = (String) list.get(1);11         12     }13     14     // 使用泛型15     @Test16     public void testGeneric2() throws Exception {17         // 声明泛型集合的时候指定元素的类型18         List
list = new ArrayList
();19 list.add("China");20 // list.add(1);// 编译时期报错21 22 String str = list.get(1); 23 }

 

  泛型擦除,泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!

 

1 /*2      * 泛型擦除实例 3      4     public void save(List
p){5 }6 public void save(List
d){ // 报错: 与上面方法编译后一样7 }8 */

 

  泛型的写法

1 // 泛型写法 2     @Test 3     public void testGeneric3() throws Exception { 4         // 声明泛型集合,集合两端类型必须一致 5         List list = new ArrayList(); 6         List
list1 = new ArrayList
(); 7 List list2 = new ArrayList
(); 8 List
list3 = new ArrayList(); 9 10 // 错误11 //List
list4 = new ArrayList
();12 // 错误: 泛型类型必须是引用类型,不能为基本类型13 List
list5 = new ArrayList
();14 }

 b. 泛型方法/泛型类/泛型接口

  作用:

  设计公用的类、方法,对公用的业务实现进行抽取!

  使程序更灵活!

 

  1. 泛型方法:

 

1 public class GenericDemo { 2  3     // 定义泛型方法 4     public 
T save(T t,K k) { 5 return null; 6 } 7 8 // 测试方法 9 @Test10 public void testMethod() throws Exception {11 // 使用泛型方法: 在使用泛型方法的时候,确定泛型类型12 save(1.0f, 1);13 }14 }

 

  2. 泛型类:

 

1 public class GenericDemo
{ 2 3 // 定义泛型方法 4 public
T save(T t,K k) { 5 return null; 6 } 7 8 public void update(T t) { 9 10 }11 12 // 测试方法13 @Test14 public void testMethod() throws Exception {15 16 // 泛型类: 在创建爱泛型类对象的时候,确定类型17 GenericDemo
demo = new GenericDemo
();18 demo.save("test", 1);19 }20 }

 

  3. 泛型接口:

1 /** 2  * 泛型接口 3  * @author Jie.Yuan 4  * 5  * @param 
6 */ 7 public interface IBaseDao
{ 8 void save(T t ); 9 void update(T t );10 }11 12 =======================================13 泛型接口类型确定: 实现泛型接口的类也是抽象,那么类型在具体的实现中确定或创建泛型类的时候确定14 public class BaseDao
implements IBaseDao
{15 ======================================16 泛型=接口类型确定: 在业务实现类中直接确定接口的类型17 public class PersonDao implements IBaseDao
{18 }

 

 c. 泛型关键字 

  泛型中:

 

    ?    指定只是接收值

 

    extends      元素的类型必须继承自指定的类

 

    super        元素的类型必须是指定的类的父类

  关键字  ?

1 /** 2  * 泛型, 涉及到一些关键字 3  *  4  * Ctrl + shift + R   查看当前项目中类 5  * Ctrl + shift + T   查看源码jar包中的类 6  * @author Jie.Yuan 7  * 8  */ 9 public class App_extends_super {10     11     //只带泛型特征的方法12     public void save(List
list) {13 // 只能获取、迭代list; 不能编辑list14 }15 16 @Test17 public void testGeneric() throws Exception {18 19 // ? 可以接收任何泛型集合, 但是不能编辑集合值; 所以一般在方法参数中用20 List
list = new ArrayList
();21 //list.add("");// 报错22 }23 }

 

  关键字  extends    【上限】

 

1 public class App_extends_super { 2      3      4     /** 5      * list集合只能处理 Double/Float/Integer等类型 6      * 限定元素范围:元素的类型要继承自Number类  (上限) 7      * @param list 8      */ 9     public void save(List
list) {10 }11 12 @Test13 public void testGeneric() throws Exception {14 List
list_1 = new ArrayList
();15 List
list_2 = new ArrayList
();16 List
list_3 = new ArrayList
();17 18 List
list_4 = new ArrayList
();19 20 // 调用21 save(list_1);22 save(list_2);23 save(list_3);24 //save(list_4);25 }26 }

 

  关键字  super     【下限】

 

1 /** 2  * 泛型, 涉及到一些关键字 3  *  4  * Ctrl + shift + R   查看当前项目中类 5  * Ctrl + shift + T   查看源码jar包中的类 6  * @author Jie.Yuan 7  * 8  */ 9 public class App_super {10     11     12     /**13      * super限定元素范围:必须是String父类   【下限】14      * @param list15      */16     public void save(List
list) {17 }18 19 @Test20 public void testGeneric() throws Exception {21 // 调用上面方法,必须传入String的父类22 List list1 = new ArrayList();23 List
list2 = new ArrayList
();24 25 List
list3 = new ArrayList
();26 //save(list3);27 }28 }

 

  d. 泛型的反射

 

    案例,设置通用方法,会用到反射泛型!下面有简单代码

 

 

  步骤:

 

  1. 案例分析 /  实现

 

  2. 涉及知识点(jdk api)

 

  3. 优化 / 反射泛型

 

 

 

 

  反射泛型涉及API

 

  Student    类型的表示

 

  Id   name

 

   参数化类型的表示

 

  ArrayList<String>();

 

 

 

  Type    接口,任何类型默认的接口!

 

          包括: 引用类型、原始类型、参数化类型

 

 

 

  List<String>  list   =  new   ArrayList<String>();

 

  泛型集合:    list

 

  集合元素定义:new   ArrayList<String>();  中的String

 

  参数化类型   

 

  即:ArrayList<String> ” 为参数化类型

 

public class AdminDao extends BaseDao
{}public class AccountDao extends BaseDao
{}/** * 所有dao的公用的方法,都在这里实现 * @author Jie.Yuan * */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(); } /** * 主键查询 * @param id 主键值 * @return 返回封装后的对象 */ 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); } }}

 

这里额外回顾反射,直接看代码:

1 public class Admin { 2  3     // Field 4     private int id = 1000; 5     private String name = "匿名"; 6      7     // Constructor 8     public Admin(){ 9         System.out.println("Admin.Admin()");10     }11     public Admin(String name){12         System.out.println("Admin.Admin()" + name);13     }14     15     // Method16     public int getId() {17         return id;18     }19     public void setId(int id) {20         this.id = id;21     }22     public String getName() {23         return name;24     }25     public void setName(String name) {26         this.name = name;27     }28     29 }30 31 32 // 反射技术33 public class App {34 35     // 1. 创建对象36     @Test37     public void testInfo() throws Exception {38         // 类全名39         String className = "cn.itcast.c_reflect.Admin";40         // 得到类字节码41         Class
clazz = Class.forName(className);42 43 // 创建对象1: 默认构造函数简写44 //Admin admin = (Admin) clazz.newInstance();45 46 // 创建对象2: 通过带参数构造器创建对象47 Constructor
constructor = clazz.getDeclaredConstructor(String.class);48 Admin admin = (Admin) constructor.newInstance("Jack");49 50 }51 @Test52 //2. 获取属性名称、值53 public void testField() throws Exception {54 55 // 类全名56 String className = "cn.itcast.c_reflect.Admin";57 // 得到类字节码58 Class
clazz = Class.forName(className);59 // 对象60 Admin admin = (Admin) clazz.newInstance();61 62 // 获取所有的属性名称63 Field[] fs = clazz.getDeclaredFields();64 // 遍历:输出每一个属性名称、值65 for (Field f : fs) {66 // 设置强制访问67 f.setAccessible(true);68 // 名称69 String name = f.getName();70 // 值71 Object value = f.get(admin);72 73 System.out.println(name + value);74 }75 }76 77 @Test78 //3. 反射获取方法79 public void testMethod() throws Exception {80 81 // 类全名82 String className = "cn.itcast.c_reflect.Admin";83 // 得到类字节码84 Class
clazz = Class.forName(className);85 // 对象86 Admin admin = (Admin) clazz.newInstance();87 88 // 获取方法对象 public int getId() {
89 Method m = clazz.getDeclaredMethod("getId");90 // 调用方法91 Object r_value = m.invoke(admin);92 93 System.out.println(r_value);94 }95 96 }

3. 注解

  概述 

  注解与注释,

 

    注解,告诉编译器如何运行程序!

 

    注释, 给程序员阅读,对编译、运行没有影响;

 

 

 

  注解作用,

 

    1. 告诉编译器如何运行程序;

 

    2. 简化(取代)配置文件   【案例后再看】

  常用的注解,

  

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

 

  自定义注解

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

     a、注解基本写法

 

/** * 自定义注解  (描述一个作者) * @author Jie.Yuan * */public @interface Author {    /**     * 注解属性     *       1. 修饰为默认或public     *    2. 不能有主体     */    String name();    int age();}//使用自定义注解@Author(name = "Jet", age = 30)    public void save() {    }

  b.带默认值的注解

 

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

 

 

 

 c、默认名臣的注解

  注解属性的默认默认名称是value

 

1 public @interface Author {2     // 如果注解名称为value,使用时候可以省略名称,直接给值3     // (且注解只有一个属性时候才可以省略名称)4     String value();5 }6 7 使用8 @Author("Jet")9 @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)   注解在运行时期有效

 

注解的反射

 

1 @Id 2     @Author(remark = "保存信息!!!", age = 19) 3     public void save() throws Exception { 4         // 获取注解信息: name/age/remark 5          6          7         // 1. 先获取代表方法的Method类型; 8         Class clazz = App_2.class; 9         Method m = clazz.getMethod("save");10         11         // 2. 再获取方法上的注解12         Author author = m.getAnnotation(Author.class);13         // 获取输出注解信息14         System.out.println(author.authorName());15         System.out.println(author.age());16         System.out.println(author.remark());17     }

 

4. 注解,优化BaseDao的代码

当表名与数据库名称不一致、 字段与属性不一样、主键不叫id, 上面的BaseDao不能用!

这是,

可以通过配置文件(XML) 解决!

 

 

注解:

简化XML配置, 程序处理非常方便!

(不便于维护: 例如修改字段名,要重新编译!)

 

XML

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

 

1 当表名与数据库名称不一致、 字段与属性不一样、主键不叫id, 上面的BaseDao不能用! 2 这是, 3     可以通过配置文件(XML) 解决! 4  5  6 注解: 7     简化XML配置, 程序处理非常方便! 8     (不便于维护: 例如修改字段名,要重新编译!) 9 10 XML11     便于维护!  需要些读取代通过反射注解=ViewCode】

 

5. Log4J日志组件

 

程序中为什么用日志组件?

 

简单来说,为了项目后期部署上线后的维护、错误排查!

 

 

Log4j,  log for java, 开源的日志组件!

 

 

使用步骤:

 

1. 下载组件,引入jar文件;

 

log4j-1.2.11.jar

 

2. 配置 :  src/log4j.properties

 

3. 使用

 

# 通过根元素指定日志输出的级别、目的地(目的地可以同时指定多个~): #  日志输出优先级: 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.PatternLayoutlog4j.appender.file.layout.ConversionPattern=%d %c.%M()-%m%n

 

下面是使用log4j的示例代码

1 public class App { 2      3     Log log = LogFactory.getLog(App.class); 4      5     @Test 6     public void save() { 7         try { 8             log.info("保存: 开始进入保存方法"); 9 10             int i = 1/0;11             12             log.info("保存: 执行保存结束,成功");13         } catch (Exception e) {14             15             log.error("执行App类Save()方法出现异常!");  // 异常16             17             e.printStackTrace();18         }19     }20     21     /*22      * 思考: 日志的输出级别作用?23      *      ----> 控制日志输出的内容。24      */25     @Test26     public void testLog() throws Exception {27         // 输出不同级别的提示28         log.debug("调试信息");29         log.info("信息提示");30         log.warn("警告");31         log.error("异常");32         33     }34 }35 public class Index extends HttpServlet {36     37     38     Log log =  LogFactory.getLog(Index.class);39 40     public void doGet(HttpServletRequest request, HttpServletResponse response)41             throws ServletException, IOException {42         try {43             log.info("进入servlet");44             int i = 1/0;45             log.info("进入servlet结束");46         } catch (Exception e) {47             log.error("计算异常!",e);48         }49     }50 }

 

6、枚举完全讲解

 

6.1基本概念

 

为什么使用枚举类

 

一些方法在运行的过程中所需要的值不是任意的,而是在一个范围中。在jdk1.5出现之前解决的方案,就是自己实现一个带有枚举功能的类。

 

l Jdk1.5新增的enum关键字用于定义一个枚举类,一旦定义一个枚举类之后,这个枚举类及自动继承了,java类库中的Enum

 

自定义枚举类/** * 自己手动的创建一个 枚举类 * 1、私有化,private,隐藏构造方法不让别人使用 * 2、蒂尼几个public static final的实例,给外界使用 *  * 手动实现的一个枚举类就是 Grade * 为Student类中定义一个,Grade,当为这个grade复制的时候,只能是Grade中定义好的几个public static final型的值,否则就会出现变异问题 * 一旦定义其他值就会出错,于是就达到了,枚举的作用,但是这样做还是比较麻烦的,于是,java中退出了一个枚举类 * @author YUCHEN * */class Grade{        private Grade(){            }        public static final Grade A = new Grade();    public static final Grade B = new Grade();    public static final Grade C = new Grade();    public static final Grade D = new Grade();    public static final Grade E = new Grade();}class Student{    private Grade grade;    //考试等级        public Grade getGrade()    {        return this.grade;    }        public void setGrade(Grade grade){        this.grade = grade;    }}

 

6.2默认构造函数枚举

 

按下面步骤,读下面案例:

 

1 // 1. 枚举类定义 2 enum Grade{ 3     A,B,C,D,E; 4 } 5 class Student{ 6     private String name; 7      8     // 2. 使用枚举类型 9     private Grade grade; //ABCDE10     public Grade getGrade() {11         return grade;12     }13     public void setGrade(Grade grade) {14         this.grade = grade;15     }16 }17 public class Demo1 {18     public static void main(String[] args) {19         Student stu = new Student();20         // 3. 给枚举类型赋值,只能是枚举类定义的值(第1步中所定义)21         stu.setGrade(Grade.A);22         23         System.out.println(stu.getGrade());24     }25 }
View Code

 

上述定义的枚举为默认构造函数枚举, 也可以这样

 

1 // 1. 枚举类定义2 enum Grade{3     A(),B(),C(),D(),E();4     // 必须为私有5     private Grade(){6     }7 }

 

此时,Grade类中有一个默认无参数构造函数

 

6.3有参构造函数

 

1 // 1. 带参数构造函数的枚举定义 2 enum Grade{ 3     A("100-90"),B("90-80"),C("80-70"),D("70-60"),E("60-0"); 4      5     private String value; 6     // 定义get方法返回数据 7     public String getValue() { 8         return value; 9     }10     11     private Grade(String value) {12         this.value = value;13     }14 }15 class Student{16     // 2. 使用枚举类型17     private Grade grade; //ABCDE18     public Grade getGrade() {19         return grade;20     }21     public void setGrade(Grade grade) {22         this.grade = grade;23     }24 }25 public class Demo1 {26     public static void main(String[] args) {27         Student stu = new Student();28         // 3. 给枚举类型赋值29         stu.setGrade(Grade.A);30         // 输出对应的“分数”31         System.out.println(stu.getGrade().getValue());32     }33 }

 

 

枚举类中抽象方法的定义

1 // 1. 带参数构造函数的枚举定义 2 // 并且需要返回更多的信息, 优秀,良好,好,一般,差 3 enum Grade{ 4     A("100-90"){ 5         public String getLocalStr() { 6             return "优秀"; 7         } 8     } 9     10     ,B("90-80"){11         public String getLocalStr() {12             return "良好";13         }14     }15     16     ,C("80-70"){17         public String getLocalStr() {18             return "好";19         }20     }21     22     ,D("70-60"){23         public String getLocalStr() {24             return "一般";25         }26     }27     28     ,E("60-0"){29         public String getLocalStr() {30             return "差";31         }32     };33     34     private String value;35     // 定义get方法返回数据36     public String getValue() {37         return value;38     }39     40     private Grade(String value) {41         this.value = value;42     }43     44     // 返回成绩段对应的“描述”, 需要每个对象重新实现次方法45     public abstract String getLocalStr();46 }47 class Student{48     // 2. 使用枚举类型49     private Grade grade; //ABCDE50     public Grade getGrade() {51         return grade;52     }53     public void setGrade(Grade grade) {54         this.grade = grade;55     }56 }57 public class Demo1 {58     public static void main(String[] args) {59         Student stu = new Student();60         // 3. 给枚举类型赋值61         stu.setGrade(Grade.A);62         // 输出对应的“分数”63         System.out.println(stu.getGrade().getValue());64         65         // 输出描述66         System.out.println(stu.getGrade().getLocalStr());67     }68 }
View Code

 

给我的体验忒儿的

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢复内容结束---

1、泛型

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

  a、概述:泛型是JDK1.5以后才有的, 可以在编译时期进行类型检查,且可以避免频繁类型转化!

1 // 运行时期异常  2     @Test 3     public void testGeneric() throws Exception { 4         // 集合的声明 5         List list = new ArrayList(); 6         list.add("China"); 7         list.add(1); 8          9         // 集合的使用10         String str = (String) list.get(1);11         12     }13     14     // 使用泛型15     @Test16     public void testGeneric2() throws Exception {17         // 声明泛型集合的时候指定元素的类型18         List
list = new ArrayList
();19 list.add("China");20 // list.add(1);// 编译时期报错21 22 String str = list.get(1); 23 }

 

  泛型擦除,泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!

 

1 /*2      * 泛型擦除实例 3      4     public void save(List
p){5 }6 public void save(List
d){ // 报错: 与上面方法编译后一样7 }8 */

 

  泛型的写法:

1 // 泛型写法 2     @Test 3     public void testGeneric3() throws Exception { 4         // 声明泛型集合,集合两端类型必须一致 5         List list = new ArrayList(); 6         List
list1 = new ArrayList
(); 7 List list2 = new ArrayList
(); 8 List
list3 = new ArrayList(); 9 10 // 错误11 //List
list4 = new ArrayList
();12 // 错误: 泛型类型必须是引用类型,不能为基本类型13 List
list5 = new ArrayList
();14 }

 b. 泛型方法/泛型类/泛型接口

  作用:

  设计公用的类、方法,对公用的业务实现进行抽取!

  使程序更灵活!

 

  1. 泛型方法:

 

1 public class GenericDemo { 2  3     // 定义泛型方法 4     public 
T save(T t,K k) { 5 return null; 6 } 7 8 // 测试方法 9 @Test10 public void testMethod() throws Exception {11 // 使用泛型方法: 在使用泛型方法的时候,确定泛型类型12 save(1.0f, 1);13 }14 }

 

  2. 泛型类:

 

1 public class GenericDemo
{ 2 3 // 定义泛型方法 4 public
T save(T t,K k) { 5 return null; 6 } 7 8 public void update(T t) { 9 10 }11 12 // 测试方法13 @Test14 public void testMethod() throws Exception {15 16 // 泛型类: 在创建爱泛型类对象的时候,确定类型17 GenericDemo
demo = new GenericDemo
();18 demo.save("test", 1);19 }20 }

 

  3. 泛型接口:

1 /** 2  * 泛型接口 3  * @author Jie.Yuan 4  * 5  * @param 
6 */ 7 public interface IBaseDao
{ 8 void save(T t ); 9 void update(T t );10 }11 12 =======================================13 泛型接口类型确定: 实现泛型接口的类也是抽象,那么类型在具体的实现中确定或创建泛型类的时候确定14 public class BaseDao
implements IBaseDao
{15 ======================================16 泛型=接口类型确定: 在业务实现类中直接确定接口的类型17 public class PersonDao implements IBaseDao
{18 }

 

 c. 泛型关键字 

  泛型中:

 

    ?    指定只是接收值

 

    extends      元素的类型必须继承自指定的类

 

    super        元素的类型必须是指定的类的父类

  关键字  ?

1 /** 2  * 泛型, 涉及到一些关键字 3  *  4  * Ctrl + shift + R   查看当前项目中类 5  * Ctrl + shift + T   查看源码jar包中的类 6  * @author Jie.Yuan 7  * 8  */ 9 public class App_extends_super {10     11     //只带泛型特征的方法12     public void save(List
list) {13 // 只能获取、迭代list; 不能编辑list14 }15 16 @Test17 public void testGeneric() throws Exception {18 19 // ? 可以接收任何泛型集合, 但是不能编辑集合值; 所以一般在方法参数中用20 List
list = new ArrayList
();21 //list.add("");// 报错22 }23 }

 

  关键字  extends    【上限】

 

1 public class App_extends_super { 2      3      4     /** 5      * list集合只能处理 Double/Float/Integer等类型 6      * 限定元素范围:元素的类型要继承自Number类  (上限) 7      * @param list 8      */ 9     public void save(List
list) {10 }11 12 @Test13 public void testGeneric() throws Exception {14 List
list_1 = new ArrayList
();15 List
list_2 = new ArrayList
();16 List
list_3 = new ArrayList
();17 18 List
list_4 = new ArrayList
();19 20 // 调用21 save(list_1);22 save(list_2);23 save(list_3);24 //save(list_4);25 }26 }

 

  关键字  super     【下限】

 

1 /** 2  * 泛型, 涉及到一些关键字 3  *  4  * Ctrl + shift + R   查看当前项目中类 5  * Ctrl + shift + T   查看源码jar包中的类 6  * @author Jie.Yuan 7  * 8  */ 9 public class App_super {10     11     12     /**13      * super限定元素范围:必须是String父类   【下限】14      * @param list15      */16     public void save(List
list) {17 }18 19 @Test20 public void testGeneric() throws Exception {21 // 调用上面方法,必须传入String的父类22 List list1 = new ArrayList();23 List
list2 = new ArrayList
();24 25 List
list3 = new ArrayList
();26 //save(list3);27 }28 }

 

  d. 泛型的反射

 

    案例,设置通用方法,会用到反射泛型!下面有简单代码

 

 

  步骤:

 

  1. 案例分析 /  实现

 

  2. 涉及知识点(jdk api)

 

  3. 优化 / 反射泛型

 

 

 

 

  反射泛型涉及API

 

  Student    类型的表示

 

  Id   name

 

   参数化类型的表示

 

  ArrayList<String>();

 

 

 

  Type    接口,任何类型默认的接口!

 

          包括: 引用类型、原始类型、参数化类型

 

 

 

  List<String>  list   =  new   ArrayList<String>();

 

  泛型集合:    list

 

  集合元素定义:new   ArrayList<String>();  中的String

 

  参数化类型   

 

  即:ArrayList<String> ” 为参数化类型

 

public class AdminDao extends BaseDao
{}public class AccountDao extends BaseDao
{}/** * 所有dao的公用的方法,都在这里实现 * @author Jie.Yuan * */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(); } /** * 主键查询 * @param id 主键值 * @return 返回封装后的对象 */ 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); } }}

 

这里额外回顾反射,直接看代码:

1 public class Admin { 2  3     // Field 4     private int id = 1000; 5     private String name = "匿名"; 6      7     // Constructor 8     public Admin(){ 9         System.out.println("Admin.Admin()");10     }11     public Admin(String name){12         System.out.println("Admin.Admin()" + name);13     }14     15     // Method16     public int getId() {17         return id;18     }19     public void setId(int id) {20         this.id = id;21     }22     public String getName() {23         return name;24     }25     public void setName(String name) {26         this.name = name;27     }28     29 }30 31 32 // 反射技术33 public class App {34 35     // 1. 创建对象36     @Test37     public void testInfo() throws Exception {38         // 类全名39         String className = "cn.itcast.c_reflect.Admin";40         // 得到类字节码41         Class
clazz = Class.forName(className);42 43 // 创建对象1: 默认构造函数简写44 //Admin admin = (Admin) clazz.newInstance();45 46 // 创建对象2: 通过带参数构造器创建对象47 Constructor
constructor = clazz.getDeclaredConstructor(String.class);48 Admin admin = (Admin) constructor.newInstance("Jack");49 50 }51 @Test52 //2. 获取属性名称、值53 public void testField() throws Exception {54 55 // 类全名56 String className = "cn.itcast.c_reflect.Admin";57 // 得到类字节码58 Class
clazz = Class.forName(className);59 // 对象60 Admin admin = (Admin) clazz.newInstance();61 62 // 获取所有的属性名称63 Field[] fs = clazz.getDeclaredFields();64 // 遍历:输出每一个属性名称、值65 for (Field f : fs) {66 // 设置强制访问67 f.setAccessible(true);68 // 名称69 String name = f.getName();70 // 值71 Object value = f.get(admin);72 73 System.out.println(name + value);74 }75 }76 77 @Test78 //3. 反射获取方法79 public void testMethod() throws Exception {80 81 // 类全名82 String className = "cn.itcast.c_reflect.Admin";83 // 得到类字节码84 Class
clazz = Class.forName(className);85 // 对象86 Admin admin = (Admin) clazz.newInstance();87 88 // 获取方法对象 public int getId() {
89 Method m = clazz.getDeclaredMethod("getId");90 // 调用方法91 Object r_value = m.invoke(admin);92 93 System.out.println(r_value);94 }95 96 }

3. 注解

  概述 

  注解与注释,

 

    注解,告诉编译器如何运行程序!

 

    注释, 给程序员阅读,对编译、运行没有影响;

 

 

 

  注解作用,

 

    1. 告诉编译器如何运行程序;

 

    2. 简化(取代)配置文件   【案例后再看】

  常用的注解,

  

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

 

  自定义注解

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

     a、注解基本写法

 

/** * 自定义注解  (描述一个作者) * @author Jie.Yuan * */public @interface Author {    /**     * 注解属性     *       1. 修饰为默认或public     *    2. 不能有主体     */    String name();    int age();}//使用自定义注解@Author(name = "Jet", age = 30)    public void save() {    }

  b.带默认值的注解

 

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

 

 

 

 c、默认名臣的注解

  注解属性的默认默认名称是value

 

1 public @interface Author {2     // 如果注解名称为value,使用时候可以省略名称,直接给值3     // (且注解只有一个属性时候才可以省略名称)4     String value();5 }6 7 使用8 @Author("Jet")9 @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)   注解在运行时期有效

 

注解的反射

 

1 @Id 2     @Author(remark = "保存信息!!!", age = 19) 3     public void save() throws Exception { 4         // 获取注解信息: name/age/remark 5          6          7         // 1. 先获取代表方法的Method类型; 8         Class clazz = App_2.class; 9         Method m = clazz.getMethod("save");10         11         // 2. 再获取方法上的注解12         Author author = m.getAnnotation(Author.class);13         // 获取输出注解信息14         System.out.println(author.authorName());15         System.out.println(author.age());16         System.out.println(author.remark());17     }

 

4. 注解,优化BaseDao的代码

当表名与数据库名称不一致、 字段与属性不一样、主键不叫id, 上面的BaseDao不能用!

这是,

可以通过配置文件(XML) 解决!

 

 

注解:

简化XML配置, 程序处理非常方便!

(不便于维护: 例如修改字段名,要重新编译!)

 

XML

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

 

1 当表名与数据库名称不一致、 字段与属性不一样、主键不叫id, 上面的BaseDao不能用! 2 这是, 3     可以通过配置文件(XML) 解决! 4  5  6 注解: 7     简化XML配置, 程序处理非常方便! 8     (不便于维护: 例如修改字段名,要重新编译!) 9 10 XML11     便于维护!  需要些读取代通过反射注解=ViewCode】

 

5. Log4J日志组件

 

程序中为什么用日志组件?

 

简单来说,为了项目后期部署上线后的维护、错误排查!

 

 

Log4j,  log for java, 开源的日志组件!

 

 

使用步骤:

 

1. 下载组件,引入jar文件;

 

log4j-1.2.11.jar

 

2. 配置 :  src/log4j.properties

 

3. 使用

 

# 通过根元素指定日志输出的级别、目的地(目的地可以同时指定多个~): #  日志输出优先级: 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.PatternLayoutlog4j.appender.file.layout.ConversionPattern=%d %c.%M()-%m%n

 

下面是使用log4j的示例代码

1 public class App { 2      3     Log log = LogFactory.getLog(App.class); 4      5     @Test 6     public void save() { 7         try { 8             log.info("保存: 开始进入保存方法"); 9 10             int i = 1/0;11             12             log.info("保存: 执行保存结束,成功");13         } catch (Exception e) {14             15             log.error("执行App类Save()方法出现异常!");  // 异常16             17             e.printStackTrace();18         }19     }20     21     /*22      * 思考: 日志的输出级别作用?23      *      ----> 控制日志输出的内容。24      */25     @Test26     public void testLog() throws Exception {27         // 输出不同级别的提示28         log.debug("调试信息");29         log.info("信息提示");30         log.warn("警告");31         log.error("异常");32         33     }34 }35 public class Index extends HttpServlet {36     37     38     Log log =  LogFactory.getLog(Index.class);39 40     public void doGet(HttpServletRequest request, HttpServletResponse response)41             throws ServletException, IOException {42         try {43             log.info("进入servlet");44             int i = 1/0;45             log.info("进入servlet结束");46         } catch (Exception e) {47             log.error("计算异常!",e);48         }49     }50 }

 

6、枚举完全讲解

 

6.1基本概念

 

为什么使用枚举类

 

一些方法在运行的过程中所需要的值不是任意的,而是在一个范围中。在jdk1.5出现之前解决的方案,就是自己实现一个带有枚举功能的类。

 

l Jdk1.5新增的enum关键字用于定义一个枚举类,一旦定义一个枚举类之后,这个枚举类及自动继承了,java类库中的Enum

 

自定义枚举类/** * 自己手动的创建一个 枚举类 * 1、私有化,private,隐藏构造方法不让别人使用 * 2、蒂尼几个public static final的实例,给外界使用 *  * 手动实现的一个枚举类就是 Grade * 为Student类中定义一个,Grade,当为这个grade复制的时候,只能是Grade中定义好的几个public static final型的值,否则就会出现变异问题 * 一旦定义其他值就会出错,于是就达到了,枚举的作用,但是这样做还是比较麻烦的,于是,java中退出了一个枚举类 * @author YUCHEN * */class Grade{        private Grade(){            }        public static final Grade A = new Grade();    public static final Grade B = new Grade();    public static final Grade C = new Grade();    public static final Grade D = new Grade();    public static final Grade E = new Grade();}class Student{    private Grade grade;    //考试等级        public Grade getGrade()    {        return this.grade;    }        public void setGrade(Grade grade){        this.grade = grade;    }}

 

6.2默认构造函数枚举

 

按下面步骤,读下面案例:

 

1 // 1. 枚举类定义 2 enum Grade{ 3     A,B,C,D,E; 4 } 5 class Student{ 6     private String name; 7      8     // 2. 使用枚举类型 9     private Grade grade; //ABCDE10     public Grade getGrade() {11         return grade;12     }13     public void setGrade(Grade grade) {14         this.grade = grade;15     }16 }17 public class Demo1 {18     public static void main(String[] args) {19         Student stu = new Student();20         // 3. 给枚举类型赋值,只能是枚举类定义的值(第1步中所定义)21         stu.setGrade(Grade.A);22         23         System.out.println(stu.getGrade());24     }25 }
View Code

 

上述定义的枚举为默认构造函数枚举, 也可以这样

 

1 // 1. 枚举类定义2 enum Grade{3     A(),B(),C(),D(),E();4     // 必须为私有5     private Grade(){6     }7 }

 

此时,Grade类中有一个默认无参数构造函数

 

6.3有参构造函数

 

1 // 1. 带参数构造函数的枚举定义 2 enum Grade{ 3     A("100-90"),B("90-80"),C("80-70"),D("70-60"),E("60-0"); 4      5     private String value; 6     // 定义get方法返回数据 7     public String getValue() { 8         return value; 9     }10     11     private Grade(String value) {12         this.value = value;13     }14 }15 class Student{16     // 2. 使用枚举类型17     private Grade grade; //ABCDE18     public Grade getGrade() {19         return grade;20     }21     public void setGrade(Grade grade) {22         this.grade = grade;23     }24 }25 public class Demo1 {26     public static void main(String[] args) {27         Student stu = new Student();28         // 3. 给枚举类型赋值29         stu.setGrade(Grade.A);30         // 输出对应的“分数”31         System.out.println(stu.getGrade().getValue());32     }33 }

 

6.4枚举类中抽象方法的定义

1 // 1. 带参数构造函数的枚举定义 2 // 并且需要返回更多的信息, 优秀,良好,好,一般,差 3 enum Grade{ 4     A("100-90"){ 5         public String getLocalStr() { 6             return "优秀"; 7         } 8     } 9     10     ,B("90-80"){11         public String getLocalStr() {12             return "良好";13         }14     }15     16     ,C("80-70"){17         public String getLocalStr() {18             return "好";19         }20     }21     22     ,D("70-60"){23         public String getLocalStr() {24             return "一般";25         }26     }27     28     ,E("60-0"){29         public String getLocalStr() {30             return "差";31         }32     };33     34     private String value;35     // 定义get方法返回数据36     public String getValue() {37         return value;38     }39     40     private Grade(String value) {41         this.value = value;42     }43     44     // 返回成绩段对应的“描述”, 需要每个对象重新实现次方法45     public abstract String getLocalStr();46 }47 class Student{48     // 2. 使用枚举类型49     private Grade grade; //ABCDE50     public Grade getGrade() {51         return grade;52     }53     public void setGrade(Grade grade) {54         this.grade = grade;55     }56 }57 public class Demo1 {58     public static void main(String[] args) {59         Student stu = new Student();60         // 3. 给枚举类型赋值61         stu.setGrade(Grade.A);62         // 输出对应的“分数”63         System.out.println(stu.getGrade().getValue());64         65         // 输出描述66         System.out.println(stu.getGrade().getLocalStr());67     }68 }
View Code

 6.5枚举API

l Java中声明的枚举类,均是java.lang.Enum类的孩子,它继承了Enum类的所有方法。常用方法:

  • Stirng name()
  • Int ordinal()
  • Enum valueof(Class enumClass, String name)

自定义的枚举类

  • Enum valueof(String name)
  • Enum[] values() 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便

 

掌握枚举对象、枚举对象下标、枚举字符串:

 

1         // 1. 输出枚举名称 2         System.out.println(Grade.B.name());// -->B 3  4         // 2. 获取枚举的位置(下标) 5         System.out.println(Grade.B.ordinal()); 6  7         // 3. 字符串转换为枚举类型 8         Grade g = Grade.valueOf("B"); 9         // Grade g = Grade.valueOf(Grade.class, "B");// 用另外一个重载方法,也可以10         System.out.println(g.getLocalStr());11         12         // 字符串转换为枚举类型13         Grade grade = Enum.valueOf(Grade.class, "B");14         System.out.println(grade.getLocalStr());15         16         // 4. 遍历所有的枚举值17         Grade[] gs = Grade.values();18         for (Grade myGrade : gs) {19             System.out.println("myGrade-->" + myGrade);20         }

 

转载于:https://www.cnblogs.com/OliverZhang/p/6003178.html

你可能感兴趣的文章
我的友情链接
查看>>
mysql binlog row模式日志查看
查看>>
每日一Lua(3)-函数
查看>>
蓝鸥Unity开发基础二——课时18 单例
查看>>
Confluence 6 空间
查看>>
lua-resty-http上传数据
查看>>
heartbeat+ldirectord实现web与dns的高可用性
查看>>
luacurl安装
查看>>
JBoss的配置
查看>>
软件测试之Web实战测试
查看>>
Tomcat的参数配置及一般问题的解决
查看>>
Extjs 4 grid中的checkbox的加载时预选中【默认选中】
查看>>
JAVA CAS原理深度分析
查看>>
O2O?啥是“呕吐呕”?
查看>>
百度的疯狂 UC的隐忍
查看>>
我的友情链接
查看>>
AGG第三十五课 gsv_text 渲染ASCII字符
查看>>
查找组成一个偶数最接近的两个素数
查看>>
不怕狼一样的敌人,就怕狗一样的朋友
查看>>
bash基础特性
查看>>