泛型
泛型是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<String> list = new ArrayList<String>();
list.add("China");
//list.add(1);// 編譯時期報錯
String str = list.get(1);
}
泛型擦除,泛型只在編譯時期有效,編譯后的字節碼文件中不存在有泛型信息!
/*
* 泛型擦除實例
*/
public void save(List<Person> p){
}
public void save(List<Dept> d){ // 報錯: 與上面方法編譯后一樣
}
*/
泛型寫法
// 泛型寫法
@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();
// 錯誤
//List<Object> list4 = new ArrayList<String>();
// 錯誤: 泛型類型必須是引用類型,不能為基本類型
List<int> list5 = new ArrayList<int>();
}
泛型方法/泛型類/泛型接口
作用:
1. 設計公用的類、方法,對公用的業務實現進行抽取!
2. 使程序更靈活!
1. 泛型方法
public class GenericDemo {
// 定義泛型方法
public <K,T> T save(T t,K k) {
return null;
}
// 測試方法
@Test
public void testMethod() throws Exception {
// 使用泛型方法: 在使用泛型方法的時候,確定泛型類型
save(1.0f, 1);
}
}
2. 泛型類
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 {
// 泛型類: 在創建愛泛型類對象的時候,確定類型
GenericDemo<String> demo = new GenericDemo<String>();
demo.save("test", 1);
}
}
3. 泛型接口
public interface IBaseDao<T> {
void save(T t );
void update(T t );
}
//泛型接口類型確定: 實現泛型接口的類也是抽象,那么類型在具體的實現中確定或創建泛型類的時候確定
public class BaseDao<T> implements IBaseDao<T> {
}
//泛型接口類型確定: 在業務實現類中直接確定接口的類型
public class PersonDao implements IBaseDao<Person>{
}
泛型關鍵字
泛型中:
? 指定只是接收值
extends 元素的類型必須繼承自指定的類
super 元素的類型必須是指定的類的父類
1. 關鍵字 ?
public class App_extends_super {
//只帶泛型特征的方法
public void save(List<?> list) {
// 只能獲取、迭代list; 不能編輯list
}
@Test
public void testGeneric() throws Exception {
// ? 可以接收任何泛型集合, 但是不能編輯集合值; 所以一般在方法參數中用
List<?> list = new ArrayList<String>();
//list.add("");// 報錯
}
}
2. 關鍵字 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>();
// 調用
save(list_1);
save(list_2);
save(list_3);
//save(list_4);
}
}
3. 關鍵字 super [下限]
public class App_super {
/**
* super限定元素范圍:必須是String父類 【下限】
* @param list
*/
public void save(List<? super String> list) {
}
@Test
public void testGeneric() throws Exception {
// 調用上面方法,必須傳入String的父類
List<Object> list1 = new ArrayList<Object>();
List<String> list2 = new ArrayList<String>();
List<Integer> list3 = new ArrayList<Integer>();
//save(list3);
}
}
泛型的反射
- 反射泛型涉及API:
- ParameterizedType 參數化類型的表示
- Type 接口,任何類型默認的接口!包括: 引用類型、原始類型、參數化類型
List<String> list = new ArrayList<String>();
泛型集合: list
集合元素定義: new ArrayList<String>(); 中的String
參數化類型: ParameterizedType 即:“ArrayList<String> ” 為參數化類型
反射泛型案例
public class AdminDao extends BaseDao<Admin> {}
public class AccountDao extends BaseDao<Account> {}
/**
* 所有dao的公用的方法,都在這里實現
*/
public class BaseDao<T>{
// 保存當前運行類的參數化類型中的實際的類型
private Class clazz;
// 表名
private String tableName;
// 構造函數: 1. 獲取當前運行類的參數化類型; 2. 獲取參數化類型中實際類型的定義(class)
public BaseDao(){
// this 表示當前運行類 (AccountDao/AdminDao)
// this.getClass() 當前運行類的字節碼(AccountDao.class/AdminDao.class)
// this.getClass().getGenericSuperclass(); 當前運行類的父類,即為BaseDao<Account>
// 其實就是“參數化類型”, ParameterizedType
Type type = this.getClass().getGenericSuperclass();
// 強制轉換為“參數化類型” 【BaseDao<Account>】
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>
* ----》 得到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);
}
}
/**
* 查詢全部
* @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);
}
}
}
反射
- 反射,可以在運行時期動態創建對象;獲取對象的屬性、方法
public class Admin {
// Field
private int id = 1000;
private String name = "匿名";
// Constructor
public Admin(){
System.out.println("Admin.Admin()");
}
public Admin(String name){
System.out.println("Admin.Admin()" + name);
}
// Method
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 反射技術
public class App {
// 1. 創建對象
@Test
public void testInfo() throws Exception {
// 類全名
String className = "com.runbean_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 = "com.runbean_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 = "com.runbean_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. 簡化(取代)配置文件
自定義注解
1. 注解基本寫法
/**
* 自定義注解 (描述一個作者)
*
*/
public @interface Author {
/**
* 注解屬性
* 1. 修飾為默認或public
* 2. 不能有主體
*/
String name();
int age();
}
//使用
@Author(name = "runBean", age = 30)
public void save() {
}
//帶默認值的注解
public @interface Author {
String name();
int age() default 30; // 帶默認值的注解; 使用的時候就可以不寫此屬性值
}
2. 默認名稱的注解
public @interface Author {
// 如果注解名稱為value,使用時候可以省略名稱,直接給值
// (且注解只有一個屬性時候才可以省略名稱)
String value();
}
//使用
@Author("runBean")
@Author(value = "runBean")
public void save() {
}
//注解屬性類型為數組:
public @interface Author {
String[] value() default {"test1","test2"};
}
//使用:
@Author({“”,“”})
public void save() {
}
元注解
元注解,表示注解的注解!
指定注解的可用范圍:
@Target({
TYPE, 類
FIELD, 字段
METHOD, 方法
PARAMETER, 參數
CONSTRUCTOR, 構造器
LOCAL_VARIABLE 局部變量
})
指定注解的聲明周期
@Retention(RetentionPolicy.SOURCE) 注解只在源碼級別有效
@Retention(RetentionPolicy.CLASS) 注解在字節碼即別有效 默認值
@Retention(RetentionPolicy.RUNTIME) 注解在運行時期有效
1.注解的反射
@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());
}
注解:
簡化XML配置, 程序處理非常方便!
不便於維護: 例如修改字段名,要重新編譯
XML
便於維護! 需要些讀取代碼!