本篇內(nèi)容介紹了“Java泛型的概念”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
我們提供的服務(wù)有:成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、太倉(cāng)ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的太倉(cāng)網(wǎng)站制作公司
所謂泛型,就是允許在定義類(lèi)、接口時(shí)通過(guò)一個(gè)標(biāo)識(shí)表示類(lèi)中某個(gè)屬性的類(lèi)型或者是某個(gè)方法的返 回值及參數(shù)類(lèi)型。這個(gè)類(lèi)型參數(shù)將在使用時(shí)(例如,繼承或?qū)崿F(xiàn)這個(gè)接口,用這個(gè)類(lèi)型聲明變量、 創(chuàng)建對(duì)象時(shí)確定(即傳入實(shí)際的類(lèi)型參數(shù),也稱為類(lèi)型實(shí)參)。
從JDK 5.0以后,Java引入了“參數(shù)化類(lèi)型(Parameterized type)”的概念,允許我們?cè)趧?chuàng)建集合時(shí)再指定集合元素的類(lèi)型,正如:List<String>,這表明該List只能保存字符串類(lèi)型的對(duì)象。
JDK 5.0改寫(xiě)了集合框架中的全部接口和類(lèi),為這些接口、類(lèi)增加了泛型支持,從而可以在聲明集合變量、創(chuàng)建集合對(duì)象時(shí)傳入類(lèi)型實(shí)參。
集合容器類(lèi)在設(shè)計(jì)階段/聲明階段不能確定這個(gè)容器到底實(shí)際存的是什么類(lèi)型的對(duì)象,所以在JDK1.5之前只能把元素類(lèi)型設(shè)計(jì)為Object,JDK1.5之后使用泛型來(lái)解決。因?yàn)檫@個(gè)時(shí)候除了元素的類(lèi)型不確定,其他的部分是確定的,例如關(guān)于這個(gè)元素如何保存,如何管理等是確定的,因此此時(shí)把元素的類(lèi)型設(shè)計(jì)成一個(gè)參數(shù),這個(gè)類(lèi)型參數(shù)叫做泛型。Collection<E>,List<E>,ArrayList<E> 這個(gè)<E>就是類(lèi)型參數(shù),即泛型。
解決元素存儲(chǔ)的安全性問(wèn)題,好比商品、藥品標(biāo)簽,不會(huì)弄錯(cuò)。
解決獲取數(shù)據(jù)元素時(shí),需要類(lèi)型強(qiáng)制轉(zhuǎn)換的問(wèn)題,好比不用每回拿商品、藥品都要辨別。
Java泛型可以保證如果程序在編譯時(shí)沒(méi)有發(fā)岀警告,運(yùn)行時(shí)就不會(huì)產(chǎn)生ClassCastException異常。同時(shí),代碼更加簡(jiǎn)潔、健壯。
@Test
public void test1(){
ArrayList list = new ArrayList();
//需求:存放學(xué)生的成績(jī)
list.add(78);
list.add(76);
list.add(89);
list.add(88);
//問(wèn)題一:類(lèi)型不安全
// list.add("Tom");
for(Object score : list){
//問(wèn)題二:強(qiáng)轉(zhuǎn)時(shí),可能出現(xiàn)ClassCastException
int stuScore = (Integer) score;
System.out.println(stuScore);
}
}圖示:

//在集合中使用泛型,以ArrayList為例
@Test
public void test1(){
ArrayList<String> list = new ArrayList<>();
list.add("AAA");
list.add("BBB");
list.add("FFF");
list.add("EEE");
list.add("CCC");
//遍歷方式一:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("-------------");
//便利方式二:
for (String str:
list) {
System.out.println(str);
}
}圖示:

@Test
//在集合中使用泛型的情況:以HashMap為例
public void test2(){
Map<String,Integer> map = new HashMap<>();//jdk7新特性:類(lèi)型推斷
map.put("Tom",26);
map.put("Jarry",30);
map.put("Bruce",28);
map.put("Davie",60);
//嵌套循環(huán)
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<String, Integer> entry = iterator.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
}① 集合接口或集合類(lèi)在JDK 5.0時(shí)都修改為帶泛型的結(jié)構(gòu)。
② 在實(shí)例化集合類(lèi)時(shí),可以指明具體的泛型類(lèi)型
③ 指明完以后,在集合類(lèi)或接口中凡是定義類(lèi)或接口時(shí),內(nèi)部結(jié)構(gòu)(比如:方法、構(gòu)造器、屬性等)使用到類(lèi)的泛型的位置,都指定為實(shí)例化的泛型類(lèi)型。
比如:add(E e) --->實(shí)例化以后:add(Integer e)
④ 注意點(diǎn):泛型的類(lèi)型必須是類(lèi),不能是基本數(shù)據(jù)類(lèi)型。需要用到基本數(shù)據(jù)類(lèi)型的位置,拿包裝類(lèi)替換
⑤ 如果實(shí)例化時(shí),沒(méi)有指明泛型的類(lèi)型。默認(rèn)類(lèi)型為java.lang.Object類(lèi)型。
泛型類(lèi)、泛型接口、泛型方法
interface List<T> 和 class GenTest<K,V>其中,T,K,V,不代表值,而是表示類(lèi)型。這里使用任意字母都可以。
常用T表示,是Type的縮寫(xiě)。
一定要在類(lèi)名后面指定類(lèi)型參數(shù)的值(類(lèi)型)。如:
List<String> strList =new ArrayList<String>();
Iterator<Customer> iterator = customers.iterator();
T只能是類(lèi),不能用基本數(shù)據(jù)類(lèi)型填充。但可以使用包裝類(lèi)填充
把一個(gè)集合中的內(nèi)容限制為一個(gè)特定的數(shù)據(jù)類(lèi)型,這就是 generics背后的核心思想
//JDK 5.0以前
Comparable c = new Date();
System.out.println(c.comparaTo("red");
//JDK 5.0以后
Comparable <Date> c = new Date();
System.out.println(c.comparaTo("red");總結(jié):使用泛型的主要優(yōu)點(diǎn)在于能夠在編譯時(shí)而不是在運(yùn)行時(shí)檢測(cè)錯(cuò)誤
泛型類(lèi)可能有多個(gè)參數(shù),此時(shí)應(yīng)將多個(gè)參數(shù)一起放在尖括號(hào)內(nèi)。比如<E1,E2,E3>
泛型類(lèi)的構(gòu)造器如下: public GenericClass(){}
而下面是錯(cuò)誤的: public GenericClass<E>{}
實(shí)例化后,操作原來(lái)泛型位置的結(jié)構(gòu)必須與指定的泛型類(lèi)型一致。
泛型不同的引用不能相互賦值。
盡管在編譯時(shí) ArrayList<String>和ArrayList<Integer>是兩種類(lèi)型,但是,在運(yùn)行時(shí)只有一個(gè)ArrayList被加載到JVM中。
泛型如果不指定,將被擦除,泛型對(duì)應(yīng)的類(lèi)型均按照Object處理,但不等價(jià)于Object。
建議:泛型要使用一路都用。要不用,一路都不要用。
如果泛型結(jié)構(gòu)是一個(gè)接口或抽象類(lèi),則不可創(chuàng)建泛型類(lèi)的對(duì)象。
JDK 7.0,泛型的簡(jiǎn)化操作: ArrayList<Fruit>first= new ArrayList<>();(類(lèi)型推斷)
泛型的指定中不能使用基本數(shù)據(jù)類(lèi)型,可以使用包裝類(lèi)替換。
在類(lèi)/接口上聲明的泛型,在本類(lèi)或本接口中即代表某種類(lèi)型,可以作為非靜態(tài)屬性的類(lèi)型、非靜態(tài)方法的參數(shù)類(lèi)型、非靜態(tài)方法的返回值類(lèi)型。但在靜態(tài)方法中不能使用類(lèi)的泛型。
異常類(lèi)不能是泛型的。
不能使用new E[]。但是可以:E[] elements= (E[])new Object[capacity];
> 參考:ArrayList源碼中聲明:Object\[\] elementData,而非泛型參數(shù)類(lèi)型數(shù)組。
父類(lèi)有泛型,子類(lèi)可以選擇保留泛型也可以選擇指定泛型類(lèi)型:
- 子類(lèi)不保留父類(lèi)的泛型:按需實(shí)現(xiàn) - 沒(méi)有類(lèi)型---擦除 - 具體類(lèi)型 - 子類(lèi)保留父類(lèi)的泛型:泛型子類(lèi) - 全部保留 - 部分保留 - 結(jié)論:子類(lèi)必須是“富二代”,子類(lèi)除了指定或保留父類(lèi)的泛型,還可以增加自己的泛型
代碼示例:
class Father<T1, T2> {
}
/**
* 定義泛型子類(lèi)Son
* 情況一:繼承泛型父類(lèi)后不保留父類(lèi)的泛型
*/
//1.沒(méi)有指明類(lèi)型 擦除
class Son1<A, B> extends Father {//等價(jià)于class Son1 extends Father<Object,Odject>{}
}
//2.指定具體類(lèi)型
class Son2<A, B> extends Father<Integer, String> {
}
/**
* 定義泛型子類(lèi)Son
* 情況二:繼承泛型父類(lèi)后保留泛型類(lèi)型
*/
//1.全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
//2.部分保留
class Son4<T2, A, B> extends Father<Integer,T2>{
}代碼示例:
/**
* 自定義泛型類(lèi)Order
*/
class Order<T> {
private String orderName;
private int orderId;
//使用T類(lèi)型定義變量
private T orderT;
public Order() {
}
//使用T類(lèi)型定義構(gòu)造器
public Order(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
//這個(gè)不是泛型方法
public T getOrderT() {
return orderT;
}
//這個(gè)不是泛型方法
public void setOrderT(T orderT) {
this.orderT = orderT;
}
//這個(gè)不是泛型方法
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
// //靜態(tài)方法中不能使用類(lèi)的泛型。
// public static void show(T orderT){
// System.out.println(orderT);
// }
// //try-catch中不能是泛型的。
// public void show(){
// try {
//
// }catch (T t){
//
// }
// }
//泛型方法:在方法中出現(xiàn)了泛型的結(jié)構(gòu),泛型參數(shù)與類(lèi)的泛型參數(shù)沒(méi)有任何關(guān)系。
//換句話說(shuō),泛型方法所屬的類(lèi)是不是泛型類(lèi)都沒(méi)有關(guān)系。
//泛型方法,可以聲明為靜態(tài)的。
// 原因:泛型參數(shù)是在調(diào)用方法時(shí)確定的。并非在實(shí)例化類(lèi)時(shí)確定。
public static <E> List<E> copyFromArryToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e :
list) {
list.add(e);
}
return list;
}
}自定義泛型類(lèi)Order的使用
@Test
public void test1() {
//如果定義了泛型類(lèi),實(shí)例化沒(méi)有指明類(lèi)的泛型,則認(rèn)為此泛型類(lèi)型為Object類(lèi)型
//要求:如果大家定義了類(lèi)是帶泛型的,建議在實(shí)例化時(shí)要指明類(lèi)的泛型。
Order order = new Order();
order.setOrderT(123);
System.out.println(order.getOrderT());
order.setOrderT("abc");
System.out.println(order.getOrderT());
//建議:實(shí)例化時(shí)指明類(lèi)的泛型
Order<String> order1 = new Order<>("Tom", 16, "male");
order1.setOrderT("AA:BBB");
System.out.println(order1.getOrderT());
}
@Test
//調(diào)用泛型方法
public void test2(){
Order<String> order = new Order<>();
Integer [] arr = new Integer[]{1,2,3,4,5,6};
List<Integer> list = order.copyFromArryToList(arr);
System.out.println(list);
}代碼示例:
/**
* 自定義泛型接口
*/
public interface DemoInterface <T> {
void show();
int size();
}
//實(shí)現(xiàn)泛型接口
public class Demo implements DemoInterface {
@Override
public void show() {
System.out.println("hello");
}
@Override
public int size() {
return 0;
}
}
@Test
//測(cè)試泛型接口
public void test3(){
Demo demo = new Demo();
demo.show();
}方法,也可以被泛型化,不管此時(shí)定義在其中的類(lèi)是不是泛型類(lèi)。在泛型方法中可以定義泛型參數(shù),此時(shí),參數(shù)的類(lèi)型就是傳入數(shù)據(jù)的類(lèi)型。
泛型方法的格式: [訪問(wèn)權(quán)限]<泛型>返回類(lèi)型 方法名(泛型標(biāo)識(shí) 參數(shù)名稱])拋出的異常
泛型方法聲明泛型時(shí)也可以指定上限
代碼示例:
//泛型方法:在方法中出現(xiàn)了泛型的結(jié)構(gòu),泛型參數(shù)與類(lèi)的泛型參數(shù)沒(méi)有任何關(guān)系。
//換句話說(shuō),泛型方法所屬的類(lèi)是不是泛型類(lèi)都沒(méi)有關(guān)系。
//泛型方法,可以聲明為靜態(tài)的。
// 原因:泛型參數(shù)是在調(diào)用方法時(shí)確定的。并非在實(shí)例化類(lèi)時(shí)確定。
public static <E> List<E> copyFromArryToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e :
list) {
list.add(e);
}
return list;
}泛型實(shí)際上就是標(biāo)簽,聲明時(shí)不知道類(lèi)型,再使用時(shí)指明
定義泛型結(jié)構(gòu),即:泛型類(lèi)、接口、方法、構(gòu)造器時(shí)貼上泛型的標(biāo)簽<T>
用泛型定義類(lèi)或借口是<T>放到類(lèi)名或接口名后面,定義泛型方法時(shí)在方法名前加上<T>
【DAO.java】:定義了操作數(shù)據(jù)庫(kù)中的表的通用操作。 ORM思想(數(shù)據(jù)庫(kù)中的表和Java中的類(lèi)對(duì)應(yīng))
public class DAO<T> {//表的共性操作的DAO
//添加一條記錄
public void add(T t){
}
//刪除一條記錄
public boolean remove(int index){
return false;
}
//修改一條記錄
public void update(int index,T t){
}
//查詢一條記錄
public T getIndex(int index){
return null;
}
//查詢多條記錄
public List<T> getForList(int index){
return null;
}
//泛型方法
//舉例:獲取表中一共有多少條記錄?獲取最大的員工入職時(shí)間?
public <E> E getValue(){
return null;
}
}【CustomerDAO.java】:
public class CustomerDAO extends DAO<Customer>{//只能操作某一個(gè)表的DAO
}【StudentDAO.java】:
public class StudentDAO extends DAO<Student> {//只能操作某一個(gè)表的DAO
}泛型在繼承方面的體現(xiàn):
雖然類(lèi)A是類(lèi)B的父類(lèi),但是G<A> 和G<B>二者不具備子父類(lèi)關(guān)系,二者是并列關(guān)系。
補(bǔ)充:類(lèi)A是類(lèi)B的父類(lèi),A<G> 是 B<G> 的父類(lèi)
代碼示例:
@Test
public void test1(){
Object obj = null;
String str = null;
obj = str;
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;
//編譯不通過(guò)
// Date date = new Date();
// str = date;
List<Object> list1 = null;
List<String> list2 = new ArrayList<String>();
//此時(shí)的list1和list2的類(lèi)型不具子父類(lèi)關(guān)系
//編譯不通過(guò)
// list1 = list2;
/*
反證法:
假設(shè)list1 = list2;
list1.add(123);導(dǎo)致混入非String的數(shù)據(jù)。出錯(cuò)。
*/
show(list1);
show1(list2);
}
public void show1(List<String> list){
}
public void show(List<Object> list){
}
@Test
public void test2(){
AbstractList<String> list1 = null;
List<String> list2 = null;
ArrayList<String> list3 = null;
list1 = list3;
list2 = list3;
List<String> list4 = new ArrayList<>();
}使用類(lèi)型通配符:?
比如:List<?>,Map<?,?>
List<?>是List<String>、List<Object>等各種泛型List的父類(lèi)。
讀取List<?>的對(duì)象list中的元素時(shí),永遠(yuǎn)是安全的,因?yàn)椴还躭ist的真實(shí)類(lèi)型是什么,它包含的都是Object
寫(xiě)入list中的元素時(shí),不可以。因?yàn)槲覀儾恢纁的元素類(lèi)型,我們不能向其中添加對(duì)象。 除了添加null之外。
說(shuō)明:
將任意元素加入到其中不是類(lèi)型安全的
Collection<?> c = new ArrayList<String>()
c.add(new Object());//編譯時(shí)錯(cuò)誤
因?yàn)槲覀儾恢纁的元素類(lèi)型,我們不能向其中添加對(duì)象。add方法有類(lèi)型參數(shù)E作為集合的元素類(lèi)型。我們傳給add的任何參數(shù)都必須是一個(gè)已知類(lèi)型的子類(lèi)。因?yàn)槲覀儾恢滥鞘鞘裁搭?lèi)型,所以我們無(wú)法傳任何東西進(jìn)去。
唯一的例外的是null,它是所有類(lèi)型的成員。
我們可以調(diào)用get()方法并使用其返回值。返回值是一個(gè)未知的類(lèi)型,但是我們知道,它總是一個(gè)Object。
代碼示例:
@Test
public void test3(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;
//編譯通過(guò)
// print(list1);
// print(list2);
//
List<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
//添加(寫(xiě)入):對(duì)于List<?>就不能向其內(nèi)部添加數(shù)據(jù)。
//除了添加null之外。
// list.add("DD");
// list.add('?');
list.add(null);
//獲取(讀取):允許讀取數(shù)據(jù),讀取的數(shù)據(jù)類(lèi)型為Object。
Object o = list.get(0);
System.out.println(o);
}
public void print(List<?> list){
Iterator<?> iterator = list.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}//注意點(diǎn)1:編譯錯(cuò)誤:不能用在泛型方法聲明上,返回值類(lèi)型前面<>不能使用?
public static <?> void test(ArrayList<?> list){
}
//注意點(diǎn)2:編譯錯(cuò)誤:不能用在泛型類(lèi)的聲明上
class GenericTypeClass<?>{
}
//注意點(diǎn)3:編譯錯(cuò)誤:不能用在創(chuàng)建對(duì)象上,右邊屬于創(chuàng)建集合對(duì)象
ArrayList<> list2 new ArrayList<?>();<?>:允許所有泛型的引用調(diào)用
通配符指定上限
上限extends:使用時(shí)指定的類(lèi)型必須是繼承某個(gè)類(lèi),或者實(shí)現(xiàn)某個(gè)接口,即<=
通配符指定下限
下限super:使用時(shí)指定的類(lèi)型不能小于操作的類(lèi),即>=
舉例:
<?extends Number>(無(wú)窮小, Number\] 只允許泛型為Number及Number子類(lèi)的引用調(diào)用
<?super Number>\[Number,無(wú)窮大) 只允許泛型為Number及Number父類(lèi)的引用調(diào)用
<? extends Comparable> 只允許泛型為實(shí)現(xiàn) Comparable接口的實(shí)現(xiàn)類(lèi)的引用調(diào)用
代碼示例:
@Test
public void test4(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
list1 = list3;
list1 = list4;
// list1 = list5;
// list2 = list3;
list2 = list4;
list2 = list5;
//讀取數(shù)據(jù):
list1 = list3;
Person p = list1.get(0);
//編譯不通過(guò)
//Student s = list1.get(0);
list2 = list4;
Object obj = list2.get(0);
////編譯不通過(guò)
// Person obj = list2.get(0);
//寫(xiě)入數(shù)據(jù):
//編譯不通過(guò)
// list1.add(new Student());
//編譯通過(guò)
list2.add(new Person());
list2.add(new Student());
}“Java泛型的概念”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
文章題目:Java泛型的概念
標(biāo)題URL:http://www.chinadenli.net/article22/gicdcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、網(wǎng)站內(nèi)鏈、品牌網(wǎng)站建設(shè)、外貿(mào)建站、標(biāo)簽優(yōu)化、定制開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)