Java泛型、泛型类、泛型方法、泛型接口、通配符、通配符上边界、通配符下边界 的理解

什么是泛型?

为了确定数据添加的指定类型而加入,实际上就是一个类型占位符 如 T W E 都可以。 将代码中所指定的类型换成类型占位符 T W E 就是泛型。

泛型类

@Data
public class PersonT<T> {

    private T name;

    private T sex;

}
//泛型类测试
@Test
void personTTest() {
    PersonT<String> stringPersonT = new PersonT<>();
    stringPersonT.setName("张三");
    System.out.println(stringPersonT.getName());

    PersonT<Integer> integerPersonT = new PersonT<>();
    integerPersonT.setName(111);
    System.out.println(integerPersonT.getName());
}

泛型方法

public class PersonMethod<T> {

    /**
     * 泛型普通方法
     *
     * @param t
     */
    public void say(T t) {
        System.out.println(t + "说话了");
    }

    /**
     * 静态泛型方法中的类型占位符和类中的占位符 毫无关系
     * 必须在static后面定义 占位符
     * 返回值为void
     */
    public static <W> void staticVoidSay(W w) {
        System.out.println(w + "说:这是一个静态泛型方法");
    }

    /**
     * 静态泛型方法必须自己声明泛型<p>
     * 返回值为 你传递进来的类型
     *
     * @param w   参数
     * @param <W> 类型
     * @return W
     */
    public static <W> W staticWSay(W w) {
        return w;
    }

    /**
     * @param r   传递的值
     * @param <R> 你想传递的类型
     */
    public <R> void differentSay(R r) {
        System.out.println(r + "说:这是一个与类泛型不同的普通泛型方法");
    }
    
}

//泛型方法测试
@Test
void personMethodTest() {
    PersonMethod<String> personMethod = new PersonMethod<>();
    //普通泛型方法 与类的泛型类型一致
    personMethod.say("小明");
    //普通泛型方法 与类的泛型类型不一致
    personMethod.differentSay(2);

    //无返回值 静态泛型方法  直接调用即可
    PersonMethod.staticVoidSay("小黄");

    //有返回值 静态泛型方法
    int i = PersonMethod.staticWSay(1);
    System.out.println(i);
}

泛型接口

//接口
public interface PersonInterface<T> {

    /**
     * 普通泛型接口 与泛型接口的类型一致
     *
     * @param t
     */
    void say(T t);
}

//普通实现
@Service
public class PersonInterfaceStringImpl implements PersonInterface<String> {

    @Override
    public void say(String o) {
        System.out.println(o + "说话了");
    }
}

//泛型实现
@Service
public class PersonInterfaceTImpl<T> implements PersonInterface<T> {

    @Override
    public void say(T t) {
        System.out.println(t + ",未指定类型 在实现中定义了类型");
    }
}

//测试
@Test
void PersonInterfaceImplTest() {
    //泛型接口的实现类可以指定具体的泛型接口的具体泛型类型
    PersonInterface<String> string = new PersonInterfaceStringImpl();
    string.say("小绿");

    //泛型接口的实现类 如果没有指定具体的泛型类型,必须要在这个实现类中声明一个类型占位符给接口使用
    PersonInterface t = new PersonInterfaceTImpl();
    t.say(2);
    t.say("小黄");
}

擦除模式

public class PersonEraseMode<T> {

    private T name;

    public void say(){
        System.out.println("擦除模式的say");
    }
}

//擦除模式测试
@Test
void PersonEraseModeTest() {
    PersonEraseMode<String> eraseModeString = new PersonEraseMode<>();
    PersonEraseMode<Integer> eraseModeInt = new PersonEraseMode<>();
    //条件始终为true
    System.out.println(eraseModeString.getClass() == eraseModeInt.getClass());
    /**
     * Java类编译之后成为字节码文件
     * 泛型类 Person<T> 到字节码阶段时 会将泛型类型去除 成为 Person person = new Person();
     * 运行期间会将 泛型类型给擦除掉
     *
     * 编码编译阶段
     * PersonEraseMode<String> eraseModeString = new PersonEraseMode<>();
     * PersonEraseMode<Integer> eraseModeInt = new PersonEraseMode<>();
     *
     * 运行阶段
     * PersonEraseMode eraseModeString = new PersonEraseMode();
     * PersonEraseMode eraseModeInt = new PersonEraseMode();
     * 将泛型类型给去除掉,所以他们两的class字节码是完全相同的
     *
     */
}

通配符 ? :由于Java中的继承关系,在泛型中不做任何的声明修饰情况写下是不被认可的,所以需要使用通配符处理。
使用通配符在泛型中将Java中的继承关系 重写绑定
通配符使用 ? 表示 ?是泛型中所有类的父类 Object

@Data
public class PersonWildcard<T> {

    private T name;
	
    public void say(PersonWildcard<T> personWildcard) {
        this.setName(personWildcard.getName());
        System.out.println("这是无法识别Java继承关系的的say:" + name);
    }
}
//测试
@Test
void personWildcardTest() {
	 PersonWildcard<Number> numberPersonWildcard = new PersonWildcard<>();
     PersonWildcard<Integer> integerPersonWildcard = new PersonWildcard<>();
	//即便 Integer和Number 是父子关系,但是泛型当中它是无法识别的
    //numberPersonWildcard.say(integerPersonWildcard);
}

由于无法识别 所以需要使用 通配符来解决一下

/**
 * ? 通配符 表示 任何类型 Object
 *
 * @param personWildcard 参数
 */
public void sayWildcardObj(PersonWildcard<?> personWildcard) {
    //强制转换
    this.setName((T) personWildcard.getName());
    System.out.println("这是任意通配符?的say:" + name);
}

//测试
 @Test
 void personWildcardTest() {
 	PersonWildcard<Number> numberPersonWildcard = new PersonWildcard<>();
    PersonWildcard<Integer> integerPersonWildcard = new PersonWildcard<>();
    //即便 Integer和Number 是父子关系,但是泛型当中它是无法识别的
    //numberPersonWildcard.say(integerPersonWildcard);
    
    integerPersonWildcard.setName(1111);
    //将它换为通配符?即可实现继承关系
    numberPersonWildcard.sayWildcardObj(integerPersonWildcard);
    //但是 不是继承关系也可以 因为 通配符?表示Object类型
    PersonWildcard<String> stringPersonWildcard = new PersonWildcard<>();
    stringPersonWildcard.setName("小明");
    numberPersonWildcard.sayWildcardObj(stringPersonWildcard);
 }

虽然通配符可以实现继承关系,但是 同时,即使不是继承关系 通配符也可以绑定,因为 通配符 ? 表示任意类型 类似于 Object
所以如果需要限制类型,则可使用 上边界 extends、下边界 super 来实现

上边界

/**
 * 上边界
 * <p>
 * 传递进来的值 必须为 特定类型的子类 或者 特定类型本身
 * <p>
 * ? extends T 传递进来的类型 必须 继承 T
 *
 * @param personWildcard 本身类型 or 子类类型
 */
public void sayWildcardExtends(PersonWildcard<? extends T> personWildcard) {
   this.setName(personWildcard.getName());
   System.out.println("这是上边界 指定泛型类型 指定泛型可以传入 T 和 T的子类:" + name);
}

//测试
@Test
void test(){
	PersonWildcard<Number> numberPersonWildcard = new PersonWildcard<>();
    PersonWildcard<Integer> integerPersonWildcard = new PersonWildcard<>();
    PersonWildcard<String> stringPersonWildcard = new PersonWildcard<>();
	//上边界 限制 Number 类型的子类 或者是Number类型本身
    numberPersonWildcard.sayWildcardExtends(integerPersonWildcard);
    //String不是Number类型的子类,所以不可传递
    //numberPersonWildcard.sayWildcardExtends(stringPersonWildcard);
}

下边界

/**
 * 下边界
 * 传递进来的值 必须为 特定类型的父类 或者 特定类型本身
 * ? super T 传递进来的类型 必须是T的父类
 *
 * @param personWildcard 必须是T或者T的父类
 */
public void sayWildcardSuper(PersonWildcard<? super T> personWildcard) {
    this.setName((T) personWildcard.getName());
    System.out.println("这是下边界 泛型类型必须是T 或者T的父类:" + name);
}

//测试
@Test
void test(){
	PersonWildcard<Number> numberPersonWildcard = new PersonWildcard<>();
    PersonWildcard<Integer> integerPersonWildcard = new PersonWildcard<>();
	
	//下边界 限制Number类型 或者Number的父类
    numberPersonWildcard.sayWildcardSuper(numberPersonWildcard);
    //Integer不是Number的父类,所以不能船体
    //numberPersonWildcard.sayWildcardSuper(integerPersonWildcard);
}

什么时候用上边界? 什么时候用下边界?

上边界:在读取T这个类型数据的时候,但 不用写入、修改 (只读取、不编辑)
下边界:需要写入数据,但 不需要读取 (只写入、不读取)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值