反射机制

package OneDay;

/**
 * 1、反射机制有什么用?
 *      通过java语言中的反射机制可以操作字节码文件
 *          优点类似于黑客(可以读和修改字节码文件)
 * 2、反射机制相关类:java.lang.reflect.*;
 * 3、相关类:(较重要)
 *      java.lang.Class;  代表字节码文件,代表一个类型   代表整个类
 *      java.lang.reflect.Method 代表字节码中的方法字节码   类中的方法
 *      java.lang.reflect.Constructor 代表字节码中的构造方法字节码   类中的构造方法
 *      java.lang.reflect.Field  代表字节码中的属性字节码    类中的成员变量(静态变量,实例变量)
 *      java.lang.Class{
 *          public class User{
 *              //Field
 *              int No;
 *
 *              //Constructor
 *              public user(){
 *
 *              }
 *
 *              //Method
 *              public void setNo(int aa){
 *
 *              }
 *              public int getNo(){
 *                  return No;
 *              }
 *          }
 *
 *      }
 *
 *  4、关于JDK中自带的类加载器:
 *      1、什么是类加载器?
 *        专门负责加载类的命令/工具
 *      2、JDK中自带了3个加载器:
 *         启动类加载器
 *         扩展类加载器
 *         应用类加载器
 *
 *      3.假设有这样一段代码:String s = "abc"
 *      代码在开始执行前,会将所需要类全部加载到JVM当中,通过类加载器加载,看到以上代码类加载器会找String.class
 *      文件,找到就加载,怎么进行加载?
 *          通过“启动类加载器”加载,启动类加载器专门加载:/jre/lib/rt.jar的文件
 *          rt.jar是JDK最核心的类库
 *
 *          如果通过“启动类加载器”加载不到的时候,会通过“扩展类加载器”进行加载
 *          /jre/lib/ext/*.jar
 *
 *          如果“扩展类加载器”没有加载到,会通过“应用类加载器”加载
 *            专门加载:classpath中的类
 *
 *       java中为了保证类加载的安全,使用了双亲委派机制,优先从启动类加载器中加载,这个称为“父”
 *       “父”无法加载到,再从扩展类加载器中加载,这个称为“母”,双亲委派,如果都加载不到,才会考虑从
 *       应用类加载器中加载,直到加载到为止。
 *
 */
public class Note01 {
}

package OneDay;

import java.util.Date;

/*
* 要操作一个类的字节码,首先获取这个类的字节码,怎么获得java.lang.Class实例?
*   三种方式:
*       1、Class c = Class.forName("完整的类名");
*       2、Class c = 对象.getClass();
*       3、Class c = 任何类型.class;
* */
public class ReflectTest01 {
    public static void main(String[] args) {

       /*
       * Class.forName()
       *    1、静态方法
       *    2、方法的参数是一个字符串
       *    3、字符串需要的是一个完整类名
       *    4、完整类名必须要带有包名:java.lang包不能省略
       * */
        Class c = null;
        Class d = null;
        try {
            c = Class.forName("java.lang.String");
            d = Class.forName("java.util.Date");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //java中任何一个对象都有一个方法:getClass()
        String s = "abc";
        Class ss = s.getClass();//ss代表String.class字节码文件,ss代表String类型
        System.out.println(c == ss);

        Date time = new Date();
//        Class y = time.getClass();
        Class y = new Date().getClass();
        System.out.println(d == y);

       //第三种方式,java语言中任何一种类型,包括基本数据类型,都有.class属性
        Class s01 = String.class;
        Class s02 = Date.class;
        Class s03 = int.class;
        Class s04 = double.class;
        System.out.println(ss == s01);

    }

}

package OneDay;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

/*
* 验证反射机制的灵活性:
*   java代码写了之后,在不改变java源代码的基础上,可以做到不同对象的实例化,只改配置文件就行,
*   非常之灵活,符合OCP原则,对扩展开放,对修改关闭
*
*   后期学期框架的时候,框架实现原理:都采用了反射机制,
*   所以,理解反射机制对以后剖析框架底层源代码有帮助
* */
public class ReflectTest02 {
    public static void main(String[] args) {

        //直接创建对象,但是这方式写死了,只能创建一个Student类型的对象
        Student student = new Student();
        System.out.println(student);

        FileReader reader = null;
        try {

            //通过反射机制,获取class,通过Class实例化对象
            Class c = Class.forName("OneDay.Student");//c代表student类型
            reader = new FileReader("src/myfile.properties");
            //创建属性类对象pro
            Properties properties = new Properties();//key,value都是String
            //加载
            properties.load(reader);

            //通过key来获取value
            String value = properties.getProperty("user");
            System.out.println("value: user = " + value);

            //通过反射机制实例化对象
            System.out.println("--------------------------------");
            Class d = Class.forName("OneDay.Student");
            Class cc = Class.forName(value);
            Object obj = cc.newInstance();
            System.out.println(obj);
            System.out.println("--------------------------------");

            //newInstance()这个方法会调用student类型的无参构造方法,完成对象的创建
            //注意:newInstance调用的是无参构造方法,必须保证无参构造方法是存在的
            Object obj01 = c.newInstance();
            System.out.println(obj01);

           /* 无参构造方法!!!!
            OneDay.Student@7ef20235
             --------------------------------
            Mon Dec 07 18:35:37 CST 2020
             --------------------------------
            无参构造方法!!!!
            OneDay.Student@1b2c6ec2
            */

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

package OneDay;

public class Student {
    public Student() {
        System.out.println("无参构造方法!!!!");
    }
}

========================

package TwoDay;

/**
 *  Class.forName()发生了什么?
 *      如果希望一个类的静态代码块执行,其他的代码一律不执行
 *      可以使用:
 *          Class.forName("完整类名")
 *          这个方法的执行会导致类加载,类加载时,静态代码块执行
 */
public class ClassForNameTest {
    public static void main(String[] args) {

        try {
            Class.forName("TwoDay.Student01");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}
class Student01{
    static {
        System.out.println("这里是静态代码块,静态代码块执行看!!!");
    }

}
package TwoDay;

import java.io.File;

/**
 * 研究一下文件路径的问题
 */
public class roadTest01 {
    public static void main(String[] args) {
        /**
         *  File reader = new File("myfile");
         *  这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的跟
         *  这个代码假设离开了IDEA,可能路径就不是project的根了,这是路径就无效了
         *
         *  注意:使用以下通用方式的前提是:这个文件必须在类路径下
         *      什么是类路径?在src下的都是类路径下,src是类的根路径
         *      (注意:在src下新建个包,在包里创建文件,也可以,不过得从src路径开始,如TwoDay/myfile02)
         *
         *  Thread.currentThread() 当前线程对象
         *  getContextClassLoader() 是线程对象的方法,可以获取当前线程的类加载器对象
         *  getResource()  获取资源,这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源
         *
         */


//        这种方式获取文件的路径是通用的,可以跨系统,如Linux系统(没有盘符),也是可以的
        String str = Thread.currentThread().getContextClassLoader().
                getResource("myfile").getPath();
        System.out.println(str);
//        /I:/project/java%e8%bf%9b%e9%98%b6/18.%e5%8f%8d%e5%b0%84/Test/out/test/Test/myfile

        String str02 = Thread.currentThread().getContextClassLoader().
                getResource("TwoDay/myfile02").getPath();
        System.out.println(str02);
///       I:/project/java%e8%bf%9b%e9%98%b6/18.%e5%8f%8d%e5%b0%84/Test/out/test/Test/TwoDay/myfile02

    }
}

package TwoDay;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class IoPropertiesTest {
    public static void main(String[] args) {

        //这里有问题,找不到文件,原来是中文的问题
      /* String path = Thread.currentThread().getContextClassLoader().
                getResource("TwoDay/myfile02").getPath();
        FileReader reader = null;*/

        InputStream reader = null;

        //返回一个流
        try {
            /*reader = new FileReader(path);*/
            reader = Thread.currentThread().getContextClassLoader().
                    getResourceAsStream("TwoDay/myfile02");
            Properties pro = new Properties();
            pro.load(reader);
            System.out.println(pro.getProperty("vip02"));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

=====================================

package ThreeDay;


import java.util.ResourceBundle;

/**
 * java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容
 * 使用以下这种方式的时候,属性配置文件***.properties必须放到类路径下(以src为起点)
 *      注意:这种方式相当于取代了IO+properties
 */

public class ResourceBundleTest {
    public static void main(String[] args) {
        //资源绑定器,只能绑定***.properties文件,并且这个文件必须在类路径下,文件拓展名也必须是properties
        //并且在写路径的时候,路径后面的扩展名不用写

        ResourceBundle boudle = ResourceBundle.getBundle("myfile");
        String str = boudle.getString("user");
        String str11 = boudle.getString("vip");
        System.out.println("user = " + str);
        System.out.println("vip = " + str11);

        ResourceBundle resourceBundle = ResourceBundle.getBundle("ThreeDay/three");
        String str01 = resourceBundle.getString("password");
        String str02 = resourceBundle.getString("user");
        System.out.println("password = " + str01);
        System.out.println("user = " + str02);

    }
}


==================================

package fourDay;

//通过反射机制,反编译一个类的属性field,给我一个class文件,我可以拿到你的源码
//的确很强大

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

public class FanBianYiTest {
    public static void main(String[] args) {
        //创建一个字符串拼接对象,使用于频繁拼接字符串时
        StringBuilder ss = new StringBuilder();

        try {
            Class student = Class.forName("java.lang.String");

            ss.append(Modifier.toString(student.getModifiers()) + " class " + student.getSimpleName() + "{\n");
            Field[] fields = student.getDeclaredFields();

            for (Field field : fields){
                ss.append("\t");
                ss.append(Modifier.toString(field.getModifiers()));
                ss.append(" ");
                ss.append(field.getType().getSimpleName());
                ss.append(" ");
                ss.append(field.getName());
                ss.append("\n");
            }
            ss.append("}");
            System.out.println(ss);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

}

package fourDay;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectTest {
    public static void main(String[] args) {

        //获取整个类
        //疑问:为什么不用File,用class呢,因为不方便,fileReader后,返回的一个flie文件
        //File主要使用来读文件的,class返回后可以获取名字,长度,还可以遍历里面的属性,修饰符
        try {

            FileReader aa = new FileReader("fourDay.Student");

            Class studentClass = Class.forName("fourDay.Student");

            String className = studentClass.getName();
            System.out.println(className);

            //获取类中所有public修饰的field
            Field[] files = studentClass.getFields();
            System.out.println("getFields.length测试数组中有几个元素:" + files.length);
            //取出这个Field
            Field file = files[0];
            //取出他的名字
            System.out.println(file.getName());

            //获取所有的Field
            Field[] fs = studentClass.getDeclaredFields();
            System.out.println("getDeclaredFields()获取的Field[]对象长度:" + fs.length);

            System.out.println("----------------");
            //遍历
            for(Field field : fs){
                //获取属性的类型名
                Class fieldTypes = field.getType();
                String fieldTypesName = fieldTypes.getName();
                System.out.println("属性的类型名:" + fieldTypesName);
                System.out.println("属性的类型名(简单实现):" + fieldTypes.getSimpleName());

                //获取属性的修饰符,返回的是一个数字,修饰符的代号
                int i = field.getModifiers();
                System.out.println("修饰符的代号 :" + i);
                String str = Modifier.toString(i);
                System.out.println("修饰符:" + str);

                 System.out.println(field.getName());

            }

        } catch (ClassNotFoundException | FileNotFoundException e) {
            e.printStackTrace();
        }

    }
}


package fourDay;

public class Student {
    protected int age;
    private String name;
    public String sex = "nan";
    boolean man ;
    public static final double PI = 3.122323;
}

============================

package five;

/**
 * 可变长度参数,int...args 可变长度参数,类型一定是三个点...
 * 1、参数个数是0-N个
 * 2、可变长度参数必须是最后一个,只能出现一个
 * 3、可变长度参数可以当做一个数组来看待
 */

public class ArgsTest {
    public static void main(String[] args) {

        m();

        s(12, "egtr", "sadvf");

        ss("aa", "abb", "afda");
        ss(new String[]{"ad", "ads", "asdf", "adf"});
        ss("发不发","绍飞表达式","是人更");
    }

    public static void m(int... args) {
        System.out.println("无参方法执行");
    }

    //可变长度参数必须是最后一个,只能出现一个
    /*public static void s(String...args,int...args){

    }*/

    public static void s(int i, String... args) {
        System.out.println("==============");
        System.out.println(i + args[0] + " " + args[1]);
        System.out.println(args);
        System.out.println("==============");
    }

    //可变长度参数可以当做一个数组来对待
    public static void ss(String... args) {
        for (int i = 0; i < args.length; i++) {
            System.out.print(args[i] + " ");
        }
    }

}

package five;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectConstructorCreate {
    public static void main(String[] args) {

        try {
            Class user = Class.forName("five.User");

            //构造方法创建无参的对象
            Object obj = user.newInstance();
            System.out.println("无参构造:" + obj);

            //创建有参的对象
            //先获得有参的构造方法
            Constructor constructor = user.getConstructor(String.class,int.class);
            Constructor constructor1 = user.getConstructor(String.class);
            Constructor constructor2 = user.getConstructor(String.class,int.class,double.class);
            Constructor constructor3 = user.getConstructor();

            //主要方法
            Object obj1 = constructor.newInstance("miao",123);
            Object obj2 = constructor1.newInstance("mmn");
            Object obj3 = constructor2.newInstance("mmm",132,123.9);
            Object obj4 = constructor3.newInstance();

            System.out.println(obj1);
            System.out.println(obj2);
            System.out.println(obj3);
            System.out.println(obj4);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }


    }
}

package five;

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

/**
 * 反射获取构造方法.
 */
public class ReflectConstructorTest {
    public static void main(String[] args) {

        try {
            //获取字节码类
            Class user = Class.forName("five.User");

            //获取构造方法
            Constructor[] constructors = user.getConstructors();
            for(Constructor constructor : constructors){
                StringBuilder ss = new StringBuilder();
                ss.append("\t");

                //修饰符
                ss.append(Modifier.toString(constructor.getModifiers()));
                ss.append(" ");

                //注意:构造方法没有数据类型,这里获取类名
                ss.append(user.getSimpleName());

                //形参
                ss.append("(");
                /**
                 *  注意这种方式是错误的
                 *  Parameter[] parameters = constructor.getParameters();
                 *  public User(arg0arg1arg2){}错误的输出
                 *  这种方式获取的是形参个数对上了,但形参类型没有输出
                 *
                 *  这种是正确的
                 *  Class[] parameters = constructor.getParameterTypes();
                 */
                Class[] parameters =  constructor.getParameterTypes();
                for( Class parameter : parameters){
                    ss.append(parameter.getSimpleName());
                    ss.append(",");
                }
                if(parameters.length > 0){
                    ss.deleteCharAt(ss.length() - 1);
                }
                ss.append("){\n}");
                System.out.println(ss);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

package five;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 重点:怎么通过反射机制调用一个对象的方法?
 *
 *   1、获取类名 Class.forName("");
 *   2、创建对象 .newInstance();
 *   3、获得方法 Method ff = user.getMethod("dengLu",String.class,int.class);
 *   4、调用方法 ff.invoke(obj,"miao",123);
 *   重点:::invoke方法调用
 *
 *      反射机制让代码更具有通用性,可变化的内容都是写到配置文件中
 *      将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了
 *      但是java代码不需要做任何改动
 *      但是现在还没有体会到
 *
 */

public class ReflectDiaoYongMethod {
    public static void main(String[] args) {

        try {
            //获取类名
            Class user = Class.forName("five.User");

            //创建对象
            Object obj = user.newInstance();

            //获取方法
            // 调用方法四要素:
            //方法,对象,实参,返回值

            Method userMethod = user.getMethod("dengLu", String.class,int.class);

            Object retValue = userMethod.invoke(obj,"miao",21);
            System.out.println(retValue);

//            master认证成功!!!欢迎回来!!

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}

package five;

//重点:给你一个类,怎么获取这个类的父类,已经实现了哪些接口?
public class ReflectFuLeiJieKou {
    public static void main(String[] args) {
        try {
            Class string = Class.forName("java.lang.String");
            Class stringParent = string.getSuperclass();

            System.out.println("获取String的父类 : " +  stringParent);

            Class[] inter = string.getInterfaces();
            System.out.println("获取string的接口:" + inter);
            for(Class jieKou : inter){
                System.out.println("遍历接口 :" + jieKou.getName());
            }
            /**
             * 获取String的父类 : class java.lang.Object
             * 获取string的接口:[Ljava.lang.Class;@7b23ec81
             * 遍历接口 :java.io.Serializable
             * 遍历接口 :java.lang.Comparable
             * 遍历接口 :java.lang.CharSequence
             * 遍历接口 :java.lang.constant.Constable
             * 遍历接口 :java.lang.constant.ConstantDesc
             */
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


    }
}

package five;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectMethodTest {
    public static void main(String[] args) {

        try {
            Class string = Class.forName("java.lang.String");

            //获取所有的方法Method(所有的方法包括私有的)
            Method[] methods = string.getMethods();
            System.out.println("String 方法的个数:" + methods.length);

            //遍历这些方法
            for (Method method : methods) {
                StringBuilder aa = new StringBuilder();
                //修饰符
                aa.append(Modifier.toString(method.getModifiers()));
                aa.append(" ");
                //返回值类型
                aa.append(method.getReturnType().getSimpleName());
                aa.append(" ");
                //方法名,这个没有SimpleName,方法没有简称
                aa.append(method.getName());

                //形参
                aa.append("(");
                Class[] parameterTypes = method.getParameterTypes();
                for (Class parameterType : parameterTypes){
                    aa.append(parameterType.getSimpleName());
                    aa.append(",");
                }
                if(parameterTypes.length > 0){
                   aa.deleteCharAt(aa.length() - 1);
                }
                aa.append(")");
                aa.append(" {\n}");

                System.out.println(aa);
            }
            /**
             * String 方法的个数:90
             * public boolean equals(Object) {
             * }
             * public int length() {
             * }
             * public String toString() {
             * }
             * public int hashCode() {
             * }
             * public void getChars(int,int,char[],int) {
             * }
             * public volatile int compareTo(Object) {
             * }
             */

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}



package five;

import java.lang.reflect.Field;

/**
 * 反射属性field
 *  怎么通过反射机制访问一个java对象的属性?
 *      给对象属性赋值
 *      获取对象属性
 *
 */
public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        //使用反射机制怎样访问一个对象的属性
        Class student = Class.forName("fourDay.Student");
        Object obj = student.newInstance();

        //obj就是Student对象(底层调用无参构造方法)

        //获取sex属性(根据属性的名称获取field)

        try {
            Field field = student.getDeclaredField("sex");

            //给Obj(student对象)的sex属性赋值,可以等同看做sex.set(obj,"nan") 个Obj的sex进行赋值,只是形式有些不是常规的
            field.set(obj,"nan");

            //获取Obj对象的age的值,这个地方为什么直接获取的是对象属性的值?而不是对象的内存地址?
            //答:这个是不是可以看做,sex.get(obj)  获取Obj对象的sex属性
            System.out.println(field.get(obj));



            /**
             * 注意修饰符,protected,private,默认访问不了
             * 打破封装就可以访问了
             *  缺点:打破封装,可能会给不法分子留下机会
             *
             */

            Field field1 = student.getDeclaredField("name");
            field1.setAccessible(true);
            Object obj1 = student.newInstance();
            field1.set(obj1,"miao");
            System.out.println(field1.get(obj1));

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }

}

package five;

public class User {
    private String name;
    private int age;
    private double balance;

    public User(String name) {
        this.name = name;
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User(String name, int age, double balance) {
        this.name = name;
        this.age = age;
        this.balance = balance;
    }

    public User() {
    }

    public String dengLu(String name,int age){
        if(name.equals("miao") && age == 21){
           return "master认证成功!!!欢迎回来!!";

        }
        return "master认证失败";
    }

    @Override
    public String toString() {
        return "  name:" + name +
                "  age:" + age +
                " balance:" + balance;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值