閱讀200 返回首頁    go 阿裏雲 go 技術社區[雲棲]


傳智播客培訓2.19 泛型和反射

一、泛型

 

1.       為什麼使用泛型?

       jdk5以前,對象一旦存入集合就是去特性,變成Object類型

       從集合取出元素時,就需要做強轉,

       有的時候我們不確定集合中到底存儲的是什麼類型,強轉時容易出錯

 

       jdk5中,為了提供集合的安全性,定義了泛型,我們可以在使用集合時利用泛型

       限定集合存入的數據類型

 

2.       用泛型的好處?

        在迭代集合時,可以避免強轉的麻煩

        將運行時期的錯誤轉移到編譯階段

3.       由於集合是用於存儲對象的,基本數據類型需要包裝後才能存入集合,所以

       集合上使用的泛型必須是引用數據類型

 

4.       什麼情況下用泛型

       如果一個類有兩個或多個方法的形參必須為同一種類型,或者方法的返回值必須為同一種類型

       就可以使用泛型來解決

 

       簡單來說,在一個類中多個方法使用的類型必須是同一種類型,但是可以為任意類型

5.       List<T> 當中T稱為類型參數  List<String> 當中String 實際類型參數

6.       自定義泛型

       在類的後麵自定義泛型,類型多處用到的類型需要是同一種類型

// 一個學生對象學習什麼就必須玩什麼

public class Student<T,E> {

 

    // 使用類型參數

    public T study(T t) {

       return null;

    }

   

    public void play(T t) {

      

    }

 

    public void eat(E e) {

      

    }

}

 

    定義泛型方法, 方法的形參和返回值需要是同一種類型

// 求兩個數的最大數

// 判斷兩個對象中的較大者

public static <T> T getMax(T x, T y) {

    /*if(x>y)

       return x;

    return y;*/

    // TreeSet

    // 判斷x對象是否具備比較的功能

    if(x instanceof Comparable) {

       Comparable com = (Comparable) x;

       int num = com.compareTo(y);

       if(num>0)

           return x;

       return y;

    }

    // 說明x不具備比較功能

    throw new RuntimeException("對不起,比不了!");

   

 

   

}

 

public static <T> void reverse(T[] arr) {

    int start = 0;

    int end = arr.length - 1;

    while(end>start) {

       T temp = arr[start];

       arr[start] = arr[end];

       arr[end] = temp;

       start++;

       end--;

    }

}

 

二、反射

 

1.       理解Class

   對象都是根據類創建出來的—>創建一個對象代表李四這個人—>李四(跑起來)

       Person.class(描述所有和李四類似的事物的信息) à Person對象 à 李四(趙六、王五)

       Class.class(描述字節碼這類事物的特征) –> Class對象—> Person.class字節碼(Student.class Boy.class String.class)

 

所有的Person對象能做的事情都用方法來描述,例如跑步用run方法描述

所有的Class對象(字節碼)能做的事情用方法來描述,例如創建對象用newInstance來描述

 

2.       通過反射獲得Class對象

三種方式獲得

// 1. 根據給定的類名來獲得

String methodname = "run";

String classname = "cn.itcast.reflect.Person";   // 來自配置文件

Class clazz = Class.forName(classname);   // 此對象代表Person.class

Object obj = clazz.newInstance();  // 創建對象

 

 

// 2. 如果拿到了對象,不知道是什麼類型

Object obj = new Person();

Class clazz1 = obj.getClass();  // 獲得對象具體的類型

 

// 3. 如果是明確地獲得某個類的Class對象

Class clazz2 = Person.class;    // 主要用於傳參

 

// java中所有的類型都會對應一個Class對象 int Integer

Class intClazz = int.class;

Class intarrClazz = int[].class;

Class voidClazz = void.class;

 

3.       反射能做什麼事情

// 調用任何一個對象的任何方法

// 讀取配置文件獲得如下信息

String classname = "cn.itcast.reflect.Student";

String methodname = "study";

 

 

// Personrun方法調用

// 1.創建Person對象

Class clazz = Class.forName(classname);   // 此對象代表Person.class

Object obj = clazz.newInstance();  // 創建對象

// 2.獲得表示run方法的對象

Method runMethod = clazz.getMethod(methodname);

// 3.通過Person對象來調用run方法

 

4.       通過反射獲得類的成員變量

// 獲得代表某個屬性的Field對象

Class clazz = Person.class;

 

Field[] fields = clazz.getDeclaredFields();

for(Field field : fields) {

    String name = field.getName();  // 獲得屬性名

    Class type = field.getType();   // 獲得屬性的類型

    System.out.println("屬性名:" + name + "屬性類型:" + type);

}

 

// 獲得對象的某個指定的屬性,並為該屬性賦值

// 明確告訴你,獲得name屬性

String fieldname = "name";

Object obj = new Person();

 

// 1. 獲得Class對象()

Class clazz1 = obj.getClass();

// 2. 獲得指定的屬性

Field nameField = clazz1.getDeclaredField(fieldname);

// 3. 為屬性賦值

// 私有屬性不行,因為java虛擬機會檢查訪問權限

// 如果一定要訪問,就需要取消java訪問檢查

nameField.setAccessible(true);

nameField.set(obj, "zhangsan");

/*

Person p = (Person) obj;

System.out.println(p.getName());*/

Object value = nameField.get(obj); // 獲得指定對象上該字段的值

System.out.println(value);

5.       通過反射獲得類的構造方法

// 獲得類

Class clazz = Person.class;

 

// 獲得類的所有構造函數

Constructor[] constructors = clazz.getConstructors();

for(Constructor con : constructors) {

    // 遍曆參數類型

    Class[] parameterTypes = con.getParameterTypes();

    for(Class type : parameterTypes)

       System.out.print(type.getName() + "   ");

    System.out.println();

}

 

// 獲得指定的構造函數,創建對象

// 要求調用參數為 String int 的構造函數

// 1. 反射出指定的構造函數

Constructor con = clazz.getConstructor(String.class, int.class);

// 2. 調用構造函數創建對象

Object obj = con.newInstance("wangwu", 23);

System.out.println(obj); // toString

6.       通過反射獲得類的成員方法

Class clazz = Person.class;

 

// 獲得類的所有方法

Method[] methods = clazz.getDeclaredMethods();

for(Method m : methods) {

    String name = m.getName();  // 方法名

    System.out.print("方法名:" + name);

    // 參數類型

    System.out.print(", 參數類型依次為:");

    Class[] types = m.getParameterTypes();

    for(Class type : types)

       System.out.print(type.getName() + "  ");

    // 返回值類型

    Class returnType = m.getReturnType();

    System.out.print(",返回值類型:" + returnType.getName());

    System.out.println();

}

 

// 反射出指定的方法,調用

// 創建一個對象

Object obj = clazz.newInstance();

// 調用play方法

Method playMethod = clazz.getMethod("play", String.class);

playMethod.invoke(obj, "zhangsan");

// 調用eat方法

Method eatMethod = clazz.getMethod("eat");

eatMethod.invoke(null);

// 調用sleep方法

Method sleepMethod = clazz.getMethod("sleep", String[].class);

String[] arr = {"a","b"};

sleepMethod.invoke(obj, (Object)arr);  // 符合1.41.5的語法

最後更新:2017-04-02 06:51:36

  上一篇:go socket編程(3)廣播 多播
  下一篇:go 限製文本框輸入指定字數內容