Java中的反射机制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。通过java语言的反射机制可以操作字节码文件。


一、反射机制的作用

1.反编译:.class–>.java

2.通过反射机制访问java对象的属性,方法,构造方法等;

二、反射机制中相关的类

1.java.lang.Class:代表字节码文件
2.java.lang.reflect.Method:代表字节码中的方法
3. java.lang.reflect.Constructor:代表字节码中的构造方法
4. java.lang.reflecy.Field:代表字节码中的属性

三、反射机制中具体功能的实现

1.获取类Class的三种方式

代码如下(示例):

public class ReflectTest01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一种:Class.forName(String string):
        /*1.静态方法    2.方法的参数是一个字符串
         3.字符串需要的是一个完整类名  4.完整类名必须包含有包名,java.lang包不能省略*/
        Class c1 = Class.forName("java.lang.String");//c1代表String类的字节码文件,即String.class文件
        Class c2 = Class.forName("java.lang.System");
        //第二种:使用Object类内的getClass()方法
        String s = "anc";
        Class x = s.getClass();//x代表String.class字节码文件
        //第三种:java语言中任何一种类型,包括基本数据类型,它都有.class属性
        Class y = String.class;
    }
}

Class的newInstance()用来实例化对象。但是需要注意这个方法内部调用了无参数构造方法,必须保证无参数构造方法存在。
如果只希望一个类中的静态代码块执行,其他代码不执行,则可以使用Class.forName("");这个方法会导致类加载,只要类加载,则静态方法块执行。

补充:关于路径问题

代码如下(示例):

public class ReflectTest02 {
    public static void main(String[] args) {
        //使用以下通用方式的前提是:这个文件必须在类路径下
        //类路径是在src下的都是类路径,src是根路径
        //采用以下方法可以获得一个文件的绝对路径
        /*
        * Thread.currentThread():当前线程对象
        * getContextClassLoader():是线程对象的方法,可以获取当前线程的类加载器对象
        *getResource(""):这是类加载器的方法,当前线程的类加载器默认是从类的根路径下加载资源的 
        hahaha是类路径下的一个文件*/
        System.out.println(Thread.currentThread().getContextClassLoader().getResource("hahaha").getPath());
    }
}

2.反射一个类及其中的基本属性

代码如下(示例):

public class ReflectTest044 {
    public static void main(String[] args) throws ClassNotFoundException {

        //创建这个是为了拼接字符串
        StringBuilder s = new StringBuilder();
        //获取Student这个类
        Class student = Class.forName("com.bjpowernode.javase.reflect.Student");
        //获取了类的修饰符与类名并且进行了拼接
        s.append(Modifier.toString(student.getModifiers())+"  class  "+student.getSimpleName()+"{"+"\n");
        //获取Student类中的所有属性
        Field[] fileds = student.getDeclaredFields();

        //增强for循环,用于反射Student类中的所有属性
        for (Field filed:fileds) {
            s.append("\t");
            s.append(Modifier.toString(filed.getModifiers()));
            s.append(" ");
            s.append(filed.getType().getSimpleName());
            s.append(" ");
            s.append(filed.getName());
            s.append(";");
            s.append("\n");
        }
        s.append("}");
        System.out.println(s);
    }
}

2.反射一个类及其中的基本属性

通过反射机制访问一个java对象的属性
   给属性赋值set
   获取属性值get
代码如下(示例):

public class ReflectTest05 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        //获取Student类
        Class student = Class.forName("com.bjpowernode.javase.reflect.Student");
        //实例化对象
        Object obj = student.newInstance();

        //获取no属性
        Field noo = student.getDeclaredField("no");
        //给obj对象的no属性赋值
        noo.set(obj,111);
        //获取no属性的值
        System.out.println(noo.get(obj));

        Field nameField = student.getDeclaredField("name");
        nameField.setAccessible(true);//因为name属性时私有属性,因此该语句用来打破封装,这也是反射机制的缺点之一
        //给obj对象的name属性赋值
        nameField.set(obj,"haha");
        //获取obj对象name属性的值
        System.out.println(nameField.get(obj));

    }
}

补充:可变长参数问题

代码如下(示例):

//括号里的内容就是可变长参数,语法是类型后加三个点,例如int...;需注意类型匹配问题
    public static void m(int... args){

    }
    //此语句错误,因为可变长参数只能放在最后一个位置上
    /*public static void n(int... args,int m){

    }*/
    //此语句错误,可变长参数只能有一个
    /*public static void n(int... args,float... arr){

    }*/

3.反射一个类中的方法

代码如下(示例):

/*利用反射机制反射类中的方法*/
public class ReflectTest07 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取UserService类
        Class uerService = Class.forName("com.bjpowernode.javase.reflect.UserService");
        //获取类中的所有方法
        Method[] methods = uerService.getDeclaredMethods();
        //System.out.println(methods.length);
        //使用增强for循环遍历Method
        for (Method method:methods) {

            //获取方法的修饰符
            System.out.println(Modifier.toString(method.getModifiers()));
           //获取方法的返回值类型
            System.out.println(method.getReturnType().getSimpleName());
            //获取方法名
            System.out.println(method.getName());
            //获取形参的类型
            Class[] classes =  method.getParameterTypes();
            for (Class cla:classes ) {
                System.out.println(cla.getSimpleName());
            }
        }
    }
}

4.反射机制反射类中的构造方法

代码如下(示例):

public class ReflectTest10 {
    public static void main(String[] args) throws ClassNotFoundException {
        StringBuilder s = new StringBuilder();
        Class vipClass = Class.forName("com.bjpowernode.javase.reflect.Vip");

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

        //拼接构造方法
        Constructor[] constructors = vipClass.getConstructors();
        for (Constructor constructor:constructors ) {
            s.append("\t");
            s.append(Modifier.toString(constructor.getModifiers()));
            s.append(" ");
            s.append(vipClass.getSimpleName());
            s.append("(");
            Class[] parameterType = constructor.getParameterTypes();
            for (Class parameterTypes:parameterType) {
                s.append(parameterTypes.getSimpleName());
                s.append(",");
            }
            if(parameterType.length>0){
            s.deleteCharAt(s.length()-1);}
            s.append("){}\n");
        }
        s.append("}");
        System.out.println(s);


    }
}

5.反射机制获取类的父类及父接口

代码如下(示例):

public class ReflectTest12 {
    public static void main(String[] args) throws Exception {
        Class stringClass = Class.forName("java.lang.String");

        //获取String的父类
        Class superClass = stringClass.getSuperclass();
        System.out.println(superClass.getName());
        //获取父接口
        Class[] interfaces = stringClass.getInterfaces();
        for (Class in:interfaces    ) {
            System.out.println(in.getName());

        }


    }
}

上述代码中用到的Student类如下:

代码如下(示例):

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

上述代码中用到的UserService类如下:

代码如下(示例):

public class UserService {
    public boolean login(String name, String password){
        if("admin".equals(name) && "123".equals(password)) {
            return true;
        }
        return false;
    }

    public void exit(){
        System.out.println("已退出");
    }
}

上述代码中用到的Vip类如下:

代码如下(示例):

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;
    }

    @Override
    public String toString() {
        return "Vip{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", birth='" + birth + '\'' +
                ", sex=" + sex +
                '}';
    }
}


总结

反射的优缺点:

1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方 便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:
(1)反射会消耗一定的系统资源;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值