Java-泛型和注解的总结

泛型

什么是泛型?

泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
例如:GenericClass< T >{ }

一些常用的泛型类型变量

  • E:元素(Element),多用于java集合框架
  • K:关键字(Key)
  • N:数字(Number)
  • T:类型(Type)
  • V:值(Value)

泛型的相关使用:

  • 集合中的使用,规范化数据,作用在编译期间
  • 泛型可以作用在类的声明,接口的声明,方法的声明
  • 在本类中当成已知类型的存在,是一个占位符
  • 反射可以越过泛型检查,其实都是Object

泛型类

  • 在定义类的时候使用泛型<T,E,K,V> 泛型符号名字和个数无要求,在本来中作为已知存在
  • 在实例化的时候如果不指定类型,都当成Object来看
  • 静态方法不能使用类的泛型占位符
public class CustomGeneric<T, A, B> {
    private T name;
    private A a;
    private B b;

    public T method1() {
        return name;
    }

    public void method2(A a) {
        System.out.println(a);
    }
    /*public static void method3(B b){//报错:静态方法不能使用类的泛型占位符
    }*/
}

泛型接口

1、定义一个接口

public interface GenericInter<A, B, C> {

    void methodA(A a);

    void methodB(B a);

    void methodC(C a);
}

2、实现接口的实现类分两种情况:

2.1 实现类指定泛型类型,在实现的时候接口泛型确定下来

public class GenericInterImpl implements GenericInter<String,Integer,Double> {
    @Override
    public void methodA(String s) {

    }

    @Override
    public void methodB(Integer a) {

    }

    @Override
    public void methodC(Double a) {

    }
}

测试类:

@Test
    public void methodA(){
        GenericInterImpl genericInter = new GenericInterImpl();
    }

2.2 现类不指定接口中泛型类型,继续把泛型占位符带上

  • 类中的泛型占位符可以多于接口中定义的占位符个数,但是必须一一对应。
  • new类的时候需要把类中定义的占位符一一对应的确定泛型
public class GenericInterImpl1<A,B,C,D> implements GenericInter<A,B,C> {
    @Override
    public void methodA(A a) {

    }

    @Override
    public void methodB(B a) {

    }

    @Override
    public void methodC(C a) {

    }
}

测试类:

@Test
    public void methodA(){
        GenericInterImpl1<String, Integer, Double, String> impl1 = new GenericInterImpl1<>();
    }

总结:

​ 使用的时候,如果不指定泛型类型,统统都当成Object来看

泛型方法

泛型是在进行方法调用时 根据传入的值来确定类型的

public class GenericMethod {

    public <T> T methodA(T t) {
        return t;
    }

    /**
     * 静态方法不能使用类的泛型占位符
     * @param b
     * @param <B>
     */
    public static <B> void methodB(B b) {
    }
}

泛型的上下限

<? extends T> 泛型的上限为T类型 只能是T类型或者T类型的子类

<? super T> 泛型的下限为T类型 只能是T类型或者T类型的父类

泛型中的约束和局限性:

1,不能实例化泛型类
2,静态变量或方法不能引用泛型类型变量,但是静态泛型方法是可以的
3,基本类型无法作为泛型类型
4,无法使用instanceof关键字或==判断泛型类的类型
5,泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的
6,泛型数组可以声明但无法实例化
7,泛型类不能继承Exception或者Throwable
8,不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出

注解

Java 注解(Annotation)又称 Java 标注,是 JDK1.5 引入的一种注释机制。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

注解只是一个特殊的标记,注解需要有解析程序:

  • 编译期间解析(编译器内部已经写好了)
  • 运行期间解析(使用反射进行解析)

内置注解(JDK提供的注解)

  • @Override:重写方法;编译器只要识别到此注解,检查子类的方法和父类的方法签名是否一致
  • @Deprecated:即将抛弃,不建议使用的
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
  • ​@SuppressWarnings:指示编译器去忽略注解中声明的警告。

元注解

元注解顾名思义我们可以理解为注解的注解,它是作用在注解中,方便我们使用注解实现想要的功能。元注解分别有@Retention、 @Target、 @Document、 @Inherited和@Repeatable(JDK1.8加入)五种。

  • @Target:表示注解可以标记在哪些类型上面(可以有多个值)
  • @Retention:注解的保留期
  • @Doucumented 在生成java API文档的时候,加入注解内容
  • @Inherited 表示子类可以继承,但这并不是真的继承,只是通过使用@Inherited,可以让子类Class对象使用getAnnotations()获取父类被@Inherited修饰的注解

@Target的取值

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE, //类上,接口上,枚举类

    /** Field declaration (includes enum constants) */
    FIELD, // 成员变量

    /** Method declaration */
    METHOD, //方法

    /** Formal parameter declaration */
    PARAMETER, //参数

    /** Constructor declaration */
    CONSTRUCTOR,// 构造方法

    /** Local variable declaration */
    LOCAL_VARIABLE, //局部变量

    /** Annotation type declaration */
    ANNOTATION_TYPE, //注解类型

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Retention的取值

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE, // 表示注解在源码中存在,编译器一旦编译完成,丢弃此注解,不会存在与class文件中

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS, // 当类加载器把class文件加载到内存中的时候会丢弃此注解

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME // 在运行期间依然保留此注解
}

自定义注解

1、自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    
    //使用的时候可以不给值,使用此默认值
    String name() default "tom";

    //当成员只有一个的时候,名字是value
    int value();
}

注解的成员数据类型

  • 所有的基本数据类型,
  • String,
  • Class,
  • Enum,
  • 注解类型,
  • 以上数据类型的数组

如果使用了其他数据类型,编译器将会丢出一个编译错误,注意,声明注解元素时可以使用基本类型但不允许使用任何包装类型,同时还应该注意到注解也可以作为元素的类型,也就是嵌套注解。

注解不支持继承

注解是不支持继承的,因此不能使用关键字extends来继承某个@interface,但注解在编译后,编译器会自动继承java.lang.annotation.Annotation接口

2、自定义的注解的使用

public class Son extends Father {
    private String name;

    @CustomAnnotation(value = 18)
    public void method() {

    }

使用注解的注意点

  • 如果注解只有一个参数,最好取名value,这样在使用的时候可以直接指定属性值。例如:@Test(“hello”)
  • 只能使用public和默认权限修饰符修饰参数
  • 参数默认值:注解参数必须有确定的值。要么在定义的时候给默认值;要么在使用注解的时候指定参数值。

使用注解模拟Junit4测试

1、自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DivTest {
}

2、在类上进行注解

public class Student {
    @DivTest
    public void method1(){
        System.out.println("method1执行了");
    }
    public void method2(){
        System.out.println("method2执行了");
    }
    @DivTest
    public void method3(){
        System.out.println("method3执行了");
    }
    public void method4(){
        System.out.println("method4执行了");
    }
    @DivTest
    public void method5(){
        System.out.println("method5执行了");
    }
}

3、对程序进行解析,通过反射,凡是方法上面有注解的,进行方法调用

public class ReflectionDivTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> aClass = Class.forName("com.codeyancy.test.Student");
        Object o = aClass.newInstance();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            if (declaredMethod.isAnnotationPresent(DivTest.class)) {
                declaredMethod.invoke(o);
            }
        }
    }
}

结果:

在这里插入图片描述
带有注解的方法执行了!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值