泛型
泛型可以解決數據類型的安全性問題,它主要的原理是:是在類聲明的時候通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。這樣在聲明類或實例化的時候只要指定好需要的類型即可。
泛型的定義格式:
[訪問權限] class 類名稱<泛型類型1,泛型類型2,….,泛型類型3>{
[訪問權限] 泛型類型標識 變量名稱;
[訪問權限] 泛型類型標識 方法名稱(){};
[訪問權限] 返回值類型聲明 方法名稱(泛型類型標識 變量名稱){};
}
泛型對象定義:
類名稱<具體類> 對象名稱 =new 類名稱<具體類>(); |
class Point<T>{ //設置泛型
private T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
}
public class gennericDemo01
{
public static void main(String args[]){
Point<String> p=new Point<String>(); //實例化泛型對象
p.setVar("今天過的很好"); //設置值
System.out.println(p.getVar());
}
}
泛型中的構造方法
構造方法可以爲類中的屬性初始化,那麼如果類中的屬性通過泛型指定,而又希望通過構造設置屬性內容的時候,那麼構造方法中的定義與之前並無不同,不需要像聲明類那樣指定泛型。其格式如下:
[訪問權限] 構造方法(<泛型類型> 參數名稱){};
代碼示例:
class Point<T>{ //設置泛型
private T var; //定義泛型變量
public Point(T var){
this.var=var;
}
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
}
public class gennericDemo02
{
public static void main(String args[]){
Point<String> p=new Point<String>("今天你好麼"); //通過構造方法指定泛型類型並且初始化屬性值
System.out.println(p.getVar());
}
}
設置多個泛型
在泛型中也可以指定多個泛型的類型:
class Notepad<K,V> //爲泛型指定兩個類型 類型自定義
{
private K key;
private V value;
public K getKey(){
return this.key;
}
public V getValue(){
return this.value;
}
public Notepad(K key,V value){ //通過構造方法爲兩個類型的屬性初始化
this.key=key;
this.value=value;
}
}
public class gennericDemo03
{
public static void main(String args[]){
Notepad<Integer,String> notepad=new Notepad<Integer,String>(30,"魔樂"); //實例化對象
System.out.println(notepad.getKey());
System.out.println(notepad.getValue());
}
}
通配符
匹配任意類型的通配符
觀察一下的代碼:
class Info<T>{ //設置泛型
private T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
}
public class gennericDemo04
{
public static void main(String args[]){
Info<String> info=new Info<String>(); //指定String爲泛型類型
info.setVar("MLDN");
fun(info); //錯誤,無法傳遞
}
public static void fun(Info<Object> temp){ //可以接收
System.out.println("編譯通過了");
}
}
注意:泛型對象進行引用傳遞的時候,泛型類型必須是一致的。
如果現在非要進行傳遞,則可以將方法中Info參數的類型取消掉,但是取消掉畢竟不是最好的處理方式,畢竟之前已經指定了泛型了。那麼可以採用使用?的形式。
class Info<T>{ //設置泛型
private T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
}
public class gennericDemo05
{
public static void main(String args[]){
Info<String> info=new Info<String>(); //指定String爲泛型類型
info.setVar("MLDN");
fun(info); //錯誤,無法傳遞
System.out.println(info.getVar());
}
public static void fun(Info<?> temp){ //可以接收
System.out.println("編譯通過了");
}
}
如果使用的是? 意味着可以接收任意的內容,但是?並不代表着具體的類型,所以此內容卻無法直接使用<?>修飾的泛型對象進行修改。代碼解釋如下:
class Info<T>{ //設置泛型
private T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
}
public class gennericDemo06
{
public static void main(String args[]){
Info<?> info=new Info<String>(); //指定String爲泛型類型
info.setVar("MLDN"); //錯誤 無法將Info<?>類型應用於Info<String>
System.out.println(info.getVar());
}
}
注意:在使用<?>只能夠接收,但是不能修改
受限泛型
在引用傳遞中,泛型操作中也可以設置一個泛型對象的範圍上限和範圍下限。範圍上限使用extends關鍵字聲明,表示參數化的類型可能是有所指定的類型,或者是此類型的子類,而範圍下限使用super關鍵字進行聲明,表示參數化的類型可能是所指定的類型,或者是此類型的父類型,直至Object類。
設置上限:
聲明對象: 類名稱<? extends 類> 對象名稱 定義類:[訪問權限] 類名稱<泛型標識 extends 類>{}; |
設置下限:
聲明對象: 類名稱<? super 類> 對象名稱 定義類:[訪問權限] 類名稱<泛型標識 extends 類>{}; |
設置上限
class Info<T>{ //設置泛型
public T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
public String toString(){ //覆寫toString方法,方便打印對象
return this.var.toString();
}
}
public class gennericDemo07
{
public static void main(String args[]){
Info<Integer> i1=new Info<Integer>(); //指定Integer爲泛型類型
Info<Float> i2=new Info<Float>(); //指定Float爲泛型類型
i1.setVar(10);
i2.setVar(10.3f);
fun(i1);
fun(i2);
}
//接收Info對象,返回上限設置爲Number,所以只能接收數字類型
public static void fun(Info<? extends Number> temp){
System.out.println(temp+"、");
}
}
上限設置在類中的應用:
class Info<T extends Number>{ //設置泛型並設置上限 最高爲Number
public T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
public String toString(){ //覆寫toString方法,方便打印對象
return this.var.toString();
}
}
public class gennericDemo08
{
public static void main(String args[]){
Info<Integer> i1=new Info<Integer>(); //指定Integer爲泛型類型
Info<Float> i2=new Info<Float>(); //指定Float爲泛型類型
Info<String> i3=new Info<String>(); //會出現類型參數 java.lang.String 不在其限制範圍之內的錯誤
i1.setVar(10);
i2.setVar(10.3f);
System.out.println(i1.getVar());
System.out.println(i2.getVar());
}
}
設置下限
當使用的泛型只能在本類及其父類類型上應用的時候,就必須使用泛型的範圍下限設置。
class Info<T>{ //設置泛型並設置上限 最高爲Number
public T var; //定義泛型變量
public void setVar(T var){
this.var=var;
}
public T getVar(){
return var;
}
public String toString(){ //覆寫toString方法,方便打印對象
return this.var.toString();
}
}
public class gennericDemo09
{
public static void main(String args[]){
Info<String> i1=new Info<String>(); //聲明String的泛型對象
Info<Object> i2=new Info<Object>(); //聲明Object的泛型對象
i1.setVar("MLDN");
i2.setVar(new Object());
fun(i1);
fun(i2);
}
public static void fun(Info<? super String> temp){ //只能接收String或Object類型的泛型
System.out.println(temp);
}
}
注意:一個類的子類可以通過對象多態性,爲其父類進行實例化,但是在泛型操作中,子類的泛型類型是無法使用父類的泛型類型接收的,例如:Info<Stirng>不能使用Info<Object>接收,只能是類型完全一致或者是採用Info<?>的格式進行接收,但是也要注意,使用Info<?>的形式是不能爲對象設置值的,只能用來接收。
泛型的其它應用
泛型接口基本概念
在JDK1.5之後,不僅僅可以聲明泛型類,也可以聲明泛型接口,聲明泛型接口和聲明泛型類的語法相似,也是在接口名稱後面加上<T>,如以下的格式:
[訪問權限] interface 接口名稱<泛型標識>{};
interface Info<T> //在接口上定義泛型
private T var;
public T getVar
}
如以下的代碼:
interface Info<T>
{
public T getVar();
}
class InfoImpl<T> implements Info<T>
{
public T getVar(){
return null;
}
}
泛型接口實現的兩種方式
定義子類:在子類的定義上也聲明泛型類型。
interface Info<T> //在接口上定義泛型
{
public T getVar(); //定義抽象方法,抽象方法的返回值類型就是泛型類型
}
class InfoImpl<T> implements Info<T> //定義泛型接口的子類
{
private T var; //定義屬性
public InfoImpl(T var){ //通過構造方法設置屬性內容
this.var=var;
}
public void setVar(T var){
this.var=var;
}
public T getVar(){
return this.var;
}
}
public class gennericDemo02
{
public static void main(String args[]){
Info<String> info=null; //聲明接口對象
info=new InfoImpl<String>("MLDN"); //通過子類實例化對象
System.out.println(info.getVar());
}
}
如果現在實現接口的子類不想使用泛型類型聲明,則在實現接口的時候可以指定好具體的泛型類型。
interface Info<T> //在接口上定義泛型
{
public T getVar(); //定義抽象方法,抽象方法的返回值類型就是泛型類型
}
class InfoImpl implements Info<String> //定義直接使用String類型的泛型類型
{
private String var; //定義屬性
public InfoImpl(String var){ //通過構造方法設置屬性內容
this.var=var;
}
public void setVar(String var){
this.var=var;
}
public String getVar(){
return this.var;
}
}
public class gennericDemo03
{
public static void main(String args[]){
Info<String> info=null; //聲明接口對象
info=new InfoImpl("MLDN"); //通過子類實例化對象
System.out.println(info.getVar());
}
}
定義泛型方法
泛型方法中可以定義泛型參數,此時,參數的類型就是傳入數據的類型,使用如下的格式定義泛型方法:
[訪問權限] <泛型標識> 泛型標識 方法名稱(泛型標識 參數名稱)
如以下的代碼:
class Demo{
public <T> T fun(T t){ //可以接收任意類型的參數
return t; //直接把參數值返回
}
}
public class gennericDemo04
{
public static void main(String args[]){
Demo demo=new Demo(); //示例化Demo類
String str=demo.fun("你好"); //傳遞字符串
int i=demo.fun(12); //傳遞整型
System.out.println(str);
System.out.println(i);
}
}
通過泛型方法返回泛型類的實例
代碼如下:
class Info<T extends Number>{ //指定上限,只能是數字類型
private T var; //此類型由外部決定
public T getVar(){
return var;
}
public void setVar(T var){
this.var=var;
}
public String toString(){ //覆寫toString方法,方便打印對象
return this.var.toString();
}
}
public class gennericDemo05
{
public static void main(String args[]){
Info<Integer> info=fun(30);
System.out.println(info.getVar());
}
public static <T extends Number> Info<T> fun(T temp){
Info<T> info=new Info<T>(); //根據傳入的數據類型實例化Info
info.setVar(temp); //將傳遞的內容設置到Info對象的var屬性之中
return info; //返回實例化對象
}
}
泛型數組
使用泛型方法的時候,也可以傳遞或返回一個泛型數組。
public class gennericDemo06
{
public static void main(String args[]){
Integer i[]=fun1(1,2,3,4); //返回泛型數組
fun2(i);
}
public static <T> T[] fun1(T...arg){ //接收可變參數
return arg; //返回泛型數組
}
public static <T> void fun2(T param[]){ //輸出泛型數組
System.out.println("泛型數組:");
for(T t:param){
System.out.print(t+"、");
}
}
}