泛型回顾

泛型从JDK1.5之后追加到java语言中,其主要目的是为了解决ClassCastException问题,在对对象进行上下转型时都可能存在有安全隐患。通过泛型可以解决一部分这种问题。

泛型问题引出

写一个类,用来记录某个坐标信息(属性为X和Y)。

package chenfu.type.domain;

/**
 * @Author: romantic_ke@163.com
 * @Description:
 * @Date: 2019/5/16 15:43
 */
public class Point {
    private Object x;
    private Object y;

    public Point(Object x, Object y) {
        this.x = x;
        this.y = y;
    }

    public Object getX() {
        return x;
    }

    public void setX(Object x) {
        this.x = x;
    }

    public Object getY() {
        return y;
    }

    public void setY(Object y) {
        this.y = y;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

测试类

package chenfu.type;

import chenfu.type.domain.Point;

/**
 * @Author: romantic_ke@163.com
 * @Description:
 * @Date: 2019/5/16 15:50
 */
public class TypeTest {

    public static void main(String[] args) {
        Point point = new Point(20, 50);
        Object x = point.getX();
        Object y = point.getY();
        System.out.println("x=" + x);
        System.out.println("y=" + y);
    }

}

上面的代码没有任何问题,通过在Point类中定义x和y属性类型为Object来实现输入整形,浮点型,字符串型数据,但是这也引发了一个问题。如果有需求只让我们在x和y属性中处理整数怎么办?例如如下:

    public static void main(String[] args) {
//        此时,就是在输入坐标时,输入字符串也合法
        Point point = new Point(20, "OK");
        Integer x = (Integer) point.getX();
        Integer y = (Integer) point.getY();
        System.out.println("x=" + x);
        System.out.println("y=" + y);
    }

这时就会引发一个ClassCastException异常,但是编译器又不会给我们提示错误,在大型项目编写过程中,这就很头疼了。泛型就是为了解决此类问题,尽量减少运行过程中代码中潜藏的ClassCastException,将其在编译阶段暴露出来。

利用泛型来改造上述代码

泛型用T标识,代表Type。用A,B,C也可以。

package chenfu.type.domain;

/**
 * @Author: romantic_ke@163.com
 * @Description:
 * @Date: 2019/5/16 15:43
 */
public class Point<T> {
    private T x;
    private T y;

    public Point(T x, T y) {
        this.x = x;
        this.y = y;
    }

    public T getX() {
        return x;
    }

    public void setX(T x) {
        this.x = x;
    }

    public T getY() {
        return y;
    }

    public void setY(T y) {
        this.y = y;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

此时的测试方法,Point的实例化就不能和以前一样了,需要加入属性的具体类型,而且,传入的参数如果不符合给定的数据类型,会在编译时提示错误。

//		  此时,正常输出
public static void main(String[] args) {
        Point<Integer> point = new Point(20, 50);
        Integer x = point.getX();
        Integer y = point.getY();
        System.out.println("x=" + x);
        System.out.println("y=" + y);
    }

泛型通配符

问题引出

观察下面代码和输出

    public static void main(String[] args) {
        Point<Integer> point = new Point(20, 50);
        Integer x = point.getX();
        Integer y = point.getY();
        System.out.println("x=" + x);
        System.out.println("y=" + y);
        run(point);
    }

    public static void run(Point point) {
        point.setX("234");
        System.out.println(point);
    }

结果:

x=20
y=50
Point{x=234, y=50}

结论:可以发现,Point类的x属性被修改了,而且被修改为了String类型。如果我们不希望我们的对象数据被修改,那么该如何实现?
通过如下方式,在方法传参的时候,不指定具体类型(使用通配符“?”)
修改测试方法

    public static void run(Point<?> point) {
        // 编译时报错
        point.setX(1200);
        // 编译时报错
        point.setY(1200);
        String sout = String.format("x=%d,y=%d", point.getX(), point.getY());
        System.out.println(sout);
    }

泛型的通配符有两种

  • ? extends 类:泛型上限-实例化时传入的数据类型必须是某个类或者是这个类的子类
  • ? super 类:泛型下限-实例化时传入的数据类型必须是这个类或者这个类的超类(父类)

展示一种泛型上限的使用方式,下限同理。
修改实体类

public class Point<T extends Number> {

测试代码:

    public static void main(String[] args) {
        Point<Integer> point = new Point<>(20, 50);
        Point<Float> point2 = new Point<>(20.3f, 50.3f);
        Point<Double> point3 = new Point<>(100d, 50.3d);
        run(point);
        run(point2);
        run(point3);
    }

    public static void run(Point<? extends Number> point) {
        System.out.println(point);
    }

输出:

Point{x=20, y=50}
Point{x=20.3, y=50.3}
Point{x=100.0, y=50.3}

总结:泛型通配符能让我们的数据更加安全(不被别的方法所修改),通过上限和下限的设置也能避免很多的数据转型的异常。

泛型接口

定义泛型接口

public interface TypeA<T> {
    void setT(T t);
    T getT();
}

实现该接口的类如果也是泛型类,直接实现接口即可。如果不是泛型类,需要在接口上注明实际类型

    class TypeB<T> implements TypeA<T> {
        @Override
        public void setT(T t) {

        }

        @Override
        public T getT() {
            return null;
        }
    }

    class TypeC implements TypeA<Integer>{
        @Override
        public void setT(Integer integer) {

        }

        @Override
        public Integer getT() {
            return null;
        }
    }

如果是某个接口继承此接口,也是如此

interface TypeB<T> extends TypeA<T> {
}

interface TypeC extends TypeA<Integer> {
}

总结:某个类或接口继承或实现了泛型接口,就务必要对其泛型进行指定,除非实现或继承了该泛型接口的类或接口也是泛型类或泛型接口。

泛型方法

泛型方法在实际开发中经常出现在工具类中,主要是对一些集合或者数据进行一些非空的校验。定义和使用起来也是非常的方便。如果需要返回值,需要在返回泛型的同时在其前面加上"<T>"对返回的数据类型进行补充和说明。
事例如下:

package chenfu.type.function;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

/**
 * @Author: romantic_ke@163.com
 * @Description:
 * @Date: 2019/5/16 17:19
 */
public class TypeFuntions {

    static class MyException extends Exception {

        public MyException(String message) {
            super(message);
        }
    }
    public static <T> T run(T t) throws Exception {
        if (Objects.nonNull(t) && (t instanceof List)) {
            List list = (List) t;
            if (!list.isEmpty() && list.iterator().hasNext()) {
                return t;
            }
        }
        throw new MyException("不是List或者List没数据");
    }

    public static void main(String[] args) throws Exception {
//        ArrayList<Object> list = new ArrayList<>();
        HashSet<Object> objects = new HashSet<>();
//        run(list);
        run(objects);
    }
}

代码地址:https://github.com/chenfu1201/java.git
本案例所有代码均在该项目的type目录下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值