zoukankan      html  css  js  c++  java
  • Java反射探索研究(转)

             林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankakay

              摘要:本文详细深入讲解是Java中反射的机制,并介绍了如何通过反射来生成对象、调用函数、取得字段、设置字段的方法。最后,给出了一些反射常用到的实例。

    一、反射

    (1)概念

       反射含义:可以获取正在运行的Java对象。
    (2)功能
            1)在运行时判断任意一个对象所属的类
            2)在运行时构造任意一个类的对象
            3) 在运行时判断任意一个类所具有的成员变量和方法
           4)在运行时调用任意一个对象的方法
    (3)实现Java反射的类
      1)Class:它表示正在运行的Java应用程序中的类和接口
      2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
      3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
      4)Method:提供关于类或接口中某个方法信息
      注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现

    (4)取得class的三种方法

    [java] view plain copy
     
    1. Dog dog = new Dog();                   
    2.  Class<?> dogClass = dog.getClass();  
    3.  Class<?> dogClass1 = Dog.class;  
    4.  Class<?> dogClass2 = Class.forName("com.lin.Dog");//注意要添加异常抛出  

    (5)关键方法

    方法关键字

    含义

    getDeclaredMethods()

    获取所有的方法

    getReturnType()

    获得方法的放回类型

    getParameterTypes()

    获得方法的传入参数类型

    getDeclaredMethod("方法名",参数类型.class,……)

    获得特定的方法

    构造方法关键字

    含义

    getDeclaredConstructors()

    获取所有的构造方法

    getDeclaredConstructor(参数类型.class,……)

    获取特定的构造方法

    父类和父接口

    含义

    getSuperclass()

    获取某类的父类

    getInterfaces()

    获取某类实现的接口

    (6)一些区别函数

    public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。

    public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。

    getFields()获得某个类的所有的公共(public)的字段,包括父类。 

    getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,
    但是不包括父类的申明字段。 

    下面来看一个例子说明:

    动物接口

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. public interface Aminal {  
    4.       
    5.     public String eat(String obj);  
    6.       
    7.     public int run(int obj);  
    8.   
    9. }  


    实现类:

    [java] view plain copy
     
    1. <pre name="code" class="java">package com.lin;  
    2.   
    3. import java.util.jar.Attributes.Name;  
    4.   
    5. public class Dog implements Aminal {  
    6.       
    7.     private String name;  
    8.       
    9.     private int age;  
    10.       
    11.     public Dog() {  
    12.         // TODO 自动生成的构造函数存根  
    13.     }  
    14.       
    15.     public Dog(String name,int age) {  
    16.         this.name = name;  
    17.         this.age = age;  
    18.     }     
    19.       
    20.     public Dog(String name) {  
    21.         this.name = name;  
    22.         this.age = 10;  
    23.     }  
    24.       
    25.     private void sleep(int x) {  
    26.         System.out.println(name + "睡觉" + x + "分钟");  
    27.     }  
    28.       
    29.     public String getName() {  
    30.         return name;  
    31.     }  
    32.   
    33.     public void setName(String name) {  
    34.         this.name = name;  
    35.     }  
    36.   
    37.     public int getAge() {  
    38.         return age;  
    39.     }  
    40.   
    41.     public void setAge(int age) {  
    42.         this.age = age;  
    43.     }  
    44.   
    45.     @Override  
    46.     public String eat(String obj) {  
    47.         System.out.println(name + "吃"+ obj);  
    48.         return null;  
    49.     }  
    50.   
    51.     @Override  
    52.     public int run(int obj) {  
    53.         System.out.println("跑,速度:"+ obj);  
    54.         return 0;  
    55.     }  
    56.       
    57.     @Override  
    58.     public String toString() {  
    59.         return "狗名:" + name + "  狗的年纪:" + age;  
    60.     }  
    61.       
    62.     private static void play() {  
    63.         System.out.println("狗狗自己玩啊玩");  
    64.     }  
    65. }  
    66. </pre><br>  

    来看看各自的调用:

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.lang.reflect.Method;  
    4.   
    5. public class ReflectLearning {  
    6.   
    7.     public static void main(String[] args) throws ClassNotFoundException {  
    8.         Dog dog = new Dog();          
    9.          System.out.println(dog.getClass());   
    10.          System.out.println(dog.getClass().getName());   
    11.            
    12.          Class<?> dogClass = dog.getClass();  
    13.          Class<?> dogClass1 = Dog.class;  
    14.          Class<?> dogClass2 = Class.forName("com.lin.Dog");  
    15.            
    16.          Method[] methods1 = dogClass.getMethods();  
    17.          System.out.println("====================通过getMethods取得方法开始====================");  
    18.          for (Method method : methods1) {  
    19.              System.out.println(method);   
    20.         }  
    21.          System.out.println("====================通过getMethods取得方法结束====================");  
    22.            
    23.            
    24.          Method[] methods2 = dogClass.getDeclaredMethods();  
    25.          System.out.println("====================通过getDeclaredMethods取得方法开始====================");  
    26.          for (Method method : methods2) {  
    27.              System.out.println(method);   
    28.         }  
    29.          System.out.println("====================通过getDeclaredMethods取得方法结束====================");  
    30.   
    31.   
    32.   
    33.     }  
    34.       
    35.   
    36. }  


    来看下结果:

    getMethods方法

    getDeclareMethos方法:

    从上面可以看出getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。

    二、通过反射调用构造函数

    (1)、列出所有的构造函数:

    [java] view plain copy
     
    1. Constructor<?>[] constructors = dogClass.getConstructors();  
    2.   
    3. System.out.println("====================列出所有的构造函数结束====================");  
    4. for (Constructor<?> constructor : constructors) {           
    5.  System.out.println(constructor);  
    6. }  
    7. System.out.println("====================列出所有的构造函数结束====================");  

    输出结果:

    (2)、通过反射生成对象

    [java] view plain copy
     
    1. System.out.println("====================通过newInstance()来生成对象,一定在有默认构造函数====================");  
    2. Dog dog1 = (Dog) dogClass.newInstance();  
    3. dog1.setName("狗狗1号");  
    4. dog1.setAge(7);  
    5. System.out.println(dog1);  
    6.   
    7. System.out.println("====================通过newInstance(参数)方法一来生成对象====================");  
    8. Dog dog2 = (Dog)constructors[0].newInstance("狗狗2号");  
    9. System.out.println(dog2);  
    10.   
    11. System.out.println("====================通过newInstance(参数)方法二来生成对象====================");  
    12. Constructor con1 = dogClass.getConstructor(new  Class[]{String.class,int.class});     //主要就是这句了  
    13. Dog dog3 = (Dog) con1.newInstance(new Object[]{"狗狗3号",14});  
    14. System.out.println(dog3);  

    输出结果:

    从上面可以看出,先通过getConstructor(new  Class[]{xxxx.class,yyy.class}),再通过con1.newInstance(new Object[]{"xxxxx",...});的方式是最灵活的,可以自动根据输入的参数类型和个数,找到对应的构造函数来调用。第二种方法需要得到构造函数的数组,并且需要知道对应哪一个构造函数。第一种就只能调用无参构造函数。

    三、通过反射调用普通函数、静态函数

    (1)取得函数的一些基本信息

    [java] view plain copy
     
    1. Class<?> dogClass = Dog.class;  
    2. Method[] methods = dogClass.getDeclaredMethods();  
    3. for (Method method : methods) {  
    4.     System.out.println("函数名:"+method.getName() +"        函数类型:"+ method.getModifiers() + "         函数返回: "+ method.getReturnType() + "        函数参数个数:" + method.getParameterCount());  
    5.       
    6. }  

    输出结果:

    其中函数类型对应表如下:
    PUBLIC: 1
    PRIVATE: 2
    PROTECTED: 4
    STATIC: 8
    FINAL: 16
    SYNCHRONIZED: 32
    VOLATILE: 64
    TRANSIENT: 128
    NATIVE: 256
    INTERFACE: 512
    ABSTRACT: 1024
    STRICT: 2048

    (2)方法调用

    这是当前狗类的方法:

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.util.jar.Attributes.Name;  
    4.   
    5. public class Dog implements Aminal {  
    6.       
    7.     private String name;  
    8.       
    9.     private int age;  
    10.       
    11.     public Dog() {  
    12.         // TODO 自动生成的构造函数存根  
    13.     }  
    14.       
    15.     public Dog(String name,int age) {  
    16.         this.name = name;  
    17.         this.age = age;  
    18.     }     
    19.       
    20.     public Dog(String name) {  
    21.         this.name = name;  
    22.         this.age = 10;  
    23.     }  
    24.       
    25.     private void sleep(int x) {  
    26.         System.out.println(name + "睡觉" + x + "分钟");  
    27.     }  
    28.       
    29.     public String getName() {  
    30.         return name;  
    31.     }  
    32.   
    33.     public void setName(String name) {  
    34.         this.name = name;  
    35.     }  
    36.   
    37.     public int getAge() {  
    38.         return age;  
    39.     }  
    40.   
    41.     public void setAge(int age) {  
    42.         this.age = age;  
    43.     }  
    44.   
    45.     @Override  
    46.     public String eat(String obj) {  
    47.         System.out.println(name + "吃"+ obj);  
    48.         return null;  
    49.     }  
    50.   
    51.     @Override  
    52.     public int run(int obj) {  
    53.         System.out.println("跑,速度:"+ obj);  
    54.         return 0;  
    55.     }  
    56.       
    57.     @Override  
    58.     public String toString() {  
    59.         return "狗名:" + name + "  狗的年纪:" + age;  
    60.     }  
    61.       
    62.     private static void play() {  
    63.         System.out.println("狗狗自己玩啊玩");  
    64.     }  
    65.       
    66.       
    67.   
    68. }  


    不同方法的调用过程:

    [java] view plain copy
     
    1. //调用私有方法  
    2. Method method1 = dogClass.getDeclaredMethod("sleep", int.class);//不要用getMethod,它只能取到public方法  
    3. Dog dog1 = (Dog) dogClass.getConstructor(new Class[] {String.class}).newInstance(new Object[]{"狗狗1号"});  
    4. method1.setAccessible(true);//私有方法一定要加这句  
    5. method1.invoke(dog1, 12);  
    6.   
    7. //调用私有静态方法  
    8.               Method method2 = dogClass.getDeclaredMethod("play");//不要用getMethod,它只能取到public方法   
    9.               method2.setAccessible(true);//私有方法一定要加这句  
    10.              method2.invoke(dogClass.newInstance());   
    11.         
    12.              //调用公共方法  
    13. Method method3 = dogClass.getMethod("eat", String.class);//这里也可以用getDeclaredMethod  
    14. Dog dog3 = new Dog("狗狗3号", 45);  
    15. method3.invoke(dog3, "苹果~");  


    输出结果:

    方法调用这里一定要记住getMethod和getDeclaredMethod的区别,并且在调用私有的方法之前一定要加setAccessible(true)这一句,要不会报错!

    四、通过反射取得字段、设置字段值

    (1)怎么通过反射获取类的属性
    a)Class.getDeclaredField(String name);
    返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
    b)Class.getDeclaredFields();
    返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
    c)Class.getField(String name);
    返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
    d)Class.getField();
    返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

    (2)进行属性获取更改

    [java] view plain copy
     
    1. Dog dog1 = new Dog("狗狗1号", 12);  
    2. System.out.println(dog1);  
    3.   
    4. Class<?> dogClass = dog1.getClass();  
    5. Field field1 = dogClass.getDeclaredField("name");//注意,getField只能取得public的字段  
    6. field1.setAccessible(true);//私有变量必须先设置Accessible为true  
    7.    System.out.println("原本狗名:" + field1.get(dog1));  
    8.   
    9. field1.set(dog1,"狗狗2号");  
    10.   
    11. System.out.println(dog1);     


    输出结果:

    值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。

    五、反射常用工具类

    (1)bean复制工具

    这里可以使用commons-beanutils中的copyProperties()方法,自己写是为了加深对反射的理解。

    1、toString的基类

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.lang.reflect.Field;  
    4. import java.text.SimpleDateFormat;  
    5. import java.util.Date;  
    6.   
    7. /** 
    8.  * bean基類 
    9.  * @author lin 
    10.  * 
    11.  */  
    12. public class BaseBean {  
    13.   
    14.     public String toString() {   
    15.       StringBuffer sb = new StringBuffer();    
    16.       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    
    17.       Class<?> cls = this.getClass();  
    18.       Field[] fields = cls.getDeclaredFields();  
    19.       sb.append(cls.getName() + "{");  
    20.       for (Field field : fields) {  
    21.            try {    
    22.           field.setAccessible(true);    
    23.           sb.append(field.getName());    
    24.           sb.append("=");    
    25.           sb.append(field.get(this));    
    26.           sb.append(" ");    
    27.       } catch (Exception e) {    
    28.           e.printStackTrace();    
    29.       }   
    30.       }  
    31.       sb.append("}");  
    32.       return sb.toString();  
    33.     }  
    34. }  


    2、bean复制工具

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.lang.reflect.Field;  
    4. import java.lang.reflect.InvocationTargetException;  
    5. import java.lang.reflect.Method;  
    6.   
    7. /** 
    8.  * 将一个JavaBean风格对象的属性值拷贝到另一个对象的同名属性中 (如果不存在同名属性的就不拷贝) 
    9.  **/  
    10.   
    11. public class BeanCopy {  
    12.     private static String GET = "get";  
    13.     private static String SET = "set";  
    14.       
    15.     /** 
    16.      *  
    17.      * @param source 
    18.      * @param target 
    19.      * @throws Exception 
    20.      */  
    21.     public static void copy(Object source,Object target){  
    22.         Class<?> sourceClz = source.getClass();  
    23.         Class<?> targetClz = target.getClass();  
    24.         // 得到Class对象所表征的类的所有属性(包括私有属性)  
    25.         Field[] sourceFields = sourceClz.getDeclaredFields();  
    26.         if (sourceFields.length == 0) {  
    27.             sourceFields = sourceClz.getSuperclass().getDeclaredFields();  
    28.         }  
    29.           
    30.         int len = sourceFields.length;  
    31.         for (int i = 0; i < len; i++) {  
    32.             String fieldName = sourceFields[i].getName();  
    33.             Field targetField = null;  
    34.             // 得到targetClz对象所表征的类的名为fieldName的属性,不存在就进入下次循环  
    35.             try {  
    36.                 targetField = targetClz.getDeclaredField(fieldName);  
    37.             } catch (NoSuchFieldException e) {  
    38.                 try {  
    39.                     targetField = targetClz.getSuperclass().getDeclaredField(fieldName);  
    40.                 } catch (NoSuchFieldException e1) {  
    41.                     e1.printStackTrace();  
    42.                 } catch (SecurityException e1) {  
    43.                     e1.printStackTrace();  
    44.                 }  
    45.             }  
    46.               
    47.             if (targetField == null) {  
    48.                 continue;  
    49.             }  
    50.               
    51.             // 判断sourceClz字段类型和targetClz同名字段类型是否相同  
    52.             if (sourceFields[i].getType() == targetField.getType()) {  
    53.                 // 由属性名字得到对应get和set方法的名字  
    54.                 String getMethodName = GET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);  
    55.                 String setMethodName = SET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);  
    56.                 // 由方法的名字得到get和set方法的Method对象  
    57.                 Method getMethod;  
    58.                 Method setMethod;  
    59.                 try {  
    60.                     try {  
    61.                         getMethod = sourceClz.getDeclaredMethod(getMethodName,new Class[] {});//get方法入參為空  
    62.                     } catch (NoSuchMethodException e) {  
    63.                         getMethod = sourceClz.getSuperclass().getDeclaredMethod(getMethodName,new Class[] {});  
    64.                     }  
    65.                     try {  
    66.                         setMethod = targetClz.getDeclaredMethod(setMethodName,sourceFields[i].getType());//set方法入參不為空  
    67.   
    68.                     } catch (NoSuchMethodException e) {  
    69.                         setMethod = targetClz.getSuperclass().getDeclaredMethod(setMethodName,sourceFields[i].getType());  
    70.                     }  
    71.                     // 调用source对象的getMethod方法  
    72.                     Object result = getMethod.invoke(source, new Object[] {});  
    73.                     // 调用target对象的setMethod方法  
    74.                     setMethod.invoke(target, result);  
    75.   
    76.                 } catch (SecurityException e) {  
    77.                     e.printStackTrace();  
    78.   
    79.                 } catch (NoSuchMethodException e) {  
    80.                     e.printStackTrace();  
    81.   
    82.                 } catch (IllegalArgumentException e) {  
    83.                     e.printStackTrace();  
    84.   
    85.                 } catch (IllegalAccessException e) {  
    86.                     e.printStackTrace();  
    87.   
    88.                 } catch (InvocationTargetException e) {  
    89.                     e.printStackTrace();  
    90.   
    91.                 }  
    92.             } else {  
    93.                 continue;  
    94.   
    95.             }  
    96.   
    97.         }  
    98.   
    99.     }  
    100.   
    101. }  

    使用:

    新建两个类:

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.util.Date;  
    4.   
    5. public class Car extends BaseBean{  
    6.       
    7.     private String name;  
    8.       
    9.     private String id;  
    10.        
    11.     private Boolean sellFlag;  
    12.       
    13.     private int age;  
    14.       
    15.     private double maxSpeed;  
    16.       
    17.     private double minSpeed;  
    18.       
    19.     private int driverPeople;  
    20.       
    21.     private Date date;  
    22.   
    23.     public String getName() {  
    24.         return name;  
    25.     }  
    26.   
    27.     public void setName(String name) {  
    28.         this.name = name;  
    29.     }  
    30.   
    31.     public String getId() {  
    32.         return id;  
    33.     }  
    34.   
    35.     public void setId(String id) {  
    36.         this.id = id;  
    37.     }  
    38.   
    39.     public Boolean getSellFlag() {  
    40.         return sellFlag;  
    41.     }  
    42.   
    43.     public void setSellFlag(Boolean sellFlag) {  
    44.         this.sellFlag = sellFlag;  
    45.     }  
    46.   
    47.     public int getAge() {  
    48.         return age;  
    49.     }  
    50.   
    51.     public void setAge(int age) {  
    52.         this.age = age;  
    53.     }  
    54.   
    55.     public double getMaxSpeed() {  
    56.         return maxSpeed;  
    57.     }  
    58.   
    59.     public void setMaxSpeed(double maxSpeed) {  
    60.         this.maxSpeed = maxSpeed;  
    61.     }  
    62.   
    63.     public double getMinSpeed() {  
    64.         return minSpeed;  
    65.     }  
    66.   
    67.     public void setMinSpeed(double minSpeed) {  
    68.         this.minSpeed = minSpeed;  
    69.     }  
    70.   
    71.     public int getDriverPeople() {  
    72.         return driverPeople;  
    73.     }  
    74.   
    75.     public void setDriverPeople(int driverPeople) {  
    76.         this.driverPeople = driverPeople;  
    77.     }  
    78.   
    79.     public Date getDate() {  
    80.         return date;  
    81.     }  
    82.   
    83.     public void setDate(Date date) {  
    84.         this.date = date;  
    85.     }  
    86.       
    87.       
    88.       
    89.   
    90. }  


    另一个:

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.util.Date;  
    4.   
    5. public class Bus extends BaseBean{  
    6.     private String name;  
    7.       
    8.     private String id;  
    9.        
    10.     private Boolean sellFlag;  
    11.       
    12.     private int age;  
    13.       
    14.     private double maxSpeed;  
    15.       
    16.     private double minSpeed;  
    17.       
    18.     private long driverPeople;//和car類型不同  
    19.       
    20.     private int driverYear;//car沒有這個  
    21.       
    22.     private Date date;  
    23.   
    24.     public String getName() {  
    25.         return name;  
    26.     }  
    27.   
    28.     public void setName(String name) {  
    29.         this.name = name;  
    30.     }  
    31.   
    32.     public String getId() {  
    33.         return id;  
    34.     }  
    35.   
    36.     public void setId(String id) {  
    37.         this.id = id;  
    38.     }  
    39.   
    40.     public Boolean getSellFlag() {  
    41.         return sellFlag;  
    42.     }  
    43.   
    44.     public void setSellFlag(Boolean sellFlag) {  
    45.         this.sellFlag = sellFlag;  
    46.     }  
    47.   
    48.     public int getAge() {  
    49.         return age;  
    50.     }  
    51.   
    52.     public void setAge(int age) {  
    53.         this.age = age;  
    54.     }  
    55.   
    56.     public double getMaxSpeed() {  
    57.         return maxSpeed;  
    58.     }  
    59.   
    60.     public void setMaxSpeed(double maxSpeed) {  
    61.         this.maxSpeed = maxSpeed;  
    62.     }  
    63.   
    64.     public double getMinSpeed() {  
    65.         return minSpeed;  
    66.     }  
    67.   
    68.     public void setMinSpeed(double minSpeed) {  
    69.         this.minSpeed = minSpeed;  
    70.     }  
    71.   
    72.     public long getDriverPeople() {  
    73.         return driverPeople;  
    74.     }  
    75.   
    76.     public void setDriverPeople(long driverPeople) {  
    77.         this.driverPeople = driverPeople;  
    78.     }  
    79.   
    80.     public int getDriverYear() {  
    81.         return driverYear;  
    82.     }  
    83.   
    84.     public void setDriverYear(int driverYear) {  
    85.         this.driverYear = driverYear;  
    86.     }  
    87.   
    88.     public Date getDate() {  
    89.         return date;  
    90.     }  
    91.   
    92.     public void setDate(Date date) {  
    93.         this.date = date;  
    94.     }  
    95.       
    96.       
    97.   
    98. }  


    调用:

    [java] view plain copy
     
    1. public static void test5() {  
    2.     Car car = new Car();  
    3.     car.setAge(12);  
    4.     car.setDriverPeople(4);  
    5.     car.setId("YU1234");  
    6.     car.setMaxSpeed(13.66);  
    7.     car.setMinSpeed(1.09);  
    8.     car.setName("小车");  
    9.     car.setSellFlag(false);  
    10.     car.setDate(new Date());  
    11.       
    12.       
    13.     Bus bus = new Bus();  
    14.     BeanCopy.copy(car,bus);  
    15.     System.out.println(car);  
    16.     System.out.println(bus);  
    17.       
    18.       
    19. }  
    除了两个不同的字段外,其它的都复制过去了,这在DTO、VO、DOMAIN对象转换时经常用到。

    http://blog.csdn.net/evankaka/article/details/49978481

  • 相关阅读:
    Linux文本检索命令grep笔记
    Python中字典的相关操作
    Go 语言函数闭包
    Go 语言多维数组
    Go 错误处理
    Go 语言接口
    Go 语言类型转换
    Go 语言递归函数
    Go 语言Map(集合)
    Go 语言范围(Range)
  • 原文地址:https://www.cnblogs.com/softidea/p/5271809.html
Copyright © 2011-2022 走看看