Java泛型
泛型的理解与应用
泛型的声明与使用
-
主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。
-
泛型的声明:
//泛型类的声明:
[访问权限] class 类名称<泛型类型标识1,泛型类型标识2...泛型类型标识3>{
[访问权限] 泛型类型标识 变量名称;
[访问权限] 泛型类型标识 方法名称() {};
[访问权限] 返回值类型声明 方法名称(泛型类型标识 变量名称) {};
}
//泛型对象的声明
类名称<具体类> 对象名称 = new 类名称<具体类>();
- 例子:
public class GenericsState {
public static void main(String[] args) {
GenericsTest1<String> test1 = new GenericsTest1<String>();
test1.setVar("张三");
String name = test1.getVar();
GenericsTest1<Integer> test2 = new GenericsTest1<Integer>();
test2.setVar(20);
int age = test2.getVar();
GenericsTest1<Double> test3 = new GenericsTest1<Double>();
test3.setVar(78.5);
double y = test3.getVar();
System.out.println("name:\t" + name);
System.out.println("age:\t" + age);
System.out.println("y:\t" + y);
}
}
class GenericsTest1<T> {
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
泛型的最大好处实际就是避免了类转换异常。
泛型应用中的构造方法
[访问权限] 构造方法 ([泛型类型 参数名称]){
}
- 例子:
public class GenericsState {
public static void main(String[] args) {
GenericsTest1<Integer> test = null;
test = new GenericsTest1<Integer>(20);
System.out.println("age = " + test.getVar());
}
}
class GenericsTest1<T> {
public GenericsTest1(T var) {
this.var = var;
}
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
通配符
- 在泛型类的操作中,在进行引用传递时泛型类型必须匹配才可以传递,否则是无法传递的。
- 通配符“?”,表示可以接收此类型的任意泛型对象。如果使用“?”泛型对象时,则不能设置被指定的内容。
- 例子:
public class SendGenerics {
public static void main(String[] args) {
GenericsTest4<String> test1 = new GenericsTest4<String>();
test1.setVar("张三");
fun(test1);
GenericsTest4<?> test2 = new GenericsTest4<String>();
test.setVar("李四");//报错,违规
test.setVar(null);//可以
}
public static void fun(GenericsTest4<?> temp){
System.out.println("内容 = " + temp.getVar());
}
}
class GenericsTest4<T> {
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
受限泛型
- 设置上限
- 现在假设一个方法中能接收的泛型对象只能是数字类型,此时定义方法参数接收对象时,就必须指定泛型的上限。因为所有包装类都是Number类的子类。
//声明对象
类名称<? extends 类> 对象名称
//定义类
[访问权限] 类名称<泛型标识 extends 类>{}
例子:
public class GenericsDemo {
public static void main(String[] args) {
Info<Integer> i1 = new Info<Integer>();
Info<Float> i2 = new Info<Float>();
i1.setVar(30);
i2.setVar(30.2f);
System.out.println("内容:" + i1.getVar());
fun(i1);
fun(i2);
}
//接受Info对象,设置上限为Number,所以只能接收数字类型。(在Info没有被设置上限的情况。)
public static void fun(Info<? extends Number> temp){
System.out.println(temp.getVar() + "、");
}
}
//此处的泛型只能是数字类型
class Info<T extends Number> {
private T var;
public Info() {
}
public Info(T var) {
this.var = var;
}
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
- 设置下限
- 当使用的泛型只能在本类及其父类类型上应用时,就必须使用泛型的范围下限进行配置。
//声明对象
类名称<? super 类> 对象名称
//定义类
[访问权限] 类名称 <泛型标识 extends 类>{}
例子
package Generics;
public class GenericsLower {
public static void main(String[] args) {
Info1<String> i1 = new Info1<String>();
Info1<Object> i2 = new Info1<Object>();
i1.setVar("张三");
i2.setVar(new Object());
fun(i1);
fun(i2);
}
//只能接收String或Object类的泛型。
public static void fun(Info1<? super String> temp) {
System.out.println("内容:" + temp);
}
}
class Info1<T> {
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
@Override
public String toString() {
return this.var.toString();
}
}
泛型与子类继承的限制
- 一个子类可以通过对象多态性为其父类实例化,但是在泛型操作中,子类的泛型类型时无法使用父类的泛型类型接收的。
/**
* 以下代码中错误提示是不匹配类型,Info<String>无法转换
* 为Info<Object>。虽然String是Object的子类,但是在
* 泛型的使用中此概念无效,此时只能应用"?"接收。
*/
public class GenericsInterface {
public static void main(String[] args) {
Info<String> i1 = new Info<String>();
Info<Object> i2 = null;
i2 = i1;
}
}
泛型接口
泛型接口的定义
[访问权限] interface 接口名称<泛型标识> {
}
//例如:
public interface Info<T> {
public T getVar();
}
泛型接口的两种实现方式
-
接口定义后就要定义此接口的子类,定义泛型接口的子类有两种方式
- 一种是直接在子类后声明泛型。
- 另一种是直接在子类实现的接口中明确的给出泛型的类型。
-
在子类的定义上声明泛型类型
public class GenericsInterface {
public static void main(String[] args) {
Infolmpl<String> i = null;
i = new Infolmpl<String>("张三");
System.out.println("内容:" + i.getVar());
}
}
interface Info2<T> {
public T getVar();
}
class Infolmpl<T> implements Info2<T> {
private T var;
public Infolmpl(T var) {
this.var = var;
}
@Override
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
- 直接在接口中定义指定具体类型
public class GenericsInterface {
public static void main(String[] args) {
Infolmpl1<String> i1 = new Infolmpl1<String>("李四");
System.out.println("内容:" + i1.getVar());
}
}
interface Info2<T> {
public T getVar();
}
class Infolmpl1<T> implements Info2<String> {
private String var;
public Infolmpl1(String var) {
this.var = var;
}
@Override
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
}
泛型方法
定义与使用
- 在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
[访问权限] <泛型标识> 泛型标识 方法名称([泛型标识 泛型名称])
//例子:
public <T> T fun(T t){
return t;
}
- 如果可以通过泛型方法返回一个泛型类型的实例化对象,则必须在方法的返回类型声明处明确地指定泛型标识。
package Generics;
public class GenericFun {
public static void main(String[] args) {
Info3<Integer> i = fun(30);
System.out.println("内容:" + i.getVar());
}
//<T extends Number>表示给方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定。
//Info3 <T>表示返回为Info类的对象。
public static <T extends Number> Info3 <T> fun(T t) {
Info3<T> info = new Info3<T>();
info.setVar(t);
return info;
}
}
class Info3<T extends Number> {
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
使用泛型统一传入的参数类型
- 如果现在一个方法要求传入的泛型类型一致,也可以通过泛型方法指定。
public class GenericFun {
public static void main(String[] args) {
Info3<String> i1 = new Info3<String>();
Info3<String> i2 = new Info3<String>();
i1.setVar("hello");
i2.setVar("world");
add(i1, i2);
}
//<T>表示泛型方法
//此处的i1和i2对象的泛型类型必须一致,不一致编译时会报错。
public static <T> void add(Info3 i1,Info3 i2) {
System.out.println(i1.getVar() + " " + i2.getVar());
}
}
class Info3<T> {
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
泛型数组
- 使用泛型方法时,也可以传递或返回一个泛型数组。
public class GenericArray {
public static void main(String[] args) {
Integer i[] = fun1(1,2,3,4,5,6);
fun2(i);
}
//接收可变参数,返回泛型数组。
public static <T> T[] fun1(T... arg) {
return arg;
}
//接收泛型数组。
public static <T> void fun2(T a[]) {
System.out.println("接收泛型数组:");
for (T t : a){
System.out.print(t + "、");
}
System.out.println();
}
}
泛型的嵌套设置
- 泛型也可以在一个类的泛型中指定另外一个类的泛型。
package Generics;
public class GenericNested {
public static void main(String[] args) {
Demo<Info4<String,Integer>> d = null;
Info4<String,Integer> i = null;
i = new Info4<String,Integer>("张三",25);
d = new Demo<Info4<String,Integer>>(i);
System.out.println("内容一:" + d.getInfo().getVar());
System.out.println("内容二:" + d.getInfo().getValue());
}
}
class Info4<T,V> {
private T var;
private V value;
public Info4(T var, V value) {
this.var = var;
this.value = value;
}
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
class Demo<S> {
private S info;
public Demo(S info) {
this.info = info;
}
public S getInfo() {
return info;
}
public void setInfo(S info) {
this.info = info;
}
}