美文网首页
反射泛型容器

反射泛型容器

作者: 顾子豪 | 来源:发表于2021-07-07 22:41 被阅读0次

    一、 反射

    1.1> 什么是反射

    Class是反射的核心。在运行期进行实例的生成。

    Class文件

    • 属性

    • 方法 (构造方法, 静态方法, 普通方法)

    • 包路径

    • 类名

      。。。。

    1.2> 创建Class对象的种方式

    三种方式

    // 方式一  类.class
    Class personClazz = Person.class;
    
    // 方式二  实例.getClass()
    Person person = new Person();
    Class personClazz1 = person.getClass();
    
    // 方式三  Class.forName("类的全路径")
    Class personClazz2 = Class.forName("com.muse.Person");
    

    1.3> 通过Class创建对象

    • 不去考虑反射,正常场景

      Person person = new person(); // 调用构造方法。

    • 考虑反射,同样也是需要靠构造方法来创建对象的。

        @Test
        public void test2() throws Throwable{
            // 第一步:获得Class
            Class personClazz = Person.class;
    
            // 第二步:获得构造方法
            // Constructor<Person> constructor = personClazz.getConstructor();
            // String name, Integer age, Byte sex, Boolean isMarriage
            Constructor<Person> constructor = personClazz.getConstructor(String.class, Integer.class, Byte.class,
                    Boolean.class);
    
            // 第三步:创建对象 new Person(String name, Integer age, Byte sex, Boolean isMarriage)
            Person person = constructor.newInstance("muse", 10, (byte)1, true);
    
            // person.setName("muse");
    
            System.out.println(person);
    
        }
    

    1.4> 通过反射获取属性值

    反射是指将一个类的成员映射成相对应的java类型

    成员:

    • 属性 Field.java
    • 方法 (构造方法 Constructor.java , 静态方法, 普通方法Method.java)
    • 包路径 Package.java
    @Test
        public void test3() throws Throwable{
            // 第一步:获得Class
            Class personClazz = Person.class;
    
            // 第二步:获得构造方法
            Constructor<Person> constructor = personClazz.getConstructor();
            Person person = constructor.newInstance();
    
            // 第三步:通过Class对象,获得Field对象
            Field nameField = personClazz.getField("name");
    
            // 第四步:操作Field,获得属性值
            String name = String.valueOf(nameField.get(person));
    
            System.out.println(name);
        }
    
        /**
         * private
         *
         * @throws Throwable
         */
        @Test
        public void test4() throws Throwable{
            // 第一步:获得Class
            Class personClazz = Person.class;
    
            // 第二步:获得构造方法
            Constructor<Person> constructor = personClazz.getConstructor();
            Person person = constructor.newInstance();
    
            // 第三步:通过Class对象,获得Field对象
            Field sexField = personClazz.getDeclaredField("sex");
            sexField.setAccessible(true);
    
            // 第四步:操作Field,获得属性值
            System.out.println(sexField.get(person));
        }
    

    1.5> 创建一个反射工具类

    我们采用反射机制来实现一个工具BeanUtils,可以将一个对象属性相同的值赋值给另一个对象。

    public class BeanUtils {
    
        public static void convertor(Object originObj, Object targetObj) throws Throwable{
            // 第一步,获得class对象
            Class orginClazz = originObj.getClass();
            Class targetClazz = targetObj.getClass();
    
            // 第二步,获得Field
            Field[] orginFields =  orginClazz.getDeclaredFields();
            Field[] targetFields =  targetClazz.getDeclaredFields();
    
            // 第三步:赋值呗
            for (Field originField : orginFields) {
                for (Field targetField : targetFields) {
                    if (originField.getName().equals(targetField.getName())) {
                        originField.setAccessible(true);
                        targetField.setAccessible(true);
                        targetField.set(targetObj, originField.get(originObj));
                    }
                }
            }
        }
    
        public static void main(String[] args) throws Throwable{
            // Service层返回的
            Person person = new Person("muse", 10, (byte)1, true);
    
            // 需要返回给前段实体对象
            Person1 person1 = new Person1();
    
            BeanUtils.convertor(person, person1);
    
            System.out.println("person, person1" + person + person1);
        }
    }
    

    二、泛型

    2.1> 什么是泛型

    Object 任意类型;String name = (String)xxxx; List<String> names = new ArrayList();

    集合 Object Dog Cat

    泛型:

    产生优点:

    1> 代码简洁。

    2> 程序更加健壮。

    3> 编码期,可读性很高了。

    2.2> 泛型的基础

    • 类泛型

    • 方法泛型

    • 派生子类:

      1>子类明确类型

      2>子类不明确类型

    • 类型通配符 ?

    public void test(List list) {
        for() {
            .....
        }
    }
    
    List<String> names = new ArrayList();
    names.....值。
    test(names); 不行的
    
    public void test(List<Object> list) {
        for() {
            .....
        }
    }
    
    test(names); ok的
    public void test(List<?> list) {
        for() {
            .....
        }
    }
    
    
    • 通配符的上限 List< ? extends Number>
        /**
         * 去读,不去写
         */
        @Test
        public void tesePECSExtends() {
            List<Dog> dogs = Lists.newArrayList();
            dogs.add(new Dog());
    
            // 只知道animals里保存的是Animal的子类
            List<? extends Animal> animals = dogs;
    
            // animals.add(new Dog()); // 编译失败
            // animals.add(new Animal()); // 编译失败
    
            Animal animal = animals.get(0);
            // Dog dog = animals.get(0); // 编译失败
    
        }
    
    • 通配符的下限 List< ? super Type>

    2.3> 类型擦除和桥接方法

    // 最初的代码
    public class Node<T> {
      public T data;
      
      public void setData(T data) {
         this.data = data;
      }
    }
    
    public class MyNode extends Node<Integer> {
      public void setData(Integer data) {
        ....
      }
    }
    
    // jvm不认识泛型的,把泛型擦除掉, 兼容老版本jdk
    public class Node {
      public Object data;
      
      public void setData(Object data) {
         this.data = data;
      }
    }
    
    public class MyNode extends Node {
      
      // 桥接方法,编译器自动生成
      public void setData(Object data) {
         setData((Integer)data)
      }
      
      public void setData(Integer data) {
        ....
      }
    }
    
    

    三、 集合容器

    3.1> List

    • ArrayList 源码解析
    • LinkedList源码解析

    3.2> Map

    • HashMap 源码解析(jdk8 底层用的是数组+链表+红黑树)

      源码主要关注4大点:

      1> 确定哈希桶数组索引的位置

      HashMap.hash() ——> hashCode()

      2> 插入数据

      HashMap.put()

      3> 扩容机制

      resize()

      4> 红黑树

      treeify()

    相关文章

      网友评论

          本文标题:反射泛型容器

          本文链接:https://www.haomeiwen.com/subject/tuafyltx.html