掌握的知識 : 基本用法、泛型擦除、泛型類/泛型方法/泛型接口、泛型關(guān)鍵字、反射泛型(案例)
泛型
- 概述 : 泛型是JDK1.5以后才有的, 可以在編譯時(shí)期進(jìn)行類型檢查,且可以避免頻繁類型轉(zhuǎn)化
// 運(yùn)行時(shí)期異常
@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 {
// 聲明泛型集合的時(shí)候指定元素的類型
List<String> list = new ArrayList<String>();
list.add("China");
// list.add(1);// 編譯時(shí)期報(bào)錯(cuò)
String str = list.get(1);
}
- 泛型擦除 : 泛型只在編譯時(shí)期有效,編譯后的字節(jié)碼文件中不存在有泛型信息!
//泛型擦除實(shí)例
public void save(List<Person> p){
}
public void save(List<Dept> d){ // 報(bào)錯(cuò): 與上面方法編譯后一樣
}
- 泛型寫法:
// 泛型寫法
@Test
public void testGeneric3() throws Exception {
// 聲明泛型集合,集合兩端類型必須一致
List<Object> list = new ArrayList<Object>();
List<String> list1 = new ArrayList<String>();
List list2 = new ArrayList<String>();
List<Integer> list3 = new ArrayList();
// 錯(cuò)誤
//List<Object> list4 = new ArrayList<String>();
// 錯(cuò)誤: 泛型類型必須是引用類型,不能為基本類型
List<int> list5 = new ArrayList<int>();
}
- 泛型方法 / 泛型類 / 泛型接口 :
- 作用 :
a> 設(shè)計(jì)公用的類、方法,對公用的業(yè)務(wù)實(shí)現(xiàn)進(jìn)行抽取!
b> 使程序更靈活! - 泛型方法 :
- 作用 :
public class GenericDemo {
// 定義泛型方法
public <K,T> T save(T t,K k) {
return null;
}
// 測試方法
@Test
public void testMethod() throws Exception {
// 使用泛型方法: 在使用泛型方法的時(shí)候,確定泛型類型
save(1.0f, 1);
}
}
- 泛型類 :
public class GenericDemo<T> {
// 定義泛型方法
public <K> T save(T t,K k) {
return null;
}
public void update(T t) {
}
// 測試方法
@Test
public void testMethod() throws Exception {
// 泛型類: 在創(chuàng)建愛泛型類對象的時(shí)候,確定類型
GenericDemo<String> demo = new GenericDemo<String>();
demo.save("test", 1);
}
}
- 泛型接口 :
// 泛型接口
public interface IBaseDao<T> {
void save(T t );
void update(T t );
}
泛型接口類型確定 :
a> 實(shí)現(xiàn)泛型接口的類也是抽象,那么類型在具體的實(shí)現(xiàn)中確定或創(chuàng)建泛型類的時(shí)候確定 :public class BaseDao<T> implements IBaseDao<T> {}
b> 泛型接口類型確定: 在業(yè)務(wù)實(shí)現(xiàn)類中直接確定接口的類型 :public class PersonDao implements IBaseDao<Person>{}
-
泛型關(guān)鍵字
-
?
: 指定只是接收值
-
//泛型, 涉及到一些關(guān)鍵字
// Ctrl + shift + R 查看當(dāng)前項(xiàng)目中類
// Ctrl + shift + T 查看源碼jar包中的類
public class App_extends_super {
//只帶泛型特征的方法
public void save(List<?> list) {
// 只能獲取、迭代list; 不能編輯list
}
@Test
public void testGeneric() throws Exception {
// ? 可以接收任何泛型集合, 但是不能編輯集合值; 所以一般在方法參數(shù)中用
List<?> list = new ArrayList<String>();
//list.add("");// 報(bào)錯(cuò)
}
}
-
extends
: 元素的類型必須繼承自指定的類
public class App_extends_super {
/**
* list集合只能處理 Double/Float/Integer等類型
* 限定元素范圍:元素的類型要繼承自Number類 (上限)
* @param list
*/
public void save(List<? extends Number> list) {
}
@Test
public void testGeneric() throws Exception {
List<Double> list_1 = new ArrayList<Double>();
List<Float> list_2 = new ArrayList<Float>();
List<Integer> list_3 = new ArrayList<Integer>();
List<String> list_4 = new ArrayList<String>();
// 調(diào)用
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<? super String> list) {
}
@Test
public void testGeneric() throws Exception {
// 調(diào)用上面方法,必須傳入String的父類
List<Object> list1 = new ArrayList<Object>();
List<String> list2 = new ArrayList<String>();
List<Integer> list3 = new ArrayList<Integer>();
//save(list3);
}
}
- 泛型的反射
// 所有dao的公用的方法,都在這里實(shí)現(xiàn)
public class BaseDao<T>{
// 保存當(dāng)前運(yùn)行類的參數(shù)化類型中的實(shí)際的類型
private Class clazz;
// 表名
private String tableName;
// 構(gòu)造函數(shù): 1. 獲取當(dāng)前運(yùn)行類的參數(shù)化類型; 2. 獲取參數(shù)化類型中實(shí)際類型的定義(class)
public BaseDao(){
// this 表示當(dāng)前運(yùn)行類 (AccountDao/AdminDao)
// this.getClass() 當(dāng)前運(yùn)行類的字節(jié)碼(AccountDao.class/AdminDao.class)
// this.getClass().getGenericSuperclass(); 當(dāng)前運(yùn)行類的父類,即為BaseDao<Account>
// 其實(shí)就是“參數(shù)化類型”, ParameterizedType
Type type = this.getClass().getGenericSuperclass();
// 強(qiáng)制轉(zhuǎn)換為“參數(shù)化類型” 【BaseDao<Account>】
ParameterizedType pt = (ParameterizedType) type;
// 獲取參數(shù)化類型中,實(shí)際類型的定義 【new Type[]{Account.class}】
Type types[] = pt.getActualTypeArguments();
// 獲取數(shù)據(jù)的第一個(gè)元素:Accout.class
clazz = (Class) types[0];
// 表名 (與類名一樣,只要獲取類名就可以)
tableName = clazz.getSimpleName();
}
// 主鍵查詢
public T findById(int id){
/*
* 1. 知道封裝的對象的類型
* 2. 表名【表名與對象名稱一樣, 且主鍵都為id】
*
* 即,
* ---》得到當(dāng)前運(yùn)行類繼承的父類 BaseDao<Account>
* ----》 得到Account.class
*/
String sql = "select * from " + tableName + " where id=? ";
try {
return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 查詢?nèi)? * @return
*/
public List<T> getAll(){
String sql = "select * from " + tableName ;
try {
return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
反射復(fù)習(xí)
- 反射,可以在運(yùn)行時(shí)期動(dòng)態(tài)創(chuàng)建對象;獲取對象的屬性、方法;
- 反射技術(shù)實(shí)例 :
// 反射技術(shù)
public class App {
// 1. 創(chuàng)建對象
@Test
public void testInfo() throws Exception {
// 類全名
String className = "cn.itcast.c_reflect.Admin";
// 得到類字節(jié)碼
Class<?> clazz = Class.forName(className);
// 創(chuàng)建對象1: 默認(rèn)構(gòu)造函數(shù)簡寫
//Admin admin = (Admin) clazz.newInstance();
// 創(chuàng)建對象2: 通過帶參數(shù)構(gòu)造器創(chuàng)建對象
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";
// 得到類字節(jié)碼
Class<?> clazz = Class.forName(className);
// 對象
Admin admin = (Admin) clazz.newInstance();
// 獲取所有的屬性名稱
Field[] fs = clazz.getDeclaredFields();
// 遍歷:輸出每一個(gè)屬性名稱、值
for (Field f : fs) {
// 設(shè)置強(qiáng)制訪問
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";
// 得到類字節(jié)碼
Class<?> clazz = Class.forName(className);
// 對象
Admin admin = (Admin) clazz.newInstance();
// 獲取方法對象 public int getId() {
Method m = clazz.getDeclaredMethod("getId");
// 調(diào)用方法
Object r_value = m.invoke(admin);
System.out.println(r_value);
}
}
注解
- 概述
- 注解與注釋 :
- 注解 : 告訴編譯器如何運(yùn)行程序!
- 注釋 : 給程序員閱讀,對編譯、運(yùn)行沒有影響;
- 注解的作用 :
- 告訴編譯器如何運(yùn)行程序;
- 簡化(取代)配置文件 【案例后再看】
- 常用的注解 :
- 注解與注釋 :
// 重寫父類的方法
@Override
public String toString() {
return super.toString();
}
// 抑制編譯器警告
@SuppressWarnings({"unused","unchecked"})
private void save() {
List list = null;
}
// 標(biāo)記方法以及過時(shí)
@Deprecated
private void save1() {
}
- 自定義注解
a. 注解基本寫法
/**
* 自定義注解 (描述一個(gè)作者)
*
*/
public @interface Author {
/**
* 注解屬性
* 1. 修飾為默認(rèn)或public
* 2. 不能有主體
*/
String name();
int age();
}
// 使用
@Author(name = "Jet", age = 30)
public void save() {
}
b. 帶默認(rèn)值的注解
public @interface Author {
/**
* 注解屬性
* 1. 修飾為默認(rèn)或public
* 2. 不能有主體
*/
String name();
int age() default 30; // 帶默認(rèn)值的注解; 使用的時(shí)候就可以不寫此屬性值
}
c. 默認(rèn)名稱的注解
public @interface Author {
// 如果注解名稱為value,使用時(shí)候可以省略名稱,直接給值
// (且注解只有一個(gè)屬性時(shí)候才可以省略名稱)
String value();
}
// 使用
@Author("Jet")
@Author(value = "Jet")
//注解屬性類型為數(shù)組
public @interface Author {
String[] value() default {"test1","test2"};
}
// 使用:
@Author({“”,“”})
public void save() {
}
- 元注解
- 元注解 : 表示注解的注解;
- 可以指定注解的可用范圍, 例 :
@Target({TYPE})
a> TYPE->類
b> FIELD->字段
c> METHOD->方法
d> PARAMETER->參數(shù)
e> CONSTRUCTOR->構(gòu)造器
f> LOCAL_VARIABLE->局部變量 - 指定注解的聲明周期, 例 :
@Retention(RetentionPolicy.SOURCE)
-
@Retention(RetentionPolicy.SOURCE)
: 注解只在源碼級別有效 -
@Retention(RetentionPolicy.CLASS)
: 注解在字節(jié)碼即別有效 默認(rèn)值 -
@Retention(RetentionPolicy.RUNTIME)
: 注解在運(yùn)行時(shí)期有效
-
- 可以指定注解的可用范圍, 例 :
- 元注解 : 表示注解的注解;
- 注解反射
@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日志組件
- 程序中為什么用日志組件?簡單來說,為了項(xiàng)目后期部署上線后的維護(hù)、錯(cuò)誤排查!Log4j, log for java, 開源的日志組件!
- 使用步驟:
- 下載組件,引入jar文件 :
log4j-1.2.11.jar
- 配置 : src/log4j.properties
- 使用
- 下載組件,引入jar文件 :
- code :
# 通過根元素指定日志輸出的級別、目的地:
# 日志輸出優(yōu)先級: 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
# 具體格式內(nèi)容
log4j.appender.console.layout.ConversionPattern=%d %p %c.%M()-%m%n
############# 日志輸出到文件 #############
log4j.appender.file=org.apache.log4j.RollingFileAppender
# 文件參數(shù): 指定日志文件路徑
log4j.appender.file.File=../logs/MyLog.log
# 文件參數(shù): 指定日志文件最大大小
log4j.appender.file.MaxFileSize=5kb
# 文件參數(shù): 指定產(chǎn)生日志文件的最大數(shù)目
log4j.appender.file.MaxBackupIndex=100
# 日志格式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %c.%M()-%m%n