Java高新技術4(注解與泛型)


 

1.注解(Annotation):

/*
注解相當於一種標記,在程序中加了注解就等於為程序打上了某種標記,
沒加,則等於沒有某種標記,以后,javac編譯器,
開發工具和其他程序可以用反射來了解你的類及各種元素上有無何種標記,
看你有什么標記,就去干相應的事。
標記可以加在包,類,字段,方法,方法的參數以及局部變量上。
看java.lang包,可看到JDK中提供的最基本的annotation。 
*/

三種基本注解:

public class AnnotationTest {

    /**
     * @param args
     */
       //@SuppressWarnings("deprecation")//指示應該在注釋元素(以及包含在該注釋元素中的所有程序元素)中取消顯示指定的編譯器警告
                                      //會取消編譯器在編譯時對方法過時發出的警告(SuppressWarning:抑制警告)
                                      //即使main方法中用到過時方法也不會發出警告
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //System.runFinalizersOnExit(true);
         DeprecatedTest.say();
      
    }
    
    
    
}
class DeprecatedTest{
    @Deprecated//表明say方法已過時,這樣做好處:以前仍使用該代碼的開發人員依然程序可以執行成功
      //后來的開發人員在看到這個標記:哥們,這個方法過時了,盡量別用,你看看有沒有別的替代方法
      //在使用不被贊成的程序元素或在不被贊成的代碼中執行重寫時,編譯器會發出警告。 
    public static void say(){
         System.out.println("....");
    }
}




class Person{
 private String name;
 private int age;
 public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
 }
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override//加上這個說明一定要復寫,不復寫在編譯時期發生:
         //AnnotationTest.java:45: 錯誤: 方法不會覆蓋或實現超類型的方法
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Person other = (Person) obj;
    if (age != other.age)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
 }

}

注解的生命周期:

/*
  Retention(保留):
    注解的生命周期:
    RetentionPolicy.SOURCE:
          僅僅給編譯器看的,編譯器檢查完丟掉
          例如:@Override 強制要求復寫掉父類方法->不復寫編譯時期報錯
              @SuppressWarnings 抑制警告->編譯器一看 不讓我警告,得我什么也不報
    RetentionPolicy.CLASS:(默認)
                 從.java保留到.class但是被類加載器加載到虛擬機中時,會去掉
                例如:通過反射將拿不到注解類的實例
    RetentionPolicy.RUNTIME:
               直到運行階段注解依然存在    
              例如:@Deprecated:不但在編譯時期檢測方法是否過時,在運行時期依然會檢測方法的字節碼
 */

自定義注解與為注解添加屬性:

元注解:注解上的注解,例如@Retention,@Target

package com.itheima.day3;

public @interface MetaAnnotation {
  String value() default "Meta";
}
/*
 反編譯:
 public interface com.itheima.day3.MetaAnnotation 
   extends java.lang.annotation.Annotation {
 
     public abstract java.lang.String value();
}
*/
package com.itheima.day3;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import com.itheima.day1.TrafficLamp;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})//TYPE:Type 是 Java 編程語言中所有類型的公共高級接口。它們包括原始類型、參數化類型、數組類型、類型變量和基本類型。 
                                            //在這里TYPE表示:類、接口(包括注釋類型)或枚舉聲明 
                                            //Target這個注解指明下面的自定義注解可以使用的位置
public @interface CustomAnnotation {
    //有一個抽象方法
    public abstract String color() default "black";//為注解增加了一個屬性color
                                                   //指定默認值為black
    String value() default "white";//增加一個value屬性
    
    int[] arrAttri() default {1,2,3};//arrAttri屬性類型為int[]
    
    TrafficLamp lamp() default TrafficLamp.RED; //lamp屬性類型為枚舉
    
    Class<?> cls() default CustomAnnotation.class;//屬性類型為Class
    
    //較為復雜
    MetaAnnotation ma() default @MetaAnnotation("MetaAnnotation");//屬性類型為一個注解類型,
                                                                 //默認值是MetaAnnotation一個實例對象
}

/*
ElementType的枚舉常量:
ANNOTATION_TYPE 
注釋類型聲明 
CONSTRUCTOR 
構造方法聲明 
FIELD 
字段聲明(包括枚舉常量) 
LOCAL_VARIABLE 
局部變量聲明 
METHOD 
方法聲明 
PACKAGE 
包聲明 
PARAMETER 
參數聲明 
TYPE 
類、接口(包括注釋類型)或枚舉聲明 
*/

使用注解中的屬性:

package com.itheima.day3;

import java.lang.reflect.Method;

import com.itheima.day1.TrafficLamp;

@CustomAnnotation
public class AnnotationDemo {

    /**
     * @param args
     */
    
    public static CustomAnnotation getAnnotationOnMethod(String methodName)throws Exception{
         Method method=AnnotationDemo.class.getMethod(methodName);
         return method.getAnnotation(CustomAnnotation.class);
    }
    
    
    @CustomAnnotation("black") //應用注解的屬性
                               //如果注解類中有一個屬性為String value();(不一定為String,只要屬性名為value均可)
                              //可以將value="black"等價於"black"(即其他屬性都采用默認值或者你只有一個value屬性)
                               //例如:@Retention(RetentionPolicy.RUNTIME)-->內部屬性RetentionPolicy value();
    public static void value()throws Exception{
       
    
       CustomAnnotation ca=getAnnotationOnMethod("value");  
       System.out.println("value: "+ca.value());//black
    }
    
    
    @CustomAnnotation(arrAttri={4,5})//如果數組元素只有一個簡寫為arrAttri=6
    public static void arrAttri()throws Exception{
        CustomAnnotation ca=getAnnotationOnMethod("arrAttri");  
        System.out.println("arrAttri: "+ca.arrAttri().length);//2    
    }
    
    
    
    @CustomAnnotation(lamp=TrafficLamp.RED)
    public static void lamp ()throws Exception{
        CustomAnnotation ca=getAnnotationOnMethod("lamp");    
        System.out.println("lamp: "+ca.lamp().nextLamp());//GREEN    
           
    }
    
    
    @CustomAnnotation(ma=@MetaAnnotation("ma"))
    public static void metaAnnotation ()throws Exception{
        CustomAnnotation ca=getAnnotationOnMethod("metaAnnotation");     
        System.out.println("ma: "+ca.ma().value());
           
 }
   
    
  public static void main(String[] args)throws Exception {
        // TODO Auto-generated method stub
      CustomAnnotation ca=AnnotationDemo.class.getAnnotation
                         (CustomAnnotation.class);//將獲取類AnnotationDemo上的CustomAnnotation注解的一個實例,沒有返回null
      System.out.println(ca+"\n");
      
      value();
      arrAttri();
      lamp();
      metaAnnotation();
    }

}

 

注解屬性

   2.泛型問題總結:

①反射與泛型:

/*
泛型術語:
ArrayList<E>:泛型類型
             :E稱為類型變量/類型參數
ArrayList<Integer>:參數化的類型
                   :Integer稱為實際類型參數             
                    :<>typeof
  ArrayList:原始類型(rawtype)
*/
package com.itheima.day4;

import java.lang.reflect.Constructor;

public class GenericDemo1 {

    /**
     * @param args
     */
    public static void main(String[] args)throws Exception {
        // TODO Auto-generated method stub
      //反射與泛型
     /* Class<T>:
      T - 由此 Class 對象建模的類的類型。例如,String.class 的類型是 Class<String>。如果將被建模的類未知,則使用 Class<?>。    
      Constructor<T>
      T -在其中聲明構造方法的類。
      public T newInstance(Object... initargs)//返回值類型為T
     */
     Constructor<String> con=String.class.getConstructor();
     String str=con.newInstance();
    }
    

}
/*
 未使用泛型前,集合中可以存入任意引用類型的元素(Object)->安全隱患->在取出元素時進行強轉->運行時可能發生ClassCastException
 使用泛型后,限定集合中的元素類型為一個特定類型,集合中只能存儲同一個類型的對象
   1.將運行時期的的安全隱患轉移到了編譯時期
   2.避免了強制轉換的麻煩
 */

②一個糾結的錯誤:

public class GenericDemo2 {

    /**
     * @param args
     */
    public static void main(String[] args)throws Exception{
        // TODO Auto-generated method stub
     List<Integer> al=new ArrayList<Integer>();
     System.out.println(al.getClass());
     al.getClass().getMethod("add",Object.class).invoke(al,"abc");
     System.out.println(al.get(0));//根據實際參數參數類型Integer確定調用println(Object obj)
     
     
     List<String> al_2=new ArrayList<String>();
     System.out.println(al_2.getClass());
     al_2.getClass().getMethod("add",Object.class).invoke(al_2,1);

     System.out.println(al_2.get(0));//根據實際參數參數類型String確定調用println(String obj)                                       //因此會引發ClassCastException
            
    
    }
  
}

③異常與泛型

//對異常使用泛型
    public static <T extends Exception> void genericException()throws T{
        try{
            
        }
        catch(Exception e){//catch中的形參必須明確不能寫 T e,catch要明確捕獲的異常
            throw (T)e;//e一定是Exception或其子類
        }
    }

④類型參數的類型推斷:

/*
 類型參數的類型推斷總結:
1.
  static <E> void swap(E[] a, int i, int j)
  swap(new String[3],3,4)
  ->推斷出E為String
2.
  static <T> void add(T a, T b) 
  add(3,5)
  T->Integer
 
  static <T> void add(T a, T b) 
  add(3.1,5)
  T->Number//取兩者最小父類
 
  static <T> T add(T a, T b) 
  Number num=add(3.1,5)
    這時候以返回值的實際參數類型為主:String->T->String,編譯器報錯,Number num=add(3.1,5)可以
3.
     static <T> void copy(T[] a,T[]  b)
     copy(new Integer[5],new String[5])
     OK,編譯器推斷出類型變量T為Number
     
     static <T> void copy(Collection<T> a , T[] b)
     copy(new Vector<String>(), new Integer[5])
           編譯器報錯:根據參數化的Vector類實例將類型變量直接確定為String類型-> T就是String,那么第二個形參的 類型變量T為String
*/

⑤如何獲取泛型中的實際類型參數?

package com.itheima.day4;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.lang.reflect.ParameterizedType;
public class GenericReflect {

    /**
     * @param args
     */
    public static void main(String[] args)throws Exception {
        // TODO Auto-generated method stub
         
        //如何通過反射來獲得泛型中的實際類型參數?
        //必須通過一個方法來獲取,因為方法對象提供有獲取形參類型的方法,由於泛型的實際類型參數在編譯后被擦除,不能直接通過反射獲取
        Method method=GenericReflect.class.getMethod("getParas",HashMap.class);
        Type[] type=method.getGenericParameterTypes();//如果形參類型是參數化類型,則為其返回的 Type 對象必須實際反映源代碼中使用的實際類型參數。 
                                                               //如果形參類型是類型變量或參數化類型,則創建它。否則將解析它。 
        System.out.println(type[0]);
        
        Type[] actualType=((ParameterizedType)type[0]).getActualTypeArguments();//返回表示此類型實際類型參數的 Type 對象的數組。
        
        System.out.println(actualType[0]+"\n"+actualType[1]);
    }
    
/*通過反射獲取泛型中的實際類型參數*/
    public static void getParas(HashMap<Integer,String> hs){
        
    }
}

反射獲取實際類型參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM