泛型
泛型可以解决数据类型的安全性问题,它主要的原理是:是在类声明的时候通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在声明类或实例化的时候只要指定好需要的类型即可。
泛型的定义格式:
[访问权限] 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+"、");
}
}
}