java泛型和注解

泛型和注解笔记

一.基本注解

      @Override:指定方法重写,强制一个子类必须重写父类的方法。只能作用于方法,不能作用于其他元素。

   @Override

   public String toString() {

      // TODO Auto-generated method stub

      returnsuper.toString();

   }

 

      @Deprecated:用于标记某个程序元素已过时,当其他程序使用已过时的类、方法时,编译器将会给出警告

   String string=new String(newbyte[1],10);

 

      @SuppressWarnings:抑制编译器警告。(译:给编译器发出一条指令,告诉它被批注的代码内部某些警告保持静默)

   @SuppressWarnings("deprecation")

   String string=new String(newbyte[1],10);

二.元注解

@Target(常用)

用于指定被修饰的Annotation可以用于什么地方。

@Retention(常用)

表示需要在什么级别保存该注解信息。

@Documented

将此注解包含在JavaDoc中

@Inherited

允许子类继承父类中的注解

@Target,@Retention

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public@interfaceMyAnnotation {

   String name() default"admin";

   int age() default 10;

}

@Target可用的ElementType参数包括

ANNOTATION_TYPE

指定该策略的Annotation只能修饰Annotation

CONSTRUCTOR

指定该策略的Annotation只能修饰构造器

FIELD

指定该策略的Annotation只能修饰成员变量

LOCAL_VARIABLE

指定该策略的Annotation只能修饰局部变量

METHOD

指定该策略的Annotation只能修饰方法定义

PACKAGE

指定该策略的Annotation只能修饰包定义

PARAMETER

指定该策略的Annotation只能修饰参数

TYPE

指定该策略的Annotation可以修饰类、接口(包括注解类型)或枚举定义

@Retention可选的RetentionPolicy参数包括:

SOURCE

编译器直接丢弃这种策略的注解

CLASS

编译器将把注解记录在class文件中。当运行Java程序时,JVM不再保留注解。这是默认值

RUNTIME

编译器将把注解记录在class文件中。当运行Java程序时,JVM仍会保留注解,程序可以通过反射获取该注解

自定义注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public@interfaceMyAnnotation {

   String name() default"admin";

   int age() default 10;

}

提取注解信息

      AnnotatedElement接口是所有程序元素(如Class、Method)的父接口,程序通过反射获取了某个类的AnnotatedElement对象之后,就可以通过该对象的方法来访问Annotation信息。

Annotation getAnnotation(Class<T> annotationClass)

返回该程序元素上存在的、指定类型的注解,如果该类型的注解不存在,则返回null

Annotation[] getAnnotations( )

返回该程序元素上存在的所有注解

boolean isAnnotationPressent(Class<? extend Annotation> annotationClass)

判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false

第一种:

Class clazz=Person.class;

Annotation[] annotations = clazz.getAnnotations();

for (Annotation annotation : annotations) {

System.out.println(annotation);

}

第二种:如果我们需要获取某个注解里的元数据,则可以将注解类型强制转换成所需的注解类型,然后通过注解对象的抽象方法来访问这些元数据。

Annotation annotation = clazz.getAnnotation(MyAnnotation.class);

    int age = ((MyAnnotation)annotation).age();

    String name2 = ((MyAnnotation)annotation).name();

    System.out.println(name2+"------"+age);

三.泛型

Java的集合有个缺点:当我们把一个对象“丢进”集合里后,集合就会“忘记”这个对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了Object类型。

为了解决这个问题,从JDK1.5以后,Java引入了“参数化类型(parametrized type)”的概念,允许我们在创建集合时指定集合元素的类型。如List<String>,这表明该List集合只能保存字符串类型的对象。Java的参数化类型被称为泛型(Generic)。

      泛型允许在定义接口、类时指定类型形参,类型形参在整个接口、类中可当成类型使用。

定义泛型接口、类

      当我们使用List类型时,为形参E传入String类型实参,则产生了一个新的类型:List<String>类型,我们可以把List<String>想象成E被替换成String的特殊List子接口:

      程序虽然定义了一个List<E>接口,但实际使用时可以产生无数多个List接口,只要为E传入不同的类型参数,系统就会多出一个新的List子接口

      注意:“ListString”只是逻辑上存在,物理上并不存在。

 

 

      当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或从该父类派生子类,但是当使用这些接口、父类时不能再包含类型参数。例如下面的代码就是错误的:

      这就好比我们定义方法的时候可以使用形参,但调用方法时必须传入实参。所以我们需要把上面代码的T换成实际类型。上面的代码应改为:

深入泛型

      当我们使用一个泛型类时,应该为这个泛型类传入一个类型实参,如果没有传入实参,就会引起泛型警告

public void test(List c)

{

       for(int i = 0;i<c.size();i++){

              System.out.println(c.get(i));

       }

}

 

 

类型通配符

      为了表示各种泛型List的父类,我们需要使用类型通配符,类型通配符是一个问号“?”,将一个问号作为类型实参传给List集合,写作:List<?>(意思是未知类型元素的List)。这个?被称为通配符,它可以匹配任何类型。

public void test(List<?> c)

{

       for(int i = 0;i<c.size();i++){

              System.out.println(c.get(i));

       }

}

 

 

      List<?>是任何泛型List的父类型

类型通配符上限

publicclass Canvas{

    publicvoid drawAll(List<Shape> shapes){

       for(Shape s:shapes){

           s.draw(this);

       }

    }

    publicstaticvoid main(String[] args) {

       List<Circle> circleList = new ArrayList<Circle>();

        circleList.add(new Circle());

       Canvas c = new Canvas();

       c.drawAll(circleList);

    }

}

 

 

 

      为了解决上述问题,可以修改代码如下:

publicclass Canvas{

    publicvoid drawAll(List<?> shapes){

       for(Shape s:shapes){

           s.draw(this);

       }

    }

    publicstaticvoid main(String[] args) {

       List<Circle> circleList = new ArrayList<Circle>();

        circleList.add(new Circle());

       Canvas c = new Canvas();

       c.drawAll(circleList);

    }

}

 

      通配符可以保证编译通过,但带来了类型安全问题

 

      实际上,我们需要一种泛型表示方法,它可以表示所有Shape泛型List的父类而不是所有泛型List的父类。为了满足这种需求,Java泛型提供了被限制的通配符

      语法:

publicclass Canvas{

    publicvoid drawAll(List<? extends shapes> shapes){

       for(Shape s:shapes){

           s.draw(this);

       }

    }

    publicstaticvoid main(String[] args) {

       List<Circle> circleList = new ArrayList<Circle>();

        circleList.add(new Circle());

       Canvas c = new Canvas();

       c.drawAll(circleList);

    }

}

 

泛型方法

      JDK1.5还提供了泛型方法的支持。

      示例:将一个Object数组的所有元素添加到一个Collection集合中。

staticvoid fromArrayToCollection(Object[] objs,Collection<Object> c){

    for(Object o:objs){

       c.add(o);

    }

}

 

      类型通配符在这里是不适用的,因为无法将对象添加到不知道具体类型的集合中

      语法:

      修改前面代码:

      与接口、类定义的类型形参相比,泛型方法定义的类型形参只能在方法内部使用

 

      前面代码编译器根据实参可以推断出最直接的类型形参的类型。为了让编译器能够准确的推断出泛型方法中类型形参的类型,不要制造迷惑!

static <T> void test(Collection<T> a,Collection<T> b){

    for(T o:a){

       b.add(o);

    }

}

publicstaticvoid main(String[] args) {

    List<Object> objList = new ArrayList<Object>();

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

    //这里将发生编译错误

    test(strList,objList);

}

 

static <T> void test(Collection<? extends T> a,Collection<T> b){

    for(T o:a){

       b.add(o);

    }

}

publicstaticvoid main(String[] args) {

    List<Object> objList = new ArrayList<Object>();

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

    test(strList,objList);

}

 

 

      前面所使用的test方法可以将集合a中的元素复制到集合b,假设该方法还需要一个返回值,返回最后一个被复制的元素,修改该方法如下:

static <T> T test(Collection<? extends T> a,Collection<T> b){

    T last = null;

    for(T o:a){

       last = o;

       b.add(o);

    }

    return last;

}

publicstaticvoid main(String[] args) {

    List<Number> nl = new ArrayList<Number>();

    List<Integer> il = new ArrayList<Integer>();

    //下面代码将引起编译错误

    Integer last = test(il,nl);

}

 

      如果要保留a集合的类型,需要使用类型通配符下限,修改该方法如下:

static <T> T test(Collection<T> a,Collection<? super T> b){

    T last = null;

    for(T o:a){

       last = o;

       b.add(o);

    }

    return last;

}

publicstaticvoid main(String[] args) {

    List<Number> nl = new ArrayList<Number>();

    List<Integer> il = new ArrayList<Integer>();

    Integer last = test(il,nl);

}

 

猜你喜欢

转载自blog.csdn.net/github_39936816/article/details/80557843