《java学习笔记》之反射机制初步

反射机制

一.反射机制的作用

二.反射机制相关的重要的类及其常用方法

2.1 java.lang.Class:

代表整个字节码,代表一个类型,代表整个类。

(一)获取class对象的三种方法
/*
 * 要操作一个类的字节码,首先要获取到这个类的字节码,怎么获取java.lang.Class实例?
 *       三种方式
 *               第一种: Class c = Class.forName("完整类名带包名");
 *               第二种: Class c =对象.getClass();
 *               第三种:  Class c =数据类型.class()
 * */
public class ReflectTest01 {
    public static void main(String[] args) {
        /*
         * Class.format()
         *   1.静态方法
         *   2.方法的参数是一个字符串
         *   3.字符串需要一个完整的类名
         *   4.完整类名必须带有包名,java.lang包也不能省
         * */

        Class c1 = null;
        try {
            c1 = Class.forName("java.lang.String");//c1代表String.class文件,或者c1代表String类型
            System.out.println(c1);//class java.lang.String
            Class c2 = Class.forName("java.util.Date");//c2代表Date类型
            System.out.println(c2);//class java.util.Date
            Class c3 = Class.forName("java.util.Random");//c3代表Random类型
            System.out.println(c3);//class java.util.Random
            Class c4 = Class.forName("java.math.BigDecimal");//c4代表 BigDecimal 类型
            System.out.println(c4);//class java.math.BigDecimal
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //java中任何一个类都有一个方法:getClass()
        String string = "abc";
        Class c5 = string.getClass();
        //内存地址相同,都是指向 String 的字节码文件
        System.out.println(c5 == c1);//true

        //第三种方式:java中任何一种数据类型,包括基本数据类型,都有.class属性
        Class c6 = String.class;
        System.out.println(c6);//class java.lang.String

        Class c7 = Integer.class;
        System.out.println(c7);//class java.lang.Integer

        Class c8 = double.class;
        System.out.println(c8);//double
    }
}
(二)通过class文件来实例化对象
/*
 * 通过Class的newInstance()方法来实例化对象
 * 注意:newInstance()方法内部实际上是调用了无参数构造方法,必须保证无参构造存在
 * */
public class ReflectTest02 {
    public static void main(String[] args) {
        //获取字节码对象
        try {
            Class c = Class.forName("javasetest.bean.User");//完整类名带包名
            //通过 class 文件来实例化对象
            Object o1 = c.newInstance();//调用了无参数构造方法
            System.out.println(o1);
            //无参构造方法执行
            //javasetest.bean.User@6bdf28bb
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

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

/*
 * 验证反射机制的灵活性
 *   java代码写一次,在不改变java源代码的基础上,可以做到不同对象的实例化
 *   非常之灵活(符合OCP原则:对拓展开放,对修改关闭)
 * */
public class ReflectTest03 {
    public static void main(String[] args) {
        //通过IO流读取calssinfo.porperties文件
        FileReader fileReader =null;
        //创建Map对象
        Properties properties = new Properties();
        try {
             fileReader = new FileReader("C:\\IdeaProjects\\chapter25 反射机制\\src\\classinfo2.properties");
             //将文件中的内容下载到 properties 中
            properties.load(fileReader);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭流
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //通过key获取value
        String value = properties.getProperty("className");
        System.out.println(value);
        //创建类对象
        Class c =null;
        try {
            //类名带包名,获得 字节码文件
            c = Class.forName(value);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //实例化对象
        Object object = null;
        try {
             object = c.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        System.out.println(object);
    }
}

import javasetest.bean.Vip;

import java.lang.reflect.Constructor;

//使用反射机制创建对象
public class ReflectTest11 {
    public static void main(String[] args) throws Exception {
        //不使用放射机制怎么创建对象
        Vip vip1 = new Vip();
        Vip vip2 = new Vip(123,"钢铁侠","2008-4-14",true);

        //使用反射机制
        //获取类
        Class vipClass = null;
        try {
            vipClass = Class.forName("javasetest.bean.Vip");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //使用无参构造
        Object o1 = vipClass.newInstance();
        System.out.println(o1);//Vip{no=0, name='null', birth='null', sex=false}

        //调用有参的构造方法
        //第一步:先获取到这个有参的构造方法
        //参数是class
        Constructor constructor = vipClass.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
        //第二步:调用构造方法new对象
        Object o2 = constructor.newInstance(123,"美国队长","2001-9-9",true);
        System.out.println(o2);//Vip{no=123, name='美国队长', birth='2001-9-9', sex=true}

    }
}

(三)了解 Class.forName()
/*
 * 研究一下,Class.forName()发生了什么
 *   如果你只是希望一个类的静态代码块执行,其余的代码一律不执行
 *   可以使用:
 *           Class.forName("完整类名");
 *           这个方法的执行会导致类加载,类加载时,静态代码块执行
 *           JDBC会使用
 * */
public class ReflectTest04 {
    public static void main(String[] args) {
        try {
            Class c = Class.forName("javasetest.reflect.MyClass");//静态方法执行
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class MyClass{
    static {
        System.out.println("静态方法执行");
    }

    public MyClass() {
        System.out.println("无参构造执行");
    }
}
2.2 java.lang.reflect.Method
(一)反射类当中所有的Method

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

//如何通过反射机制获取方法
public class reflectTest08 {
    public static void main(String[] args) {
        //获取类
        Class userServiceClass = null;
        try {
            userServiceClass = Class.forName("javasetest.UserService");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //获取所有的方法
        Method[] methods = userServiceClass.getDeclaredMethods();
        //看一下有多少方法
        System.out.println(methods.length);//2
        //遍历
        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 p:parameterTypes){
                System.out.println(p.getSimpleName());
            }
        }
    }
}
(二)通过反射机制调用对象的方法
import javasetest.UserService;

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

/*
 * 重点:必须掌握
 * 通过反射机制再怎么调用一个对象的方法
 * */
public class reflectTest09 {
    public static void main(String[] args) {
        //不使用反射机制怎么调用方法?
        UserService user1 = new UserService();
        //调用方法
        boolean log1 = user1.login("钢铁侠","123");
        System.out.println(log1);//true

        //使用反射机制
        Class userServiceClass = null;
        try {
            userServiceClass = Class.forName("javasetest.UserService");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //创建对象
        Object object = null;
        try {
            object = userServiceClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        //获取方法
        Method methodLog = null;
        try {
            methodLog = userServiceClass.getMethod("login",String.class,String.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //调用方法
        Object log2 = false;
        try {
            log2 = methodLog.invoke(object,"美国队长","321");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        System.out.println(log2);//false
    }
}

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

/*
反编译一个类的Constructor构造方法
* */
public class ReflectTest10 {
    public static void main(String[] args) throws Exception{
        StringBuilder s= new StringBuilder();
        Class vipClass = Class.forName("javase.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 p: parameterTypes){
                s.append(p.getSimpleName());
                s.append(",");
            }
            if (parameterTypes.length > 0){
                s.deleteCharAt(s.length() - 1);
            }
            s.append("){}\n");
        }

        s.append("}");
        System.out.println(s);
    }
}

2.4 java.lang.reflect.Field:

代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

(一)反射类当中所有的Field
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/*
 * 反射Student类当中所有的Field(了解)
 * */
public class ReflectTest05 {
    public static void main(String[] args) {
        //获取整个类
        try {
            Class studentClass = Class.forName("javasetest.bean.Student");

            //获取类的名字
            String stringName = studentClass.getName();
            System.out.println("完整类名 " + stringName);//完整类名 javasetest.bean.Student
            //获取类的简单名字
            String stringSimpleName = studentClass.getSimpleName();
            System.out.println("简单类名 " + stringSimpleName);//简单类名 Student

            //获取Student类的属性
            Field[] fields = studentClass.getFields();
            //想知道里面有几个属性
            System.out.println(fields.length);//1
            //想知道里面是什么元素
            //取出整个Field
            System.out.println(fields[0]);//public int javasetest.bean.Student.no
            //取出这个属性的名字
            //说明只有 public 修饰的可以被取出来
            System.out.println(fields[0].getName());//no

            //取出所有的属性
            Field[] fields1 = studentClass.getDeclaredFields();
            //看里面是不是有四个元素
            System.out.println(fields1.length);//4

            //遍历
            for (int i = 0; i < fields1.length; i++) {
                //取出名字
                //System.out.println(fields1[i].getName());
                //获取属性的类型
                //System.out.println(fields1[i].getType());
                //获取属性修饰符
                //int j = fields1[i].getModifiers();//1 2 4 0
                //将代号转化成字符串
                //String string = Modifier.toString(j);
                //public
                //private
                //protected
                //

                int j = fields1[i].getModifiers();
                String string = Modifier.toString(j);
                Object type = fields1[i].getType();
                String stringname = fields1[i].getName();
                System.out.print( j +"   "+ string +"   "+type + "   "+stringname);
                System.out.println();
                //1   public   int   no
                //2   private   class java.lang.String   name
                //4   protected   int   age
                //0      boolean   sex
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

(二)通过反编译,反编译一个类属性Field
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

//通过反编译,反编译一个类属性Field(了解)
public class ReflectTest06 {
    public static void main(String[] args) {
        //拼接字符串
        StringBuilder stringBuilder = new StringBuilder();
        //获得整个类的class
        try {
            Class studentClass = Class.forName("javasetest.bean.Student");
            stringBuilder.append(Modifier.toString(studentClass.getModifiers()) + " class " + studentClass.getSimpleName() + "{");
            stringBuilder.append("\n");
            Field[] fields = studentClass.getDeclaredFields();
            for (Field field : fields){
                stringBuilder.append("\t");
                stringBuilder.append(Modifier.toString(field.getModifiers()));
                stringBuilder.append(" ");
                stringBuilder.append(field.getType().getSimpleName());
                stringBuilder.append(" ");
                stringBuilder.append(field.getName());
                stringBuilder.append(";");
                stringBuilder.append("\n");
            }
            stringBuilder.append("}");
            System.out.println(stringBuilder);
            //public class Student{
            //	public int no;
            //	private String name;
            //	protected int age;
            //	 boolean sex;
            //}
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

(三)通过放射机制访问一个java对象的属性
import javasetest.bean.Student;

import java.lang.reflect.Field;

/*必须掌握:
 *   怎么通过放射机制访问一个java对象的属性?
 *       给属性赋值 set
 *       获取属性的值get
 * */
public class ReflectTest07 {
    public static void main(String[] args) {
        //不使用反射机制,怎么访问一个java对象的属性
        Student student = new Student();
        System.out.println(student.no);//0
        student.no = 10;
        System.out.println(student.no);//10
        //使用反射机制
        try {
            Class studentClass = Class.forName("javasetest.bean.Student");
            //实例化对象
            Object object = studentClass.newInstance();//底层调用无参构造
            //获取属性(根据属性名称)
            Field noField = studentClass.getDeclaredField("no");
            //给o对象(Student对象)的no属性赋值

            /*
             * object : 对象 引用
             * field: 属性
             * 2222 : 字面量
             *
             * 放射机制让代码复杂了,但是为了“灵活”
             * */
            noField.set(object,222);
            //读取属性的值
            System.out.println(noField.get(object));//222

            //试一下可不可以访问是有属性
            Field nameField = studentClass.getDeclaredField("name");
            //java.lang.IllegalAccessException: 
            // class javasetest.reflect.ReflectTest07 
            // cannot access a member of class javasetest.bean.Student with modifiers "private"
            //如果没有下面这行代码
            nameField.setAccessible(true);//打破封装
            nameField.set(object,"钢铁侠");
            System.out.println(nameField.get(object));//可以访问私有属性
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

2.5 如何获取父类及类实现的接口
//给你一个类,怎么获取这个类的父类
public class ReflectTest13 {
    public static void main(String[] args) throws Exception {
        //先获取本类
        Class stringClass = Class.forName("java.lang.String");
        //本类的父类
        Class superClass = stringClass.getSuperclass();
        System.out.println(superClass);//class java.lang.Object
        //获取String类实现的所有接口
        Class[] classes = stringClass.getInterfaces();
        for (Class c : classes){
            System.out.println(c);
        }
        //interface java.io.Serializable
        //interface java.lang.Comparable
        //interface java.lang.CharSequence
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值