小編給大家分享一下java泛型基本知識的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
泛型的基本使用
泛型是Java SE 1.5的新特性, 泛型的本質是參數化類型, 也就是說所操作的數據類型被指定為一個參數. 這種參數類型可以用在類、接口和方法的創建中, 分別稱為泛型類、泛型接口、泛型方法. Java語言引入泛型的好處是安全簡單.
今天就從以下幾個方面介紹一下java的泛型: 基礎, 泛型關鍵字, 泛型方法, 泛型類和接口.
基礎:
通過集合的泛型了解泛型的基本使用
public void testBasis(){
List<String> list = new ArrayList<String>();
// new ArrayList<int>();
}
//這是最基本的泛型使用, 就不多說了, 不過要注意的是泛型只能是引用數據類型, 不能是基本類型, 而且泛型只在編譯期有效, 在編譯后的class文件中是不存在泛型信息的注意: 泛型只在編譯期有效, 在編譯后的class文件中是不存在泛型信息的
泛型關鍵字:
通配符?表示任意引用類型, extends關鍵字表示子類及其本身, super關鍵字是表示父類及其本身. 通過一個例子看一下, 解釋說明都在例子中
public void testKeyWord() throws Exception {
//實例化參數類型必須指明具體類型
List<?> list = new ArrayList<String>();
//由于list中類型不明確, 所以不能進行添加操作
// list.add("sk");
//通配符?表示任意引用類型
List<List<?>> list1 = new ArrayList<List<?>>();
//list1的參數化類型是一個List, 而這個List也是一個參數化類型, 它的類型是任意類型, 所以list1可以添加任意List類型對象
list1.add(new ArrayList<Object>());
list1.add(new ArrayList<String>());
//實例化list2時指明了類型參數List, 只不過這個List是一個泛型類型
//從這里可以看到關鍵字extends的用法, 其實就是繼承, 如下這里的list2中的參數化類型List(在這里記為paramList)的參數化類型是繼承自Number的
//所以在list2在添加的時候只能添加參數化類型為Number及其子類的paramList
List<Integer> l1 = new ArrayList<Integer>();
List<Number> l2 = new ArrayList<Number>();
List<Object> l3 = new ArrayList<Object>();
List<List<? extends Number>> list2 = new ArrayList<List<? extends Number>>();
list2.add(l1);
list2.add(l2);
// list2.add(l3); //這里使用了extends關鍵字, 所以不能添加Number的父類
//相信大家也猜到了, 既然extends關鍵字表示子類及其本身, 那么super關鍵字是表示父類及其本身, 是的, 沒錯
//和上面的不一樣了, l1不能添加, 因為Integer是Number的子類, 并不是Number的父類
List<List<? super Number>> list3 = new ArrayList<List<? super Number>>();
// list3.add(l1); //這里使用了super關鍵字, 所以不能添加Number的子類
list3.add(l2);
list3.add(l3);
}泛型方法:
java中任何類型必須先定義才能使用, 泛型也是如此. 既然要使用泛型作為參數, 所以要先定義, 泛型的定義在訪問修飾符和返回類型之間, 注意不要掉了尖括號
//無返回值有參的方法, 參數為泛型
public <T> void show(T t){
System.out.println("t-=-=" + t);
}
//有返回值的有參方法, 只有一個參數化類型, 這里定義泛型的方式和上面一樣, 也是先定義后使用, 只不過這里的返回類型是泛型
public <T> T get(T t){
return t;
}
//有返回值的有參方法, 有多個參數化類型, 這里以兩個為例
public <T, K> K get(T t, K k){
return k;
}
@Test
public void testGeneric() throws Exception {
show(3);
show("generic");
System.out.println("----------------");
System.out.println("我返回Integer類型-" + get(4));
System.out.println("我返回String類型-" + get("returnGeneric"));
System.out.println("------------------");
System.out.println("我返回String類型-" + get(1, "a"));
System.out.println("我返回Integer類型-" + get("b", 2));
}本來想寫無參的泛型方法, 可是寫著寫著感覺那樣沒有什么意義, 不知道各位有什么見解.
泛型類和接口:
寫泛型類的時候只需要在類名后面加上泛型即可, 就像這樣
public class GenericClass<T> {
public T get(T t){
return t;
}
public void scr(T t){
System.out.println(t);
}
public void show(){
GenericClass<Integer> gc = new GenericClass<Integer>();
// GenericClass<T> gc1 = new GenericClass<T>();
gc.get(3);
gc.scr(5);
//下面2個會報錯
// gc1.get(3);
// gc1.scr(5);
}
}從上面的例子中可以看到, 參數化類型是在創建對象的時候具體化的, 那么除此之外, 還可以再什么時候具體化參數化類型呢?
如果是在繼承或實現中, 可以在子類或實現類中確定具體類型
使用java泛型設計通用方法
泛型是Java SE 1.5的新特性, 泛型的本質是參數化類型, 也就是說所操作的數據類型被指定為一個參數. 因此我們可以利用泛型和反射來設計一些通用方法. 現在有2張表, 一張user表和一張student表.
user:

student:

如果要根據id查詢數據, 你會怎么做呢?寫2個方法分別查詢user和student?其實這時候我們就可以使用泛型和反射寫一個通用的方法.
user的實體類:
private Integer id; private String username; private String password; private String hobby; //getXxx方法和setXxx方法
student實體類:
private Integer id; private String name; private Integer age; //getXxx方法和setXxx方法
BaseDao接口:
public interface BaseDao<T> {
//根據id查詢的方法
T findById(Integer id);
}BaseDaoImpl類, 實現了BaseDao接口, 通用方法就在這里面完成:
//設置為抽象的, 不讓他實例化, 讓其子類實例化就行了
//通過泛型設計通用方法的關鍵就是利用反射拿到泛型的具體類型
public abstract class BaseDaoImpl<T> implements BaseDao<T> {
private String tableName; //表名
private Class<T> actualType;//真實類型
/**
* findById(Integer id)這個方法被子類繼承了, 假設我們在UserDaoImpl中操作, 此時參數化類型T為User
* 下面的講解都假設是在UserDaoImpl中進行的
*/
//把公共部分可以放到構造方法中
@SuppressWarnings("unchecked")
public BaseDaoImpl() {
//返回類型是Type 是 Java 編程語言中所有類型的公共高級接口. 它們包括原始類型、參數化類型、數組類型、類型變量和基本類型.
//Type的已知子接口: ParameterizedType 表示參數化類型, 如 Collection<String>.
//getClass()得到UserDaoImpl的Class, 得到Class一般有3中方式: getClass(), 類名.class, Class.forName()
Type type = getClass().getGenericSuperclass();//獲取UserDaoImpl<User>的參數化類型的父類BaseDaoImpl<User>
//由于我們得到的是一個參數化類型, 所以轉成ParameterizedType, 因為需要使用里面的方法
ParameterizedType pt = (ParameterizedType) type;//強轉
Type[] actualTypeArr = pt.getActualTypeArguments();//獲取真實參數類型數組[User.class], 可以調試看到這里的值
actualType = (Class<T>) actualTypeArr[0];//數組只有一個元素
tableName = actualType.getSimpleName();
}
@Override
public T findById(Integer id) {
String sql = "select * from " + tableName + " where id = ?";
try {
return QRUtils.getQueryRunner().query(sql, new BeanHandler<T>(actualType), id);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}連接數據庫操作是用的c3p0和dbutils, 有關這方面的內容可以參看我以前的隨筆.
UserDao接口, 繼承BaseDao接口:
public interface UserDao<T> extends BaseDao<T> {
}UserDaoImpl類, 實現UserDao接口, 繼承BaseDaoImpl類, 可以看到里面什么方法也沒有:
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao<User> {
}StudentDao接口, 繼承BaseDao接口:
public interface StudentDao<T> extends BaseDao<T> {
}StudentDaoImpl類, 實現StudentDao接口, 繼承BaseDaoImpl類, 也可以看到里面什么方法也沒有:
public class StudentDaoImpl extends BaseDaoImpl<Student> implements StudentDao<Student> {
}從以上dao可以看到, 我是在繼承BaseDaoImpl類時把泛型具體化了.
測試:
@Test
public void testGeneric() throws Exception {
UserDao<User> userDao = new UserDaoImpl();
System.out.println(userDao.findById(1));
System.out.println("-------------------");
StudentDao<Student> studentDao = new StudentDaoImpl();
System.out.println(studentDao.findById(1));
}看一下測試的結果: 同一個方法把2張表中的數據都查出來了

看完了這篇文章,相信你對“java泛型基本知識的示例分析”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。