传智播客培训2.19 泛型和反射-阿里云开发者社区

开发者社区> 开发与运维> 正文

传智播客培训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的语法

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章