码迷,mamicode.com
首页 > 其他好文 > 详细

反射那些事

时间:2018-10-13 22:52:03      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:static   arrays   忽略   ret   integer   相关   pack   sse   调用   

一直以为只要把类的成员变量设置为private,或者方法设置为private,那么他就对外完全隐藏,类外部无法直接对该成员变量或者方法进行直接访问。但是java的反射,拥有十分强大的功能,它可以访问类中的任意成员变量和方法,我们可以通过反射直接入侵类的私有变量和私有方法,私有构造器。我们来了解一下反射的一些用法吧。

package com.reflect;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

class Person{

    public final Integer id=1001;

    private String name;

    public Person() {}

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

    public String getName() {
        return name;
    }

    private void say(String message){
        System.out.println("You want to say: "+message);
    }

}

public class Reflect {

    @Test
    public void testGetField() throws ClassNotFoundException {
        Class<?> clazz=Class.forName("com.reflect.Person");
        //获得声明为public域的字段
        System.out.println("Fields: "+Arrays.toString(clazz.getFields()));
        //获取所有的字段
        System.out.println("Declared Fields: "+Arrays.toString(clazz.getDeclaredFields()));
    }

    //通过类型标签我们只能调用无参的构造器
    //以下是如果通过反射调用带参数的构造器
    @Test
    public void test() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> clazz=Class.forName( "com.reflect.Person" );

        Constructor c=clazz.getConstructor(String.class);

        Person person= (Person) c.newInstance("viscu");

        System.out.println(person.getName());
    }


    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {

        Person person=new Person();

        Class<?> classType=person.getClass();

        //访问私有方法
        //getDeclaredMethod可以获取到所有方法,而getMethod只能获取public
        Method method=classType.getDeclaredMethod("say", String.class);
    
        //设置为true 可以忽略对类相关访问权限的检查
        method.setAccessible(true);

        //通过反射调用person类中的private方法
        method.invoke(person,"check");

        //入侵类内部的私有成员变量
        Field field=classType.getDeclaredField("name");

        field.setAccessible(true);

        field.set(person,"walk");

        System.out.println(person.getName());
    }

}

以上就是通过反射对类的私有域进行访问的一些例子,利用反射我们可以轻易地入侵到类的内部,举个通过入侵改变类的运行机制的例子。

单例模式(顾名思义:就是该类型的类只有一个实例)

public class SingletonTest {

    private static final SingletonTest INSTANCE = new SingletonTest();

    private SingletonTest(){
        //todo
    }

    public static SingletonTest getInstance(){
        return INSTANCE;
    }
    public void show(){
        System.out.println("Singleton using static initialization in Java");
    }

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        SingletonTest demo=SingletonTest.getInstance();
        demo.show();

        Class<?> clazz=SingletonTest.class;
        SingletonTest o= (SingletonTest) clazz.newInstance();
        o.show();

        System.out.println(demo==o);

    }

}

虽然我们把Singleton的构造器设置为private了,可是我们还是可以通过反射轻易地构造出第二个SingletonTest 实例,第三个,第四个.....等,那么就违背了单例模式的本意了。

至于如何预防

  • 我们可以在私有构造器中抛出一个异常即可防止构建新的实例。
private SingletonTest(){
     if(INSTANCE!=null){
          throw new RuntimeException("you can‘t create another one");
     }
}

反射,让我们原本以为安全的类变得不那么安全了,别人可以轻易入侵你的类内部改变你的原有数据,至于如何预防,有待研究。

反射那些事

标签:static   arrays   忽略   ret   integer   相关   pack   sse   调用   

原文地址:https://www.cnblogs.com/viscu/p/9784303.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!