01、泛型是什么?—,双非本科字节跳动Android面试题分享

1.1 参数化类型

我们以泛型类的使用作为事例,如下:

// 泛型类的定义
public class Generics {
// 未知类型
private T mData;

public T getData() {
return mData;
}

public void setData(T data) {
this.mData = data;
}
}

在泛型类内定义了泛型【T】,此时【T】是一个未知类型。

// 泛型类的使用,将Person类作为参数传入泛型类
Generics generics = new Generics();

在泛型类创建对象时,我们将Person类作为参数传入泛型类,此时泛型类内部的【T】就变成了已知类型Person。

通过参数传入,作为泛型的类型,就是参数化类型。

二、泛型种类及边界

2.1 泛型种类

1. 泛型接口

public interface Base {

public T getData();

public void setData(T data);

}

2. 泛型类

public class Generics{
private T mData;

public T getData() {
return mData;
}

public void setData(T data) {
this.mData = data;
}
}

3. 泛型方法

// public后面的是泛型方法的关键
public Generics getGenerics() {
return new Generics();
}

2.2 泛型边界

以上几种类型均可定义泛型的边界,语法 、<T extends A&B&…>,泛型重载了extends的关键字,与通常JAVA中使用的extends不同。

  • < T extends A>:单个边界,A可以是类或接口,只能接收继承或者实现A的类型。
  • < T extends A&B&…>:多个边界,A可以是类或接口,A之后的只能是接口。比如:<T extends A&B&C>里面,T必须继承A类型或实现A接口,并且必须实现B和C接口。

三、泛型的好处

3.1 代码更健壮

泛型将集合的类型检测提前到了编译期,保证错误在编译时就会抛出,基本上代码编辑器(Android Studio、IDEA等)在书写代码阶段给泛型传入错误类型就会报错。

拥有泛型之前只能在运行时抛出类型转换异常(ClassCastException),代码十分脆弱。

// 泛型存在之前
// 集合里存入Fruit和Dog,编译不会报错
List fruits = new ArrayList();
fruits.add(new Fruit());
fruits.add(new Dog()); // X 错误的插入,直到运行时报错

// 泛型存在之后
List fruits = new ArrayList();
fruits.add(new Fruit());
fruits.add(new Dog());// X 编译时就会报错

3.2 代码更简洁

泛型省去了类型的强制转换。在没有泛型之前,集合内的对象都会被向上转型为Object,所以需要强转。

// 没有泛型之前,获取对象需要强转
Fruit fruit = (Fruit) fruits.get(0);

3.3 代码复用性强

泛型就是使用参数化类型,在一段代码上操作多种数据类型。比如:对几个类的处理,在逻辑上完全相同,那自然会想这段逻辑代码只写一遍就好了,所以泛型就产生了。

四、泛型的原理

泛型在JDK1.5才出现,为了向下兼容,虚拟机是并不支持泛型的,所以JAVA在编译阶段除了进行类型判断,还对泛型进行了擦除,于是所有的泛型在字节码里都变成了原始类型,和C#的泛型不同,JAVA使用的是伪泛型

4.1 泛型擦除

在编译阶段生成字节码时,会进行泛型擦除,所以我们看下生成的字节码文件,就可以清晰的看到泛型【

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

浏览器打开:qq.cn.hn/FTe 免费领取

T】被转换成了Object。

// java代码
public class Generics {
private T mData;

public T getData() {
return mData;
}

public void setData(T data) {
this.mData = data;
}
}

下面是Generics类生成的字节码

// class version 51.0 (51)
// access flags 0x21
// signature <T:Ljava/lang/Object;>Ljava/lang/Object;
// declaration: com/kproduce/androidstudy/test/Generics
public class com/kproduce/androidstudy/test/Generics {

// compiled from: Generics.java

// access flags 0x2
// signature TT;
// declaration: T
private Ljava/lang/Object; mData

// access flags 0x1
public ()V
L0
LINENUMBER 6 L0
ALOAD 0
INVOKESPECIAL java/lang/Object. ()V
RETURN
L1
LOCALVARIABLE this Lcom/kproduce/androidstudy/test/Generics; L0 L1 0
// signature Lcom/kproduce/androidstudy/test/Generics<TT;>;
// declaration: com.kproduce.androidstudy.test.Generics
MAXSTACK = 1
MAXLOCALS = 1

// access flags 0x1
// signature ()TT;
// declaration: T getData()
public getData()Ljava/lang/Object;
L0
LINENUMBER 10 L0
ALOAD 0
GETFIELD com/kproduce/androidstudy/test/Generics.mData : Ljava/lang/Object;
ARETURN
L1
LOCALVARIABLE this Lcom/kproduce/androidstudy/test/Generics; L0 L1 0
// signature Lcom/kproduce/androidstudy/test/Generics<TT;>;
// declaration: com.kproduce.androidstudy.test.Generics
MAXSTACK = 1
MAXLOCALS = 1

// access flags 0x1
// signature (TT;)V
// declaration: void setData(T)
public setData(Ljava/lang/Object;)V
L0
LINENUMBER 14 L0
ALOAD 0
ALOAD 1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值