反射机制笔记

1.反射机制有什么用?

通过java的反射机制可以操作字节码文件。
反射机制的相关类在java.lang.reflect.*包下。
反射机制相关的类有:
1.java.lang.Class 代表字节码文件
2.java.lang.reflect.Method 代表字节码文件中的方法
3.java.lang.reflect.Constructor 代表字节码文件中的构造方法
4.java.lang.reflect.Field 代表字节码文件中的属性

2.获取一个类的字节码文件

要操作一个类的字节码文件,首先要获取到这个类的字节码。
第一种方式:Class c=Class.forName(“包名+类名”) 这个方法的执行会导致类加载
第二种方式:Class c=对象.getClass()
第三种方式:Class c=数据类型.clsss

public class GetReflect01 {
    public static void main(String[] args) {
        /**
         * Class.forName()
         * 1.静态方法
         * 2.参数是个字符串
         * 3.字符串是一个完整的类名
         * 4.类名必须带有包名(有同名类)
         */
        Class c1=null;
        Class c3=null;
        try {
            c1=Class.forName("java.lang.String");
            Class c2=Class.forName("java.lang.Thread");
            c3=Class.forName("java.util.Date");
            Class c4=Class.forName("java.lang.Integer");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //任何一个java对象都有一个方法:getClass()
        String s="abc";
        Class s1 = s.getClass();//s1表示String.class字节码文件
        System.out.println(c1==s1);//比较两种方式获取的String.class字节码文件地址是否一样
        Date d=new Date();
        Class d1= d.getClass();
        System.out.println(c3==d1);//比较的是对象的内存地址
        //任何一种数据类型都有class属性  基本数据类型也有这个属性
        Class s2=String.class;
        System.out.println(s1==s2);
    }
}

3.通过反射机制实例化对象

newInstance()会调用对象的无参构造方法,完成对象的创建。只会调无参构造,所以每次写实体类一定要把无参构造写起!!!

public class Reflect01 {
    public static void main(String[] args) {
        //通过反射机制,获取Calss,通过Class实例化对象
        try {
            Class user=Class.forName("com.zhouqun.reflect.User");
            //newInstance()会调用对象的无参构造方法,完成对象的创建
            Object o = user.newInstance();
            System.out.println(o);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

与直接new对象比起来,理用反射创建对象更加灵活,可以通过读取配置文件来创建对象。不用修改java的源代码,实例化不同的对象,符合开闭原则。

public class Reflect02 {
    public static void main(String[] args) {
        //通过修改配置文件,实例化不同的对象
        try {
            //通过IO流读取文件
            FileReader reader = new FileReader("classname.properties");
            //创建属性类对象Map   =左边是key   =右边是value
            Properties pro=new Properties();
            //加载
            pro.load(reader);
            //关闭流
            reader.close();
            //通过key获取value
            String className = pro.getProperty("className");
            //实例化对象
            Class user = Class.forName(className);
            Object o = user.newInstance();
            System.out.println(o);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

获取文件的绝对路径:各个操作系统通用(文件放在src下)

//            通过IO流读取文件
            String path=Thread.currentThread().getContextClassLoader().getResource("classname.properties").getPath();
            FileReader reader = new FileReader(path);
// 创建属性类对象Map   =左边是key   =右边是value
            Properties pro=new Properties();
            //加载
            pro.load(reader);
            //关闭流
            reader.close();

还可以写成:

 InputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream("classname.properties");
            Properties pro=new Properties();
            //加载
            pro.load(in);
            //关闭流
            in.close();

4.资源绑定器

java.util包下提供了一个资源绑定器,便于获取属性文件(properties)中的内容,属性文件必须放在类路径下(src)

public class Boundle {
    public static void main(String[] args) {
        ResourceBundle bundle=ResourceBundle.getBundle("classname");
        String className = bundle.getString("className");
        System.out.println(className);
    }
}

5.通过反射获取Field

public class Student {
    public String name;
    private int id;
    protected String sex;
    int age;
}

1.类.getFields() 获取类中修饰符为public的属性;

//获取整个类
        Class student=Class.forName("com.zhouqun.bean.Student");
        //获取类中的所有属性字段
        Field[] fields = student.getFields();//这种方法只能获取修饰符为public的属性字段
        //取出这个field
        Field field=fields[0];
        //获取这个属性的名字
        System.out.println(field.getName());

2.类.getDeclaredFields() 获取类中所有属性

//获取整个类
        Class student=Class.forName("com.zhouqun.bean.Student");
        Field[] declaredFields = student.getDeclaredFields();
        for (Field f:declaredFields){
            System.out.println(f.getName());
        }

3.类.getName 获取完整类名(包名+类名)
类.getSimpleName 获取简单类名(类名)
4.属性.getType() 获取属性的数据类型

Field[] declaredFields = student.getDeclaredFields();
        for (Field f:declaredFields){
            //获取字段的数据类型
            Class<?> type = f.getType();
            System.out.println(type);
            System.out.println("获取数据类型的名字"+type.getName());
            System.out.println("获取属性名"+f.getName());
        }

5.属性.getModifiers 获取属性的修饰符
改方法返回的是代表修饰符编号的数字

Field[] declaredFields = student.getDeclaredFields();
        for (Field f:declaredFields){
            //获取字段的修饰符编号
            int i= f.getModifiers();
            //将编号转换成字符串
            String modifierStr=Modifier.toString(i);
            System.out.println(modifierStr);
        }

6.通过反射机制获取、修改属性的值【get\set】

public class Reflect03 {
    public static void main(String[] args) throws Exception{
        //使用反射机制,去访问对象的属性
        Class<?> student = Class.forName("com.zhouqun.bean.Student");
        //实例化一个student对象   调用的是无参构造
        Object o = student.newInstance();
        //根据属性名获取name属性   只能获取修饰符为public的属性
        Field name = student.getDeclaredField("name");
        //通过set给student对象(obj)的name属性赋值
        name.set(o,"张三");
        //通过get获取student对象的name属性的值
        Object o1 = name.get(o);
        System.out.println(o1);
    }
}

7.打破封装 setAccessible(true)

第六小节只能获取和修改public的属性,要是想修改private的属性,就需要打破封装。这是反射机制的缺点

public class Reflect03 {
    public static void main(String[] args) throws Exception{
        //使用反射机制,去访问对象的属性
        Class<?> student = Class.forName("com.zhouqun.bean.Student");
        //实例化一个student对象   调用的是无参构造
        Object o = student.newInstance();
        //根据属性名获取name属性   只能获取修饰符为public的属性
        Field id = student.getDeclaredField("id");
        //打破封装
        id.setAccessible(true);
        //通过set给student对象(obj)的name属性赋值
        id.set(o,111);
        //通过get获取student对象的name属性的值
        Object o1 = id.get(o);
        System.out.println(o1);
    }
}

8.反射Method

public class StudentService {
    public void login(String name,int age){
    }
    public boolean loginout(String name,int age){
        return true;
    }
}
public class Reflect04 {
    public static void main(String[] args) throws Exception {
        //获取studentService对象
        Class<?> student = Class.forName("com.zhouqun.bean.StudentService");
        //获取所有的Method  包括私有的
        Method[] declaredMethods = student.getDeclaredMethods();
        //遍历method
        for (Method method:declaredMethods){
            //获取修饰符列表
            System.out.println(Modifier.toString(method.getModifiers()));
            //获取方法的返回值
            System.out.println(method.getReturnType().getSimpleName());
            //获取方法名
            System.out.println(method.getName());
            //获取方法的参数列表(可能会有多个参数)
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (Class para:parameterTypes){
                System.out.println(para.getSimpleName());
            }
        }
    }
}

9.通过反射机制调用对象的方法【及其重要:invoke】

public class Reflect04 {
    public static void main(String[] args) throws Exception {
        //获取studentService对象
        Class<?> student = Class.forName("com.zhouqun.bean.StudentService");
        //new一个studentService
        Object o = student.newInstance();
        //获取method   分别传入方法名和参数
        Method login = student.getDeclaredMethod("login", String.class, int.class);
        //调用method【及其重要】
        //调用o对象(studentService)的login方法,传入参数:"张三", 12   stu是返回值
        Object stu = login.invoke(o, "张三", 12);
        System.out.println(stu);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值