JavaSE学习笔记27:反射机制(二)

反射机制(二)

Field

java.lang.reflect.Field 代表字节码中的属性字节码,代表类中的成员变量(包括静态变量、实例变量)

获取Field

package se6;
//反射属性Field
public class Student {
    //Field翻译为字段,其实就是属性/成员
    //4个Field,分别采用了不同的访问控制权限修饰符
    public int no;
    private String name;
    protected int age;
    boolean sex;
    public static final double MATH_PI = 3.1415926;
}
package se6;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
反射Student类当中所有的Field
 */
public class ReflectTest07 {
    public static void main(String[] args) throws Exception {

        //获取整个类
        Class studentClass = Class.forName("se6.Student");
        //获取完整类名
        String className = studentClass.getName();
        System.out.println("完整类名:" + className);//se6.Student
        //获取简类名
        String simleName = studentClass.getSimpleName();
        System.out.println("简类名:" + simleName);//Student
        System.out.println("=======================");

        //获取类中所有的public修饰的Field
        Field[] fields = studentClass.getFields();
        System.out.println(fields.length);//1
        //取出这个field
        Field f = fields[0];
        //取出field它的名字
        String fieldName = f.getName();
        System.out.println(fieldName);//no
        System.out.println("=======================");

        //获取所有的Field
        Field[] fs = studentClass.getDeclaredFields();
        System.out.println(fs.length);//5
        System.out.println("=======================");

        //遍历
        for (Field field : fs){
            //获取属性的修饰符列表
            int i = field.getModifiers();//返回的修饰符是一个数字,每个数字都是修饰符代号
            //System.out.println(i);
            //将代号转换成字符串
            String modifierString =  Modifier.toString(i);
            System.out.println(modifierString);

            //获取属性的类型
            Class fieldType = field.getType();
            //String fName = fieldType.getName();
            String fName = fieldType.getSimpleName();
            System.out.println(fName);
            //获取属性的名字
            System.out.println(field.getName());
            System.out.println("=======================");
            /**
             * public
             * int
             * no
             * =======================
             * private
             * String
             * name
             * =======================
             * protected
             * int
             * age
             * =======================
             *
             * boolean
             * sex
             * =======================
             * public static final
             * double
             * MATH_PI
             * =======================
             */
        }
    }
}

通过反射机制,反编译一个类的属性Field(了解即可)

package se6;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

//通过反射机制,反编译一个类的属性Field(了解即可)
public class ReflectTest08 {
    public static void main(String[] args) throws Exception {
        //创建这个是为了拼接字符串
        StringBuilder s = new StringBuilder();

        //Class studetClass = Class.forName("se6.Student");
        Class studetClass = Class.forName("java.lang.String");

        s.append(Modifier.toString(studetClass.getModifiers()) + "class" + studetClass.getSimpleName() + " {\n");

        Field[] fields = studetClass.getDeclaredFields();
        for (Field field : fields){
            s.append("\t");
            s.append(Modifier.toString(field.getModifiers()));
            s.append(" ");
            s.append(field.getType().getSimpleName());
            s.append(" ");
            s.append(field.getName());
            s.append(";\n");
        }
        s.append("}");
        System.out.println(s);
        /**
         * public finalclassString {
         *     private final char[] value;
         *     private int hash;
         *     private static final long serialVersionUID;
         *     private static final ObjectStreamField[] serialPersistentFields;
         *     public static final Comparator CASE_INSENSITIVE_ORDER;
         * }
         */
    }
}

通过反射机制访问一个java对象的属性(重点)

package se6;
//反射属性Field
public class Student {
    //Field翻译为字段,其实就是属性/成员
    //4个Field,分别采用了不同的访问控制权限修饰符
    public int no;
    private String name;
    protected int age;
    boolean sex;
    public static final double MATH_PI = 3.1415926;
}
package se6;

import java.lang.reflect.Field;

/*
如何通过反射机制访问一个java对象的属性?(重点)
    给属性赋值
    获取属性的值
 */
public class ReflectTest09 {
    public static void main(String[] args) throws Exception {

        //不使用反射机制访问对象的属性
        Student s = new Student();
        //给属性赋值
        s.no = 1111;    /*
                         三要素:给s对象的no属性赋值1111
                          1.对象s
                          2.no属性
                          3.1111
                        */
        //读属性值
        System.out.println(s.no);

        //使用反射机制访问对象的属性
        Class studentClass = Class.forName("se6.Student");
        Object obj = studentClass.newInstance();//obj就是Student对象,底层调用无参数构造方法实例化对象

        //获取no属性(根据属性的名称来获取Field)
        Field noField = studentClass.getDeclaredField("no");

        //给obj对象(Student对象)的no属性赋值
        /*
        虽然使用了反射机制,但是三要素还是缺一不可:
            1.obj对象
            2.no属性
            3.001值
        注意:反射机制让代码复杂了,但是为了灵活,也是值得的
         */
        noField.set(obj,1);//给obj对象的no属性赋值1

        //读取属性的值
        //两个要素:获取Obj对象的no属性的值
        System.out.println(noField.get(obj));

        //可以访问私有的属性吗?
        Field nameField = studentClass.getDeclaredField("name");
        //打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会)
        //这样设置完之后,在外部也是可以访问private的
        nameField.setAccessible(true);
        //给name属性赋值
        nameField.set(obj,"阿波");
        //获取name属性的值
        System.out.println(nameField.get(obj));
    }
}

可变长参数

int...args
语法是:类型...(注意:一定是3个点)

  1. 可变长度参数要求的参数个数是:0~N个
  2. 可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个
  3. 可变长度参数可以当做一个数组来看待
package se6.bean;

public class ArgsTest {
    public static void main(String[] args) {
        
        m();
        m(10);
        m(10,20);
        //m("abc");编译报错
        
        m2(100);
        m2(200,"abc");
        m2(200,"abc","def");
        m2(200,"abc","def","xyz");
        
        m3("ab","de","kk","ff");
        
        String[] strs = {"a","b","c"};
        //可以传一个数组
        m3(strs);
        //直接传一个数组
        m3(new String[]{"最","爱","琴","女","E"});//没必要,可以直接如下一行代码即可
        m3("最","爱","琴","女","E");
        
    }
    public static void m(int...args){
        System.out.println("m方法执行了!");
    }
    //public static void m2(String...args,int...args2){}报错
    //必须在最后,只能有1个
    public static void m2(int a,String...args1){}
    
    public static void m3(String...args){
        //args有length属性,说明args是一个数组
        //可以将可变长度参数当做一个数组来看
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }
}

Method

java.lang.reflect.Method 代表字节码中的方法字节码,代表类中的方法

反射Method

package se6.service;
/*
用户业务类
 */
public class UserService {
    /**
     * 登录方法
     * @param name 用户名
     * @param password 密码
     * @return true表示登录成功,false表示登录失败。
     */
    public boolean login(String name,String password){
        if ("admin".equals(name) && "123".equals(password)){
            return true;
        }
        return false;
    }
    /**
     * 退出系统的方法
     */
    public void logut(){
        System.out.println("系统已经安全退出!");
    }
}
package se6;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
作为了解内容:反射Method
(不需要掌握)
 */
public class ReflectTest10 {
    public static void main(String[] args) throws Exception {
        //获取类
        Class userServiceClass = Class.forName("se6.service.UserService");
        //获取所有的Method(包括私有的)
        Method[] methods = userServiceClass.getDeclaredMethods();
        System.out.println(methods.length);//2
        System.out.println("==================================");

        //遍历Method
        for (Method method : methods){
            //获取修饰符列表
            System.out.println(Modifier.toString(method.getModifiers()));
            //获取方法的返回值类型
            System.out.println(method.getReturnType().getSimpleName());
            //获取方法名
            System.out.println(method.getName());

            //方法的修饰符列表(一个方法的参数可能会有多个)
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType : parameterTypes){
                System.out.println(parameterType.getSimpleName());
            }
        }
    }
}

反编译

package se6;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
了解,不需要掌握
反编译一个类的方法
 */
public class ReflectTest11 {
    public static void main(String[] args) throws Exception {

        StringBuilder s = new StringBuilder();
        Class userServiceClass = Class.forName("se6.service.UserService");

        s.append(Modifier.toString(userServiceClass.getModifiers()) + "class" + userServiceClass.getSimpleName() + "{\n");

        Method[] methods = userServiceClass.getDeclaredMethods();
        for (Method method : methods){
            //public boolean login(String name.String password){}
            s.append("\t");
            s.append(Modifier.toString(method.getModifiers()));
            s.append(" ");
            s.append(method.getReturnType().getSimpleName());
            s.append(" ");
            s.append(method.getName());
            s.append("(");
            //参数列表
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType : parameterTypes){
                s.append(parameterType.getSimpleName());
                s.append(",");
            }
            //删除指定下标位置上的字符
            s.deleteCharAt(s.length() - 1);
            s.append("){}\n");
        }
        s.append("}");
        System.out.println(s);
    }
}

通过反射机制调用对象的方法

重点:通过反射机制调用对象的方法
反射机制让代码具有通用性,可变化的内容都是写到配置文件当中,
将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,
但是java代码不需要做任何改动,这就是反射机制的魅力。

package se6;

import se6.service.UserService;

import java.lang.reflect.Method;

public class ReflectTest12 {
    public static void main(String[] args) throws Exception {
        //不使用反射机制,怎么调用方法
        UserService userService = new UserService();
        //调用方法
        /*
        要素分析:
            1.对象userService
            2.login方法名
            3.实际参数列表
            4.返回值
         */
        boolean loginSuccess = userService.login("admin","123");
        System.out.println(loginSuccess ? "登录成功" : "登录失败");

        //使用反射机制调用对象的方法
        Class userServiceClass = Class.forName("se6.service.UserService");
        //创建对象
        Object obj = userServiceClass.newInstance();
        //获取Method(方法)
        Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);
        //调用方法
        //invoke(调用)
        //反射机制中最重要的一个方法,必须记住
        /*
        4要素
            1.loginMethod 方法
            2。Obj 对象
            3。"admin","123" 实参
            4.retValue 返回值
         */
        Object retValue = loginMethod.invoke(obj,"admin","123");
        System.out.println(retValue);//true
    }
}

Constructor

java.lang.reflect.Constructor 代表字节码中的构造方法字节码,代表类中的构造方法

反编译一个类的Constructor(构造方法)

package se6;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class ReflectTest13 {
    public static void main(String[] args) throws Exception {

        StringBuilder s = new StringBuilder();

        Class vipClass = Class.forName("se6.bean.Vip");
        s.append(Modifier.toString(vipClass.getModifiers()));
        s.append(" class ");
        s.append(vipClass.getSimpleName());
        s.append("{\n");

        //拼接构造方法
        Constructor[] constructors = vipClass.getDeclaredConstructors();
        for (Constructor constructor : constructors){
            s.append("\t");
            s.append(Modifier.toString(constructor.getModifiers()));
            s.append(" ");
            s.append(vipClass.getSimpleName());
            s.append("(");
            //拼接参数
           Class[] parameterTypes = constructor.getParameterTypes();
           for (Class parameterType : parameterTypes){
               s.append(parameterType.getSimpleName());
               s.append(",");
           }
           //删除最后下标位置上的字符
            if(parameterTypes.length > 0){
                s.deleteCharAt(s.length() - 1);
            }
           s.append("){}\n");
        }
        s.append("}");
        System.out.println(s);
        /**
         * public class Vip{
         *     public Vip(int,String,String,boolean){}
         *     public Vip(int,String,String){}
         *     public Vip(int,String){}
         *     public Vip(int){}
         *     public Vip(){}
         * }
         */
    }
}

通过反射机制调用构造方法实例化java对象

package se6.bean;

public class Vip {

    int no;
    String name;
    String birth;
    boolean sex;

    public Vip() {}
    public Vip(int no) {
        this.no = no;
    }
    public Vip(int no, String name) {
        this.no = no;
        this.name = name;
    }
    public Vip(int no, String name, String birth) {
        this.no = no;
        this.name = name;
        this.birth = birth;
    }
    public Vip(int no, String name, String birth, boolean sex) {
        this.no = no;
        this.name = name;
        this.birth = birth;
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Vip{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", birth='" + birth + '\'' +
                ", sex=" + sex +
                '}';
    }
}
package se6;

import se6.bean.Vip;

import java.lang.reflect.Constructor;
/*
通过反射机制调用构造方法实例化java对象
 */
public class ReflectTest14 {
    public static void main(String[] args) throws Exception {
        //不使用反射机制怎么创建对象
        Vip v1 = new Vip();
        Vip v2 = new Vip(110,"张三","2001-10-11",true);

        //使用反射机制创建对象
        Class c = Class.forName("se6.bean.Vip");
        //调用无参数的构造方法
        Object obj = c.newInstance();
        System.out.println(obj);
        //Vip{no=0, name='null', birth='null', sex=false}

        //调用有参数的构造方法
        //第一步:先获取到这个有参数的构造方法
        Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
        //第二步:调用构造方法new对象
        Object obj2 = con.newInstance(111,"李四","1990-10-11",true);
        System.out.println(obj2);
        //Vip{no=111, name='李四', birth='1990-10-11', sex=true}

        //获取无参数构造方法
        Constructor con2 = c.getDeclaredConstructor();
        Object obj3 = con2.newInstance();
        System.out.println(obj3);
        //Vip{no=0, name='null', birth='null', sex=false}
    }
}

获取这个类的父类、实现的接口

package se6;
/*
重点:给一个类,如何获取这个类的父类,已经实现了哪些接口?
 */
public class ReflectTest15 {
    public static void main(String[] args) throws Exception {
        //String举例
        Class stringClass = Class.forName("java.lang.String");

        //获取String的父类
        Class superClass = stringClass.getSuperclass();
        System.out.println(superClass);//class java.lang.Object

        //获取String类实现的所有接口(一个类可以实现多个接口)
        Class[] interfaces = stringClass.getInterfaces();
        for (Class in : interfaces) {
            System.out.println(in.getName());
        }
        /*
        java.io.Serializable
        java.lang.Comparable
        java.lang.CharSequence
        */
    }
}
posted @ 2020-12-01 16:45  最爱琴女E  阅读(138)  评论(0)    收藏  举报