一、泛型的概念
1、什么是泛型,看表面的意思,泛型就是指广泛的、普通的类型
2、所谓的泛型就是在类定义时,不为类中属性和方法指定数据类型,而是在类对象创建时为其指定相应的数据类型。这个参数类型将在使用的时候就确定了。
二、为何使用泛型?
使用集合时就用过泛型List 创建一个List对象List list=new ArrayList();
1)首先就像上面那个例子一样,使用泛型能够限定集合中,如List, Set中元素的类型,保证一个集合中只有一个类型。
2)程序也能更加健壮(只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常)
public class Point<T> {
//x坐标
private T X;
//y坐标
private T Y;
//输出坐标的值
public void show(){
System.out.println("x的坐标:"+X+";y的坐标:"+Y);
}
public Point() {}
public Point(T x, T y) {X = x; Y = y;}
public T getX() {return X;}
public void setX(T x) { X = x;}
public T getY() { return Y;}
public void setY(T y) {Y = y; }
}
创建一个test测试类
public class Test {
public static void main(String[] args) {
Point p1=new Point(12,3);//坐标为整数int--自动装箱->Integer--->Object(向上转型)
p1.show();
//如果没指定泛型类型,默认为Object
Point p2=new Point(2.3,"北纬20度");
p2.show();
//泛型类型必须是引用类型
// x和y的值可以都是整数类型。
Point<Integer> p3=new Point<Integer>(4,5);
p3.show();
// x和y的值可以都是小数类型。
Point<Double> p4=new Point<Double>(2.1,4.5);
p4.show();
// x和y的值可以都是字符串类型。
Point<String> p5=new Point<String>("东经180度","北纬25度");
p5.show();
}
}
测试结果如下:
注意: 上面的泛型类型必须都是引用类型。不能是基本类型。
三、如何定义泛型
泛型可以定义在类上,接口上,方法上。 泛型类,泛型接口以及泛型方法。
泛型可以解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的数据类型或者是某个方法的返回值及参数类型。这样在类声明或者实例化时只要指定好需要的类型即可。
1、泛型定义在类上
格式:
public class 类名<泛型标志,泛型标志....>{
//类成员
}
public class Test2 {
public static void main(String[] args) {
Info<String> i = new Info<>("HELLO");
i.show();
//创建对象时需要为每个泛型指定相应的数据类型
Info<Integer> i1 = new Info<>(12);
i1.show();
//没有指定泛型类型,默认为Object
Info i2=new Info();
i2.setVar("吃了吗你");
//想使用真正的类型接收,必须强制转
String s = (String) i2.getVar();
System.out.println(s);
}
}
//创建泛型类
/*public class 类名<泛型标志,泛型标志....>{
//类成员
}*/
class Info<T>{
private T var;
public void show(){
System.out.println("var========>"+var);
}
public Info() {
}
public Info(T var) {
this.var = var;
}
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
}
运行结果如下:
2、泛型定义在接口上
语法:
public interface 接口名<泛型标志,泛型标志....>{
//静态常量
//抽象方法。
}
public class Test5 {
public static void main(String[] args) {
UPAN upan=new UPAN();
System.out.println(upan.fun());
System.out.println("=========================");
Mouse<Integer> mouse=new Mouse<>();
System.out.println(mouse.fun());
}
}
/*
public interface 接口名<泛型标志,泛型标志....>{
//静态常量
//抽象方法。
}
*/
interface USB<T>{
//常量的命名必须为大写
public static final String NAME=" ZHANG";
//抽象方法
T fun();
}
//子类实现接口时,确定泛型类型
class UPAN implements USB<String>{
@Override
public String fun() {
System.out.println("UPAN的fun()方法");
return "HELLO WORLD";
}
}
//子类实现泛型与父类名相同的泛型
class Mouse<T> implements USB<T>{
@Override
public T fun() {
System.out.println("Mouse的fun()方法");
return null;
}
}
运行结果如下:
3、泛型定义在方法上
泛型方法的定义与其所在的类是否是泛型类是没有任何关系的,所在的类可以是泛型类,也可以不是泛型类。
【泛型方法的简单定义】
[访问权限] <泛型标识> 泛型标识 方法名称(泛型标识 参数名称)
public class Test6 {
public static void main(String[] args) {
String hello = Student.fun("hello");
Integer fun = Student.fun(1);
Double fun1 = Student.fun(1.23);
System.out.println(hello);
System.out.println(fun);
System.out.println(fun1);
}
}
class Student{
//泛型方法:static静态成员,随着类的加载被加载到jvm内存中,常量池
public static <T> T fun(T t){
return t;
}
}
运行结果如下:
四、通配符
在开发中对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行引用传递时,泛型类型必须匹配才可以传递,否则是无法传递的。如果想传递,可以定义泛型为通配符:<?>。
<?> 一般用在方法参数,表示可以接受该类所有类型的泛型变量。public class Test3 {
public static void main(String[] args) {
//此时的?代表的是Integer
Info<Integer> i1=new Info<>(23);
fun(i1);
Info<String> i2=new Info<>("你好啊!");
fun(i2);
Info<Double> i3=new Info<>(2.1);
fun(i3);
}
//通配符 ? 的运用
//设置泛型类型接收任意类型,用通配符?接收
public static void fun(Info<?> info){
info.show();
}
}
//T为随意命名
class Info<T> {
private T var;
public void show(){
System.out.println("var======>"+var);
}
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
public Info() {
}
public Info(T var) {
this.var = var;
}
}
运行结果:
五、有限制条件的通配符使用
1、设置上限
? extends T ----- 类型上界
这个时候这个通配符可以配的范围就是 T类型对象和T类型子类的对象
形象的也可以看成是 : (-oo , T];
就是负无穷到T — 把T包含在内
[设置上限]
声明对象: 类名称<? extends 类> 对象名称;
定义类: [访问权限] 类名称<泛型标识 extends 类>{}
那么这个时候G<? extends A>就可以作为G< A>和G< B>的父类,其中A是B的父类
public class Test4 {
public static void main(String[] args) {
Info<Integer> e1=new Info<>(2);
fun1(e1);
Info<Float> e2=new Info<>(1.2f);
fun1(e2);
Info<Number> e3=new Info<>(11.1);
fun1(e3);
/* //String不是Number的子类,所以不能在上限这里使用
Info<String> e4=new Info<>("hello world!");
fun1(e4); */
}
//泛型设置上限,传递的参数泛型类型必须为Number的子类或者Number类型
public static void fun1(Info<? extends Number> info){
info.show();
}
}
class Info<T>{
private T var;
public void show(){
System.out.println("var=======>"+var);
}
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
public Info() {
}
public Info(T var) {
this.var = var;
}
}
运行结果如下:
2、设置下限
? super T — 类型下界
这个时候这个通配符可以配的范围就是T类型的对象和T类型的父类的对象
形象的说也可以看成是: [T , +oo)
也就是T到正无穷
[设置下限]
声明对象: 类名称<? super 类> 对象名称;
定义类: [访问权限] 类名称<泛型标识 super 类>{}
那么这时候G<? super A> 就可以作为G< A>和G < C>的父类,其中A是C的子类
public class Test42 {
public static void main(String[] args) {
Infos<Number> s1=new Infos<>(23);
fun2(s1);
Infos<Object> s2=new Infos<>("hello world!");
fun2(s2);
/* //Integer不是Number的父类,所以不能在下限这里使用
Info<Integer> s3=new Info<>(1);
fun2(s3); */
}
//泛型设置下限,传递的参数泛型类型必须为Number的父类或者Number类型
public static void fun2(Infos<? super Number> infos){
infos.show();
}
}
class Infos<T>{
private T var;
public void show(){
System.out.println("var=======>"+var);
}
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
public Infos() {
}
public Infos(T var) {
this.var = var;
}
}
结果如下: