java 泛型 相关

泛型

什么是泛型

  1. 参数化类型
  2. 解决类型相关算法重用
  3. 编译器需要指定参数类型,否则无法通过编译
  4. 使用泛型类型转换都是自动或者隐式的进行的
  5. 泛型只能是引用类型
  6. 泛型可以用在类,方法,上面

泛型提升安全性的原理

  1. 确保类型安全
  2. 类型自动转换不需要手动进行类型转换
  3. 可以结合使用Object作为超类使用的时候进行类型转换出现的问题进行比较,使用Object 必须显示的进行类型转换

有界泛型

声明泛型的时候声明泛型的范围
形式 T extends superClassName

代码示例

public class Stats<T extends Number> {

T[] nums;

public Stats(T[] o) {
    this.nums = o;
}

double arerage() {
    double sum = 0.0;
    for(int i=0;i<nums.length;i++) {
        sum += nums[i].doubleValue();
    }
    return sum/nums.length;
}

public static void main(String[] args) {
    Stats<Integer> s1 = new Stats<Integer>(new Integer[]{1,2,3,4}) ;
    System.out.println(s1.arerage());
}

}

使用通配符参数

根据上面的例子比较两个平均数的大小,正好两个类型不一致,将无法通过编译,请看小面的这种情况

boolean sameAvg(Stats<T> obj) {
    if(obj.arerage() == arerage())
        return true;
    
    return false;
}

Stats<Integer> s1 = new Stats<Integer>(new Integer[]{1,2,3,4}) ;
    System.out.println(s1.arerage());
    
    Stats<Double> s2 = new Stats<Double>(new Double[] {1.0,2.0,3.0,4.0});
    
    System.out.println(s1.sameAvg(s2));

使用通配符?,代码示例:

boolean sameAvg(Stats<?> obj) {
    if(obj.arerage() == arerage())
        return true;
    
    return false;
}

Stats<Integer> s1 = new Stats<Integer>(new Integer[]{1,2,3,4}) ;
    System.out.println(s1.arerage());
    
    Stats<Double> s2 = new Stats<Double>(new Double[] {1.0,2.0,3.0,4.0});
    
    System.out.println(s1.sameAvg(s2))

通配符不会影响创建什么类型的对象,因为对象的类型是由 T extends className 来进行控制的,通配符只是匹配所有有效的类型。

有界通配符

代码示例1:(无界)

public class TwoD {
private Integer x;
private Integer y;
public TwoD(Integer x,Integer y) {
    this.x = x;
    this.y = y;
    System.out.println("=====TwoD==========");
}
public Integer getX() {
    return x;
}
public void setX(Integer x) {
    this.x = x;
}
public Integer getY() {
    return y;
}
public void setY(Integer y) {
    this.y = y;
}
@Override
public String toString() {
    return "TwoD [x=" + x + ", y=" + y + "]";
}
}

public class ThreeD extends TwoD {

private Integer z;

public ThreeD(Integer x, Integer y,Integer z) {
    super(x, y);
    this.z =z;
    System.out.println("=====ThreeD==========");
}
public Integer getZ() {
    return z;
}
public void setZ(Integer z) {
    this.z = z;
}
@Override
public String toString() {
    return super.toString() + "ThreeD [z=" + z + "]";
}
}

public class Point<T extends TwoD> {

T[] points;

public Point(T[] o) {
    this.points = o;
}

public static void showXY(Point<?> p) {
    for(int i=0;i<p.points.length;i++) {
        System.out.println("x=" + p.points[i].getX() + "\ty=" + p.points[i].getY());
    }
}
}

测试方法

public static void main(String[] args) {
    
    Point<TwoD> p =new Point<>(new TwoD[] {new TwoD(1,2),new TwoD(3,4)});
    
    Point.showXY(p);
}

代码示例2 (有界)

上面方法 showXY 只能获取到x,y的数值。不能获取到z,因为关键字 Point 所以不能获取到z.

增加下面的方法:

public static void showXYZ(Point<? extends ThreeD> p) {
    for(int i=0;i<p.points.length;i++) {
        System.out.println("x=" + p.points[i].getX() + "\ty=" + p.points[i].getY() + "\tz=" + p.points[i].getZ());
    }
}

测试输出:

 	public static void main(String[] args) {
    
    
    Point<ThreeD> p2 =new Point<>(new ThreeD[] {new ThreeD(1,2,4),new ThreeD(3,4,4)});
    
    Point.showXYZ(p2);
}

	x=1	y=2	z=4
	x=3	y=4	z=4	

以上创建的都是上界通配符,当然还有下界通配符。关键字supper

这种只有超类才是符合的参数

方法上面使用泛型

public static<T extends Comparable<T>,V extends T> boolean compareTo(T t,V[] vs) {
    
    for(int i=0;i<vs.length;i++) {
        if(t.equals(vs[i])){
            return true;
        }
    }
    return false;
}


public static void main(String[] args) {
    Integer a = 10;
    Integer[] arrs = new Integer[] {1,2,3,10,20};
    boolean b1 = compareTo(a,arrs);
    System.out.println(b1);
    String s1 = "aa";
    String[] arrs1 = new String[] {"bb","aa"};
    System.out.println(compareTo(s1,arrs1));
}

泛型构造函数

可以将类的构造函数泛型化,即使此类不是泛型化的也可以

示例

public class ConstructorFX {
Double d;
public <T extends Number> ConstructorFX(T t) {
    d = t.doubleValue();
}

}

泛型接口

示例

public interface InterfaceFX<T> {

	T get(T t);

}
  1. 类实现泛型接口必须是泛型化的
  2. 类实现泛型接口也可指定泛型类型

原始类型和遗留代码

jdk5之前还没有泛型的概念,为了处理过度,声明泛型类可以不指定泛型的类型

 public static void main(String[] args) {
    Point p1 =new Point(new TwoD[] {new TwoD(1,2),new TwoD(3,4)});
    Point.showXY(p1);
    
}

泛型自动类型推算

class-name<type-arg-list> var-name = class-name<>(arg-list)

后面的参数列表不需要填写具体的类型

泛型的实现原理

擦除

  1. java 使用擦除实现泛型
  2. 因为java5之前是没有泛型的,现在的jvm或者语法都要兼容以前的代码
  3. 在编译泛型代码的时候所有泛型信息都会被删除,使用泛型的界定类型替换类型参数,如果没有显示的指定界定类型则会使用Object类型,然后应用适当的类型转换,
  4. 也就是说运行时没有泛型,没有类型参数。编译器已经解决了

桥接方式

  1. 发生在字节码阶段
  2. 子类中重写的类型擦除不能与超类中产生相同的方法擦除
  3. 子方法重写了父类方法

模糊性问题

public class Mohu <T,V>{

T t;
V v;

public void set(T t) {this.t = t;}
public void set(V v) {this.v = v;}

}	

上面的方法看起来是合理的,但是当使用擦除后,T和V如果类型相同 两个set方法就变成一样的了

泛型的限制

1.不能实例化泛型参数 new T(); 是错误的

2.不能声明静态变量和静态返回值 以下示例是不正确的

代码示例

  static T t;

   public static T get() {
    return t;
	}
}

3.不能创建引用类型数组 ,

错误示例:

  T[] num = new T[10];
  Point<TwoD>[] p = new Point<TwoD>[2];

但是可以使用下面的这种通配符的方式

    public static void main(String[] args) {
   // Point<TwoD>[] p = new Point<TwoD>[2];
    
    Point<?>[] p = new Point<?>[2];
    p[0] = new Point<TwoD>(new TwoD[] {new TwoD(1,2),new TwoD(3,4)}); 
    p[1] = new Point<TwoD>(new ThreeD[] {new ThreeD(1,2,4),new ThreeD(3,4,4)}); 
    
   for(int i=0;i<p.length;i++) {
       Point.showXY(p[i]);
   }
}

4.不能创建泛型异常类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值