Java基础篇--概念理解(泛型、注解)

在之前的文章中,已经发布了常见的面试题,这里我花了点时间整理了一下对应的解答,由于个人能力有限,不一定完全到位,如果有解答的不合理的地方还请指点,在此谢过。

本文主要描述的是java面试中可能会出现的泛型和注解。说是可能会出现,但基本还是不会面试到这里啦。但是,如果你在实战中,泛型和注解在代码优化上能够起到很好的作用。在无侵入开发中,注解有着很重要的作用,所以理解好注解和泛型对我们实战过程还是很有帮助的。下面我们通过几个简单的例子来说明一下。

泛型的工作原理?有了解过类型擦除么?

在说到泛型的工作原理的时候,我们第一个想到的是类型擦除。所以我们先介绍一下类型擦除这个概念。

Java的泛型类型在编译器阶段实现,编译过程,泛型类型会被清除掉,生成的字节码中不包含任何的泛型信息,这个过程被称为类型擦除

List<String> list = new ArrayList<>();

上面定义的list为List<String>经过编译之后就成了List,所以在方法区里面并没有存入String的相关信息。当然我们可以通过以下一个简单的例子来说明一下类型擦除的效果:

public static void main(String[] args) throws Exception {

        List<String> list = new ArrayList<>();

        list.add("2");

        //idea在做检查的时候会报错,无法通过编译

        list.add(1);

        //类型擦除之后,通过反射可以添加整型,这句话执行不会报错

        list.getClass().getMethod("add", Object.class).invoke(list, 1);

    }

上面的反射可以添加任何类型,不会报错,但是要通过get方法取出来的时候会报错,因为get会进行强制类型转换为String。

 

泛型的原型

类型被擦除之后,在jvm中存入的是其限定类,如果没有限定,存入的是object类。换句话说,上面的list的类型被擦除之后,我们可以添加任何类型。

 

泛型的优缺点

当我们了解了类型擦除之后,我们就可以知道java泛型的工作原理了,当我们定义一个泛型T的时候,这个T是在jvm中存入object类型。聊到这里,你可能会想到既然存入的是Object,那为什么不直接使用Object呢?

这个就是泛型的作用了,java在1.5之后的版本引入了泛型,在这之前可能List的强制类型转换的错误会比较多,为了更好的避免这个问题,我们在使用泛型的时候,编译器一定会做类型检查,这样能够大大减少类型转换错误。比如上面的例子定义了一个List<String>的时候,我们想添加integer的时候会直接报错。但是泛型的使用也不是没有弊端的,从上面的内容我们知道,泛型根本不会被存入编码区,所以一个泛型的类型T是无法new 出来的,并且我们不能使用T.class()。一个被经常使用的场景就是反序列化一个泛型T是不被允许的,这个时候,我们必须要传入T的具体类型,这样就增加了一个传参,具体如下。

public class GenericClass<T> {

    public T getResult(String s){

        //报错,T不是一个类型

        T t = JSON.parseObject(s,T.class);

        return t;

    }

    //通过传入具体的类型,在强制转换

    public T getResult(String s,Class cls){

        T t = (T)JSON.parseObject(s,cls);

        return t;

    }

}

 

擦除之后,如何获取类型?

上面的内容说明了泛型是如何被擦除的,那么是不是一个泛型被擦除之后,就不能获取到其对应的类型了呢。显然不是的,在java中,泛型的类型在编译的时候确实被擦除了,但却有另外一种形式来保存,这个形式被称为签名(Signatures)。我们可以通过签名来获取泛型的类型。

public class Test extends GenericClass<String> {

}

//获取类型

ParameterizedType genericType =(ParameterizedType)Test.class.getGenericSuperclass();

//输出字符串类型

System.out.println(genericType.getActualTypeArguments()[0]);

 

泛型的限定符

通过上面的内容,应该对java的泛型有一个大概的了解了吧,上面我们有提到泛型的原型,如果没有限定符的话,那么原型就是object。在java中,有两个限定符extends 和 super。那么这两个限定符的作用是什么?这个限定符的常见使用方式是List<? extends T>和List <? super T>,List<? extends T>是指T的子类都可以存入,List <? super T>是指T的父类都可以存入。

 

如何定义一个java的注解,并阐述其实现原理

在java语言中,注解是比较常见的,比如@override,而在实战中,注解有助于我们代码的解耦和无侵入性。Java的注解有三类,分别是:元注解,自定义注解,jdk自带的注解

元注解是指在定义一个注解的时候,必须要使用元注解进行标注,@Target,@Retention,@Documented,@Inherited,这四个是java的元注解;

jdk自带的注解是java已经定义好的注解,比如@override。

自定义注解是开发者定义的注解,下面我们通过一个注解的定义来简单说明一下注解的几个基本元素。

import java.lang.annotation.*;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented()

@Inherited()

public @interface AnnotationTest {

String value()default "";

}

 

定义好一个注解,至少需要使用到元注解的两个@Target和@Retention。元注解的四个注解分别代表的意思是:

元注解

作用

取值

@Target

运行地方

如下

@Retention

保留时间

Source代码中,class编译后的类,runtime运行(常用)

@Document

是否文档化

@Inhrited

能否被继承

 

@Target的取值有以下:

ElementType.CONSTRUCTOR 可以给构造方法进行注解

ElementType.FIELD 可以给属性进行注解

ElementType.LOCAL_VARIABLE 可以给局部变量进行注解

ElementType.METHOD 可以给方法进行注解

ElementType.PACKAGE 可以给一个包进行注解

ElementType.PARAMETER 可以给一个方法内的参数进行注解

ElementType.ANNOTATION_TYPE 可以给一个注解进行注解

ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举(常用)

 

Java注解的实现原理是根据不同的存留时间分别实现的。Source是只保留在源码阶段,在编译的时候就会把这些信息丢弃掉,所以基本上我们不会使用到。Class是指编译之后会保存在类中,但不会到jvm中。Runtime是会一直到运行环境中保存。在runtime的过程中,实际上底层是通过反射的原理去实现的。而编译时的注解会通过apt技术对类进行扫描,如果是source的不会进行编译到class中,如果是class的话,会添加到环境中,如果是runtime的话,会通知jvm把这些数据也加载到jvm中。

 

自定义注解的参数支持返回以下类型:

1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)

2.String类型

3.Class类型

4.enum类型

5.Annotation类型

6.以上所有类型的数组

 

注解和泛型是我们在代码中经常用到的技术,掌握这些技术,对提高代码的可读性有大的提升,但是面试的时候,注解和泛型并不是经常被问到。注解的核心在于如何自定义一个注解,并且结合spring的aop一起使用,而泛型的核心在于理解类型擦除的概念,了解这个概念之后,对你了解泛型有很大的帮助。本文的内容就这么多,如果你觉得对你的学习和面试有些帮助,帮忙点个赞或者转发一下哈,谢谢。

 

想要了解更多java内容(包含大厂面试题和题解)可以关注公众号,也可以在公众号留言,帮忙内推阿里、腾讯等互联网大厂哈

 

                                     

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值