JavaSE进阶回顾第七天-反射机制

第七章

  • 反射机制概述
  • Class
  • Field
  • Method
  • Constructor
反射机制概述
  1. 反射机制有什么用?

​ 通过java语言中的反射机制可以操作字节码文件

​ 类似于黑客,可以读和改字节码文件。

  1. 反射机制的相关类在哪个包下?

    java.lang.reflect.*;
    
  2. 反射机制相关的重要的类有哪些?

    java.lang.Class;//代表字节码文件
    java.lang.reflect.Method;//代表字节码中的方法字节码
    java.lang.reflect.Constructor;//代表字节码中的构造方法字节码
    java.lang.reflect.Field;//代表字节码中的属性字节码
    
获取Class的三种方式
/**
 * 要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例?
 *  三种方式:
 *      第一种:Class c = Class.forName("完整类名带包名")
 *      第二种:Class c = 引用.getClass();
 *      第三种:Class c = String.class;
 *             Class c = int.class;
 *
 */
public class ReflectTest01 {
    public static void main(String[] args) {
        /*
        Class.forName()
            1、静态方法。
            2、方法的参数是一个字符串。
            3、字符串需要的是一个完整的类名。
            4、完整类名必须带有包名。java.lang包也不能省略。
         */
        Class c1=null;
        Class c2=null;

        //第一种方式
        try {
            c1 = Class.forName("java.lang.String");
            c2 = Class.forName("java.util.Date");
            Class c3 = Class.forName("java.lang.Integer");
            Class c4 = Class.forName("java.lang.System");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //第二种方式
        //java中任何一个对象都有一个方法getClass()
        String s = "abd";
        Class x = s.getClass();
        System.out.println(c1==x);//true 内存地址一样

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

        //第三种方式
        Class z = String.class;
        Class k = int.class;
        Class f = Date.class;
        Class e = double.class;
    }
}
Class作用
/**
 * 获取到class能干什么?
 *      通过Class的newInstance()方法来实例化对象,
 *      注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参数构造方法的存在才可以。
 */
public class ReflectTest02 {
    public static void main(String[] args) {
        try {
            //通过反射机制,获取Class,通过Class来创建对象。
            Class c = Class.forName("com.chinasoft.reflect.User");
            //也可以使用泛型。
            Class<User> c2 = (Class<User>)Class.forName("com.chinasoft.reflect.User");

            //newInstance方法会调用User类的无参构造方法。
            Object obj = c.newInstance();
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
/*
运行结果:
com.chinasoft.reflect.User@1b6d3586
*/
反射机制的灵活性

classinfo.properties文件:

className=com.chinasoft.reflect.User
#className=java.util.Date
/**
 * 验证反射机制的灵活性。 传统的new方式就写死了。
 * 这里只需要改classinfo.propertie文件的className即可创建不同类型的对象。
 */
public class ReflectTest03 {
    public static void main(String[] args) throws Exception {
        //通过IO流读取classinfo文件的className
        FileReader reader = new FileReader("chapter25/src/classinfo.properties");
        Properties p = new Properties();
        p.load(reader);
        //Set<Map.Entry<Object, Object>> set = p.entrySet();
        String className = p.getProperty("className");
        System.out.println(className);//com.chinasoft.reflect.User

        Class c = Class.forName(className);
        Object obj = c.newInstance();//通过反射机制创建对象
        System.out.println(obj);

        reader.close();//关闭流
    }
}
/*
运行结果:
com.chinasoft.reflect.User
com.chinasoft.reflect.User@1b6d3586
*/
/**
 * 研究一下Class.forName()发生了什么?
 * 重点:
 *      如果你只希望一个类的静态代码块执行,其他代码一律不执行
 *      可以使用:
 *          Class.forName("完整类名");
 *
 * JDBC技术使用。
 */
public class ReflectTest04 {
    public static void main(String[] args) {
        try {
            //这个方法的执行会导致类加载
            Class.forName("com.chinasoft.reflect.MyClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class MyClass{
    //静态代码块在类加载时执行,并且只执行一次。
    static {
        System.out.println("静态代码块执行!");
    }
}
获取类路径下的绝对路径(重要)
/**
 * 获取类路径下的绝对路径。(这种方式是通用的!)
 */
public class ReflectTest05 {
    public static void main(String[] args) {
        //获取绝对路径的类必须在src根路径下。 "classinfo.properties"是在src根路径下开始的。
        String path = Thread.currentThread().getContextClassLoader()
                .getResource("classinfo.properties").getPath();
        System.out.println(path);// /F:/IdeaProjects/javase/out/production/chapter25/classinfo.properties
        
    }
}

对以往获取路径方式的改进(以后都用这种!!!)

/**
 *IoProperties改进
 */
public class IoPropertiesTest {
    public static void main(String[] args) throws Exception {
        //获取classinfo.properties的绝对路径
        String path = Thread.currentThread().getContextClassLoader()
                .getResource("classinfo.properties").getPath();

        FileReader reader = new FileReader(path);
        Properties p = new Properties();
        p.load(reader);
        reader.close();
        //通过key值获取value
        System.out.println(p.getProperty("className"));//com.chinasoft.reflect.User
    }
}
资源绑定器

这种方式可以代替IoProperties的方式!!!

/**
 * java.util报下的一个资源绑定器,便于获取属性配置文件的内容。
 * 使用以下这种方式的时候,属性配置文件xxx.properties必须放到类路径下。
 * 
 * 这种方式可以代替IoProperties的方式!!!
 */
public class ResourceBundleTest {
    public static void main(String[] args) {
        //资源绑定器
        //路径后面的扩展名不能写。
        ResourceBundle rb = ResourceBundle.getBundle("classinfo2");
        String className = rb.getString("className");
        System.out.println(className);
    }
}
Field
/**
 * 反射Student类当中所有的Field
 */
public class ReflectTest06 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取整个类
        Class stuClass = Class.forName("com.chinasoft.reflect.Student");
        System.out.println(stuClass.getName());//com.chinasoft.reflect.Student
        System.out.println(stuClass.getSimpleName());//Student

        //获取类中所有的public修饰的Field
        Field[] fields = stuClass.getFields();
        System.out.println(fields.length);//1
        for (int i=0;i<fields.length;i++){
            System.out.println(fields[i].getName());
        }
        System.out.println("================================================");

        //获取所有的Field
        Field[] fields1 = stuClass.getDeclaredFields();
        System.out.println(fields1.length);//4
        for (Field field:fields1){
            System.out.println(field.getName());//获取属性名
            System.out.println(field.getType());//获取属性类型

            int i = field.getModifiers();//获取属性修饰符
            System.out.println(i);
            String modifierString = Modifier.toString(i);
            System.out.println(modifierString);
        }

    }
}
反编译一个类的属性Field(了解)
/**
 *通过反射机制,反编译一个类的属性Field
 */
public class ReflectTest07 {
    public static void main(String[] args) throws Exception{

        //创建这个是为了拼接字符串。
        StringBuilder s = new StringBuilder();

        Class stuClass = Class.forName("com.chinasoft.reflect.Student");//java.lang.Integer

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

        Field[] fields = stuClass.getDeclaredFields();

        for (Field field:fields){
            s.append(Modifier.toString(field.getModifiers())+" "+field.getType().getSimpleName()+" "+field.getName()+";\n");
        }

        s.append("}");

        System.out.println(s);

    }
}
/*
运行结果:
public class Student {
public int no;
private String name;
protected int age;
 boolean sex;
public static final double PI;
}
*/
通过反射机制访问对象属性(重点)

重点

/**
 * 怎么通过反射机制访问一个java对象的属性?
 *      给属性赋值set
 *      获取属性的值get
 */
public class ReflectTest08 {
    public static void main(String[] args) throws Exception{
        Class stuClass = Class.forName("com.chinasoft.reflect.Student");
        Object obj = stuClass.newInstance();

        //根据属性的名称获取Field
        Field field = stuClass.getDeclaredField("no");

        //可以访问私有的属性吗?
        Field nameField = stuClass.getDeclaredField("name");
        //打破封装
        nameField.setAccessible(true);//这样设置后,私有属性就可以访问了!
        nameField.set(obj, "jackon");//私有属性不能直接访问
        System.out.println(nameField.get(obj));//jackon

        //给obj对象的no属性赋值
        field.set(obj, 1111);
        //读取属性的值
        Object o = field.get(obj);
        System.out.println(o);//1111

    }
}
/*
运行如下:
jackon
1111
*/
Method(最重要)

可变长度参数:

/**
 * 可变长度参数
 *      int... args 这是可变长度参数
 *      语法是:类型...  (注意:一定是3个点)
 *
 *      1、可变长度参数要求参数的个数是:0~N个。
 *      2、可变长度参数在参数列表中必须在最后一个位置上。
 */
public class ArgsTest {
    public static void main(String[] args) {
        m();
        m(10);
        m(10,100);

        m2(5);
        m2(5,"100");
        m2(5,"100","200");

        //也可以传一个数组
        String[] strs = {"a","b","c"};
        m3(strs);
    }

    public static void m3(String... args) {
    }

    public static void m2(int a,String... args) {
        //可以将可变长度参数当做一个数组来看。
        for (int i=0;i<args.length;i++){
            System.out.println(args[i]);
        }
    }

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

通过反射机制调用方法 重点!!!

重点

/**
 * 重点(必须掌握):通过反射机制调用方法。
 *
 * 要素分析:
 *      要素1:对象userService
 *      要素2:login方法名
 *      要素3:实际参列表
 *      要素4:返回值
 */
public class ReflectTest09 {
    public static void main(String[] args) throws Exception{
        Class c = Class.forName("com.chinasoft.reflect.UserService");
        Object obj = c.newInstance();
        Method loginMethod = c.getDeclaredMethod("login", String.class,String.class);//获取login方法
        //反射机制中最最最重要的方法 invoke()
        Object ret = loginMethod.invoke(obj, "admin","123");//执行对象obj的login方法
        System.out.println(ret);//true
    }
}
Constructor

通过反射机制调用构造方法:

/**
 * 通过反射机制调用构造方法
 */
public class ReflectTest10 {
    public static void main(String[] args) throws Exception{

        Class vipClass = Class.forName("com.chinasoft.reflect.Vip");

        //调用无参数构造方法创建对象
        Object obj = vipClass.newInstance();

        //调用有参数构造方法怎么办?
        //第一步:先获取到这个有参数的构造方法
        Constructor constructor = vipClass.getConstructor(int.class,String.class,String.class,boolean.class);
        //第二步:调用构造方法创建对象
        Object obj2 = constructor.newInstance(1,"王磊","1999-11-29",true);

        //获取无参构造方法
        Constructor constructor1 = vipClass.getDeclaredConstructor();
        Object obj3 = constructor1.newInstance();

        System.out.println(obj);
        System.out.println(obj2);
        System.out.println(obj3);
    }
}
/*
运行结果:
Vip{no=0, name='null', birth='null', sex=false}
Vip{no=1, name='王磊', birth='1999-11-29', sex=true}
Vip{no=0, name='null', birth='null', sex=false}
*/

通过获取父类和父接口

/**
 * 获取父类和父接口
 */
public class ReflectTest11 {
    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.getName());
        System.out.println("===================================");

        //获取String类实现的所有接口(一个类可以实现多个接口)
        Class[] interfaces = stringClass.getInterfaces();
        for (Class in:interfaces){
            System.out.println(in.getName());
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值