欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

黑马程序员--Java注解以及泛型,黑马--java

来源: javaer 分享于  点击 24989 次 点评:87

黑马程序员--Java注解以及泛型,黑马--java


---------------------- android培训、java培训、期待与您交流! ------------------------------------------------------------------------------------------------------------------------------------------------

 Java中的注解

注解就相当于是一个类,在程序中用注解,就相当于创建了一个该类的对象。

 

常见的注解:

1、.@SuppressWarnings(value)(该注解仅仅保留在SOURCE阶段,因为编译器用完了就没有用了)
压制警告。指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。

2@Deprecated(该注解保留在RUNTIME阶段,因为例如System.runFinalizersOnExit(true)这个方法,在调用的时候,编译器或开发工具会显示该方法已经过时的警告,为什么会显示这个警告呢,是因为在编写这个方法的源程序的时候,使用了@Deprecated的注解,但是JDK中的类都是打包好的class类。这时Javac编译器或者开发工具会扫描System这个类,所以就会将该类加载到内存中,通过反射在内存中的该类的字节码上这个方法上是否有@Deprecated这个注解,因为有,所以编译器或者开发工具才会给出警告。所以应该是保留在RUNTIME阶段)
用来标记该方法已经过时了。
jdk原句:用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。


3、@Override(该注解仅仅保留在SOURCE阶段,因为编译器用完后就没有用了)

用来表示该方法是覆盖父类的方法,如果加了这个注解的方法报告了编译错误,表明该方法并没有真的按照覆盖的要求来写。
表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。

 

实现 Annotationjava.lang 中的类

Deprecated
  用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。

Override
  表示一个方法声明打算重写超类中的另一个方法声明。

SuppressWarnings
  指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。

 

 

 

实现 Annotationjava.lang.annotation 中的类

interface

Documented
  指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。

interface

Inherited
  指示注释类型被自动继承。

interface

Retention
  指示注释类型的注释要保留多久。

interface

Target
  指示注释类型所适用的程序元素的种类。

 

总结:

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。

 

自定义注解:

   @Retention(RetentionPolicy.RUNTIME)//Retention元注解代表的是ItcastAnnotation这个注解保留到运行阶段。


   @Target({ElementType.METHOD,ElementType.TYPE}) //Target这个元注解说明ItcastAnnotation这个注解作用在哪些上边。


   public @interface ItcastAnnotation {

   }
 

   定义了一个名称为ItcastAnnotation的注解。

  @ItcastAnnotation
  class AnnotationDemo {

  }

 在AnnotationDemo这个类上应用ItcastAnnotation这个注解。

 

public class AnnotationTest {
    public static void main(String[] args) {

         //判断在AnnotationDemo这个类的字节码上是否有注解存在。
         boolean flag=AnnotationDemo.class.isAnnotationPresent(ItcastAnnotation.class);
         if(flag){

              //在类上用@注解,就相当于是创建了该注解类的对象。

              //此处获取AnnotationDemo类的注解对象。
             ItcastAnnotation annotation=AnnotationDemo.class.getAnnotation(ItcastAnnotation.class);
             System.out.println(annotation);
         }
    }
}

通过反射,获取到AnnotationDemo这个类上的ItcastAnnotation这个注解。

元注解:

 

就是作用于注解的注解。常用的有2个,都位于java.lang.annotation包中

@Retention

@Retention其三种取值:RetetionPolicy.SOURCERetetionPolicy.CLASSRetetionPolicy.RUNTIME;

 

表明的是注解最后能保存到的阶段。

分别对应:java源文件-->class文件-->内存中的字节码。

java源程序中加入某个了注解,如果该注解的@Retention的属性是RetetionPolicy.SOURCE,则javac编译器在编译的时候,会将该注解去除掉,编译后的.class文件中就不会再有该注解的信息。如果是RetetionPolicy.CLASS,则javac编译器就不会将注解去除掉,该注解保留在.class文件中,当程序运行的时候调用该类的时候,就会用到类加载器通过各种检查,处理等操作加载该class文件,将该class文件加入到内存中,这时候,就会去除掉注解的信息,内存中的字节码,就不再有注解的信息。如果是RetetionPolicy.RUNTIME,则加载到内存中仍旧保留着这些注解的信息。

如果注解类型声明中不存在 Retention注释,则保留策略默认为RetentionPolicy.CLASS

@Target

指示注解类型所适用的程序元素的种类。如果注解类型声明中不存在 Target 元注解,则声明的类型可以用在任一程序元素上。如果存在这样的元注解,则编译器强制实施指定的使用限制。

例如,此元注释指示该声明类型是其自身,即元注释类型。它只能用在注释类型声明上:

@Target(ElementType.ANNOTATION_TYPE)

public @interface MetaAnnotationType {

     ...

}

对Target元注解应用的例子:

  //注解保留到内存阶段。
  @Retention(RetentionPolicy.RUNTIME)
  // 说明该注解只能用于方法声明上边。
  @Target(ElementType.METHOD)
   public @interface ItcastAnnotation {

  }

/*@ItcastAnnotation  这个会报错*/
   public class AnnotationTest {
   @ItcastAnnotation
   public static void main(String[] args) {

   }
}

如果在类上声明元注解。就会报错,这是因为在定义ItcastAnnotation注解的时候,Target元注解指明 了该注解只能用在

方法声明上边。所以,用在类上会报错。

枚举常量摘要

ANNOTATION_TYPE
 
注解类型声明(该注解就是元注解)

CONSTRUCTOR
 
构造方法声明

FIELD
 
字段声明(包括枚举常量)

LOCAL_VARIABLE
 
局部变量声明

METHOD
 
方法声明

PACKAGE
 
包声明

PARAMETER
 
参数声明

TYPE
 
类、接口、注解或枚举声明

 

 

注解的属性

如果在使用注解的时候,仅需要设置名称为value属性的值的时候,可以省略掉value=,直接写上值就可以了。当然这里的仅需设置value属性的值有多种情况:该注解仅有一个value属性;其他的属性都有默认值了,不用设置等等。

@SuppressWarnings(“deprecation”),这个注解就是只需要设置value属性的值,所以省略掉了value=

    //没有声明@Retention,默认值为在CLASS阶段。
    @Retention(RetentionPolicy.RUNTIME)
     public     @interface      ItcastAnnotation {
                public abstract String Color() default "BLUE";
                String value();
     }

 


    // 因为此处除了设置value属性外,还有Color属相设置了,所以value=不能省略
    @ItcastAnnotation(Color = "RED", value = "111111")
    public    class     AnnotationTest {
    // 此处需设置value属性,所以value=可以省略。
             @ItcastAnnotation("2222222222")
              public static void main(String[] args) {

             }
    }

属性的类型:

原始类型,StringClass类型,数组类型,枚举类型,注解类型,以及前边这些类型的数组。

 

属性类型举例:

注解属性为String类型的:

    //没有声明@Retention,默认值为在CLASS阶段。
    @Retention(RetentionPolicy.RUNTIME)
     public   @interface     ItcastAnnotation   {
                // 为该注解设置一个String类型的Color属性,但是定义的方式是定义抽象方
                // 法的形式,和接口基本一致,在定义属性的时候,属性前可以不加public abstract,
                // 系统会自动加上。
     public abstract String Color();
   }

 

    //此处是为Color属性赋值,因为定义的是String类型的属性,所以就要赋String类型的值
    //如果在定义注解的属性的时候,没有为属性赋默认值,那么一定要在注解使用的时候为该
    //属性赋值。
    @ItcastAnnotation(Color = "RED")
     public class AnnotationTest {

     }

 

public    class     AnnotationView {
      public static void main(String[] args) {
                       boolean flag = AnnotationTest.class
                                                                      .isAnnotationPresent(ItcastAnnotation.class);
                if (flag) {
                                   ItcastAnnotation annotation = AnnotationTest.class
                                                                                     .getAnnotation(ItcastAnnotation.class);
                                   // 属性调用的时候,是按照方法的形式来调用的。
                                  System.out.println(annotation.Color());
                            }
                  }
   }

  

 

数组类型,枚举,注解类型的属性:

       定义注解,并未注解定义属性。

        @Retention(RetentionPolicy.RUNTIME)
        public     @interface        ItcastAnnotation {
        // String类型的属性。
         public      abstract      String     Color() default "BLUE";

         String value();

        // 数组类型的属性。
         int[] arrayarr() default { 1, 2, 3 };

         // 枚举类型的属性
         TrafficLamp lamp() default TrafficLamp.GREEN;

         // 注解类型的属性
        /*
              * 该属性的类型是注解类型MetaAnnotation,同时为该属性指定了一个默认值,默认值也就是
              * 该类型的一个实例。因为MetaAnnotation有一个属性值是value,所以设置为了“zhangsan”
        */
         MetaAnnotation annotationArr() default @MetaAnnotation("zhangsan");

}

 

     在类上使用注解,并设置属性的值。

       // 因为此处除了设置value属性外,还有Color属相设置了,所以value=不能省略
       @ItcastAnnotation(Color = "RED", value = "111111", arrayarr = { 3, 4, 5, 5 }, annotationArr = @MetaAnnotation("lisi"))
        public class AnnotationTest {
       // 此处需设置value属性,所以value=可以省略。
       @ItcastAnnotation("2222222222")
        public static void main(String[] args) {

        }

       @SuppressWarnings("unused")
       // 当数组属性的值只有一个的情况下,可以不加大括号{}。
       @ItcastAnnotation(value = "11111", arrayarr = 2)
       private void test() {

       }
}

 

获取注解,获取注解的属性。


public     class    AnnotationView {
        public static void main(String[] args) {
                 boolean flag = AnnotationTest.class
                                            .isAnnotationPresent(ItcastAnnotation.class);
             if (flag) {
                            ItcastAnnotation annotation = AnnotationTest.class
                                                               .getAnnotation(ItcastAnnotation.class);
                                   // 属性调用的时候,是按照方法的形式来调用的。
                                  System.out.println(annotation.Color());
                                   // 获取数组属性的长度。
                                  System.out.println(annotation.arrayarr().length);
                                  // 获取枚举类型的属性
                                   System.out.println(annotation.lamp().nextLamp());
                                   // 获取注解类型的属性
                                   System.out.println(annotation.annotationArr().value());
                           }
                    }
            }

    }

Java中的泛型

Java中的泛型类型(或者泛型)类似于 C++ 中的模板。但是这种相似性仅限于表面,Java 语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码,这种实现技术称为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除)。这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会为 Java 厂商升级其 JVM 造成难以逾越的障碍。所以,java的泛型采用了可以完全在编译器中实现的擦除方法。

泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。
注意 类型<E> 例如 :ArrayList<E>,泛型E是用来限定ArrayList这个类的,编译器是从这个ArrayList的类源文件中擦出泛型信息的。
泛型的术语:
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>中的E称为类型变量或类型参数
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念着typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告,例如,
Collection<String> c = new Vector();//可不可以,不就是编译器一句话的事吗?
原始类型可以引用一个参数化类型的对象,编译报告警告,例如,
Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去
参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>(); //错误!
Vector<Object> v = new Vector<String>(); //也错误!
不能因为String是继承自Object类型,就认为这样也是正确的。
综上所述:
如果要使用泛型的话
一种情况是:两边都使用泛型,且类型参数必须相同;
二种情况是:只有一边使用泛型。
如果两边都使用泛型,但类型参数不同,那么就是错误的,编译器会报告异常。

?通配符
使用?通配符作为类型参数的参数化的类型的变量可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
也就是带?号的参数化的类型变量可以=其他参数化的类型变量。
例如:
Class<?> forName(String className)

Class<String>  clz=Class.forName(“java.lang.String”);
这样做是不对的,因为该方法返回的是Class<?>,只能用这种类型的变量引用其他各种参数化的类型的变量。
例如:
Class<?> cla= String.class;
限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();
提示:
限定通配符总是包括自己。
?只能用作引用,不能用它去给其他变量赋值
Vector<? extends Number> y = new Vector<Integer>();
Vector<Number> x = y;
上面的代码错误,原理与Vector<Object > X = new Vector<String>();相似,
只能通过强制类型转换方式来赋值
自定义泛型:
之前的都是使用泛型也就是用别人定义的泛型,自定义泛型就是定义泛型让其他人调用。
自定义泛型分为:定义泛型方法和定义泛型类。

定义泛型方法:
Java的泛型方法没有C++模板函数功能强大,java中的如下代码无法通过编译:
<T> T add(T x,T y)
{
 return (T) (x+y);
}
这是因为T代表的是任意类型的,不知道该类型是否支持+操作。所以会出现错误。
用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示,该字母可以是任意的,通常是T或者E。
其中<T>是用来定义泛型类型的,而其他部分的不写<>的T,则是在应用这个泛型类型。
只有引用类型才能作为泛型方法的实际参数,swap(new int[3],3,5);语句会报告编译错误。
编译器会把 原始类型[] 当做是Object来处理,而原始类型的数据的话,会自动装箱和拆箱。这是编译器就是这么设计的,没有内在的意义。
例如: int i=3在特定的应用场合将i自动装箱为Integer类型的,但是int[] arr,则不会将其装箱为Integer[] arr,编译器直接当做Object来处理。
泛型的应用场合:
1. 除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。
在应用的时候的场景是:

 

<U>Class<? extends U>

asSubclass(Class<U> clazz)
 
强制转换该 Class对象,以表示指定的 class对象所表示的类的一个子类。

 

 

boolean

isAnnotationPresent(Class<? extendsAnnotation>  annotationClass)

这个一个Class类的方法的使用时候的情形。
在泛型方法定义时候的场景(也就是<T> 中的情形):

 

<A extendsAnnotation>A
   
   

getAnnotation(Class<A> annotationClass)
   

public <A extends Annotation> A getAnnotation(Class<A> annotationClass)

并且可以用&来指定多个边界,如<V extends Serializable & cloneable> void method(){}

这个表示V既是Serializable的子类,也是cloneable的子类。

2. 普通方法、构造方法和静态方法中都可以使用泛型。
3. 也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch子句中。
4. 在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,例如:
public static <K,V> V getValue(K key) { return map.get(key);}

根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:
当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:
swap(new String[3],3,4)   à    static <E> void swap(E[] a, int i, int j)

当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:
add(3,5)   à static <T> T add(T a, T b) 
当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题:
fill(new Integer[3],3.5f)   à static <T> void fill(T[] a, T v) 
当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型, 并且使用返回值,这时候优先考虑返回值的类型,例如,下面语句实际对应的类型就是Integer了,编译将报告错误,将变量x的类型改为float,对比eclipse报告的错误提示,接着再将变量x类型改为Number,则没有了错误:
 int x =(3,3.5f)   à static <T> T add(T a, T b) 
参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题:
copy(new Integer[5],new String[5]) à static <T> void copy(T[] a,T[]  b);
copy(new Vector<String>(), new Integer[5]) à static <T> void copy(Collection<T> a , T[] b);

 

类型推断示例:

 

                    public    class    GenerticTest2 {
                                              @SuppressWarnings("unused")
                                              @Test
                                               /* test1演示类型的推断 */
 /*
  * 就本例而言,从下边可以看出,推断出来的T的实际类型是X和Y所继承的父类和接口的交集。 例如:add(3,
  * "word");3是Integer类型的,继承了Object,Number,Serializable,Comparable
  * 这些接口和类。而String继承了:Object,Serializable, CharSequence, Comparable。 所以交集就是:
  * Object,Serializable,Comparable。另外例如:Foloat和Integer都继承了Object以及Number,这个时候
  * 就只提示Number,不再提示Object。
  */
                                      public   void     test1() {
                                                                  Integer i = add(3, 5);
                                                                  // Type mismatch: cannot convert from Number&Comparable<?> to Float
                                                                  // Float f=add(3.5, 3);
                                                                  Number n = add(3.5, 3);
                                                                  Comparable<?> c = add(3.5, 3);
                                                                  // Type mismatch: cannot convert from Object&Comparable<?>&Serializable
                                                                  // to String
                                                                  // String s=add(3, "word");
                                                                  Object obj = add(3, "word");
                                                                  Serializable s = add(3, "abc");
                                       }

                                    private <T> T add(T x, T y) {
                                                     // The operator + is undefined for the argument type(s) T
                                                     // return x+y;
                                                     // 所以此处只能模仿C++的模板,C++的模板是在此处是可以写+的。
                                                     return null;
                                    }

 
                                   @Test
                                   public   void   test2() {
                                                    String[] str = { "zhang", "wan", "ting" };
                                                    swap(str, 0, 1);
                                                    System.out.println(Arrays.toString(str));
                                                    int[] arr = { 1, 2, 3, 4 };
                                                    // 此处会报错,错误原因是:int不能被当做是Object类型,而泛型T只能是引用数据类型。
                                                    // 所以int[]不能被当做是T[]来对待。通常情况下,编译器会把 原始类型[] 直接当做Object来处理
                                                    // 但是add(3,3)能成功,是因为自动装箱功能。
                                                    // swap(arr,2,3);
                                  }

                                  private <T>  void   swap(T[] a, int i, int j) {
                                                   T  temp  =  a[i];
                                                   a[i] = a[j];
                                                   a[j] = temp;
                                 }

                                 @Test
                                 // 这是编译器进行类型推断的算法,具体什么情况下做推断,可以参考PPT。
                                public   void    test3() {
                                                   copy1(new Vector<String>(), new String[10]);
                                                   copy2(new Date[10], new String[10]);
                                                   // copy1(new Vector<Date>(), new String[10]);这个是错误的。
                                                   // copy3(new Vector<String>(), new Vector<Date>());这个是错误的。
                                 }

                                 /* 把任意参数类型的集合中的数据安全地复制到相应类型的数组中 */
                                 private <T> void copy1(Collection<T> src, T[] dest) {

                                 }

                                 /* 把任意参数类型的一个数组中的数据安全地复制到相应类型的另一个数组中 */
                                 private <T> void copy2(T[] src, T[] des) {

                                 }

                                @SuppressWarnings("unused")
                                 private <T> void copy3(Collection<T> src, Collection<T> dest) {

                                 }
             }

 

定义泛型的类型:

就是在类的身上定义泛型。例如类 Vector<E>就是泛型类型,之前的是方法级别的泛型。

如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型的时候,这个时候要采用泛型类型的方式进行定义,也就是类级别的泛型。

语法格式如下:

  public  class   GenericDao<T>{

          private T field;

          public void save(T  obj){ }

          public T  getByID(int id){ }

}

示例:

            /*
                     * 采用一个通用的方式,因为向数据库中插入和查找的可能是人,也可能是产品。
                     * 但是这种做法的弊病也很明显,因为在方法中定义的E的类型不确定。同一个dao
                     * 对象在操作的时候插入的时候可以插入的是人,查找的时候可能到的就是
                     * 商品。也就是说方法级别定义的泛型的类型参数之间没有相互的联系,是互相独立的。
            */
              public class GenericDao1 {

                              // 向数据库中添加一个新的对象。
                              public <E> boolean save(E obj) {
                                                  return false;
                              }

                             // 从数据库中根据id检索出一个对象
                              public <E> E findById(int id) {
                                                 return null;
                             }

                             //方法级别的泛型可以作用于静态方法。
                             public static <E> boolean update(E obj) {
                                               return false;
                              } 
              }

 

类级别的泛型是根据引用该类名时候指定的类型信息来参数化类型变量的。例如,如下两种方式都可以:

1.      GenericDao<String>dao=null;

2.      new  GenericDao<String>();

注意:

1.      在对泛型类型进行参数化的时候,类型参数的实例必须是引用类型,不能是基本类型。

2.      当定义泛型类型的时候,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。

因为静态成员是被所有参数化的类所共享,所以静态成员不应该有类级别的类型参数。

方法级别的泛型可以用静态。

             /*
                    * 和GenericDao1相比,此时的save方法和findById方法的E就是一致的关系。
                    * 同一个对象在操作的时候,就是在操作同一种类型的对象。
             */
                   public class GenericDao2<E> {

                                                // 向数据库中添加一个新的对象。
                                     public boolean save(E x) {
                                                           System.out.println(x.getClass().getName());
                                                           return false;
                  }

                   // 从数据库中根据id检索出一个对象
                  public E findById(int id) {
                                   return null;
                  }

               /*
                     * 类级别的泛型不可作用于静态方法。这是因为:本来定义泛型就是为了作用于某个类型的对象的 例如:GenericDao2<User> dao = new
                     * GenericDao2<User>();但是静态方法直接用类名就可以 调用,此时的E是什么还不能确定,所以当然是不可以的。
              */
                 // public static boolean update(E obj) {
                 // return false;
      // }
}

获取泛型中的实际类型参数:

具体的应用场景在hibernatewebService中有,但是我不是很清晰。

但是就技术点而言,就是获取实际类型参数。

例如:

通过访问数据库获取了大量的数据,要将这些数据封装成某种类型添加到一个集合中

   public void getData(){

             通过访问数据库获取大量的数据。

   }

   public Collection getVector(Vector<Person> v){

            getData();

            …………..

            …………..

}

或者

  public Vector<Person>  getVector(){

          getData();

          …………….

          …………….

}

当然在框架中定义的都是用泛型来定义。通过用户配置类型。

此时,到底是将获取的数据封装为何种类型的对象存入到集合中呢?

这就要获取泛型的实际类型参数。

首先,通过通过参数化类型的对象是不能获取到的。

例如:Vector<Person>  v,通过v对象获取字节码是获取不到实际类型参数的。因为,在编译阶段,就将泛型的信息擦除掉了。在程序运行阶段就更获取不到泛型的信息了。

但是可以通过方法的反射来获取方法参数的信息或者方法返回类型的信息达到我们获取实际类型参数的目的。

 

Type[]

getGenericExceptionTypes() 
 
返回 Type 对象数组,这些对象描述了声明由此  Method 对象抛出的异常。

Type[]

getGenericParameterTypes() 
 
按照声明顺序返回 Type对象的数组,这些对象描述了此  Method对象所表示的方法的形参类型的。

Type

getGenericReturnType() 
 
返回表示由此 Method对象所表示方法的正式返回类型的  Type对象。

 

Class<?>[]

getParameterTypes() 
 
按照声明顺序返回 Class对象的数组,这些对象描述了此  Method对象所表示的方法的形参类型。

 

获取泛型参数的例子:

public class GetActualTypeArg {
      @Test
        public void test1() throws Exception {
                              Method applymethod = GetActualTypeArg.class.getMethod("applyVector",
                                                                                                                                                                  Vector.class);
                                              // 获取applymethod方法的参数类型,注意getGenericParameterTypes和getParameterTypes()方法的区别。
                              Type[] types = applymethod.getGenericParameterTypes();
                                              // 因为形参类型是按照顺序返回的,因为第一个是参数化的类型,所以就强转为了
                                              // 参数化的类型。其中ParameterizedType是Type的子接口。
                              ParameterizedType pType = (ParameterizedType) types[0];
                                              // 获取pType的原始类型。
                              System.out.println(pType.getRawType());
                                             // 获取Ptype的实际类型参数。因为可能是<k,v>这种形式,所以
                                             // getActualTypeArguments方法返回的仍旧是Type[]类型的。我们获取第一个就可以了。
                              System.out.println(pType.getActualTypeArguments()[0]);
       }

       @Test
        public void test2() throws Exception {
                              Method getListmethod = GetActualTypeArg.class.getMethod("getList");
                                             // 通过getGenericReturnType这个方法,返回泛型化的返回类型,要和getReturnType方法进行区分。
                              Type retargtype = getListmethod.getGenericReturnType();
                                            // 因为本身这个类型就是参数化的类型,所以进行强转为参数化的类型。
                              ParameterizedType ptype = (ParameterizedType) retargtype;
                              System.out.println(ptype.getRawType());
                              System.out.println(ptype.getActualTypeArguments()[0]);
     }

      public void applyVector(Vector<Date> v) {

     }

     public ArrayList<String> getList() {
                           return null;
     }
 }

 

 

-----------------------android培训、java培训、期待与您交流! --------------------------------------------------------------------------------------------------------------------------------------------------

详细请查看:http://edu.csdn.net/heima  

相关文章

    暂无相关文章
相关栏目:

用户点评