30反射

 ·

耦合度:多个模块之间的关联或者依赖关系(低耦合)

解析类:用于找到字节码对象以产生实例对象的过程----反射   字节码文件就是.class

Class---代表类的类,把类抽取成一个对象,代表的也就是.class的类

Field --------代表属性的类

Method-------代表方法的类

Construct-----代表构造方法的类

Annotation----代表注解的类

Package------代表包的类

 

 类加载器

类加载器负责将.class文件(可能在磁盘上,也可能在网络上)加载到内存种,并为之生成对应的

java.;ang.Class对象。

 

获取字节码对象的方式

    //1.类型.class
    //获取String的字节码对象
    Class<String>clz=String.class;
    System.out.println(clz); //class java.lang.String
    //接口的字节码对象
    Class<List>clc=List.class;
    System.out.println(clc); //interface java.util.List
    //基本类型的字节码对象
    Class cla=int.class;
    System.out.println(cla);//int
    String str="abc";
//2对象.class 返回的是对象实际创建类的字节码对象
    Class<String>clb=(Class<String>) str.getClass();//class java.lang.String
    System.out.println(clb);
    Integer i=1;
    Class<Integer> cld=(Class<Integer>) i.getClass();//class java.lang.Integer
    System.out.println(cld);
    //3.没有类没有对象获取对应的字节码对象 ----Class.forName(全路径名);
    Class clh=Class.forName("java.utils.Math"); //class java.lang.String
    //class java.lang.Integer
    System.out.println(clh);

 

 

 

 

 

通过构造器创建实例对象

public class ClassDemo2 {
    public static void main(String[] args) throws ReflectiveOperationException, IllegalAccessException {
        //先获取Stirng的字节码对象
        Class<String> clz=String.class;
        //获取实例对象
        //newInstance()---默认调用类的无参构造
        //String str=clz.newInstance();    
        //str="abc";
        //System.out.println(str);
        //通过字节码对象调用到String类的有参构造
        Constructor c=clz.getConstructor(char[].class);//传入构造方法参数类型的字节码对象,获取到一个构造方法
        Constructor c1=clz.getConstructor(String.class);
        //获取到的有参构造调用newInstance()传入实际参数构造实例对象
        String str=(String) c.newInstance(new char[] {'1','4','a'});
        String str1=(String)c1.newInstance("dbsb");
        System.out.println(str);
        System.out.println(str1);
        //根据Integer创建一个对象
        //通过Class.forname获取字节码对象
        Class<Integer> clz3=(Class<Integer>) Class.forName("java.lang.Integer");
        //获取有参构造方法new Integer(int)
        Constructor c2=clz3.getConstructor(int.class);
        Integer str2=(Integer) c2.newInstance(123);
        System.out.println(str2);
    }
}

获取私有或者默认的构造方法

public class ClassDemo3 {
    public static void main(String[] args) throws ReflectiveOperationException, SecurityException {
        //获取字节码对象
        Class<String> clz=String.class;
        //获取指定构造方法,忽略访问权限修饰符
        //getDeclaredConstructor 和getConstructor区别,前者可以忽略掉构造方法的访问修饰符,尽量都用前者
        Constructor c1=clz.getDeclaredConstructor(char[].class,boolean.class);
        c1.setAccessible(true);//为true就是暴力破解---将原来的构造方法破解成我们可以直接赋值的构造方法
        //传参--构建实例对象;
        String str=(String) c1.newInstance(new char[] {'1','2','3'},true);//直接赋值时不行的,因为访问修饰符你
        //不能传值进去,要通过反射的暴力破解特殊的构造方法
    }
}

获取全部的构造方法

    public static void main(String[] args) {
        Class<String>clz=String.class;
        //获取字符数组的所有的构造方法
        Constructor[] cs=clz.getDeclaredConstructors(); 
        System.out.println(Arrays.toString(cs));
    }

获取属性

 

public class ClassDemo5 {
    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        //String 字节码对象
        Class<String> clz=String.class;
        //获取指定属性
        Field f=clz.getDeclaredField("hash");//hash属性是私有的
        //暴力破解
        f.setAccessible(true);
        //给字符串对象 属性赋值
        String str="abc";
        //给对象属性赋值 ---给Str对象的hash属性赋值123
        f.set(str, 123);
        //取值 ----获取str对象hash属性的值
        System.out.println(f.get(str));//123
        //获取String对象所有的属性
        Field[] fs=clz.getDeclaredFields();

    }
}

获取普通方法

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

public class ClassDemo6 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //获取字节码对象
        Class<String>clz=String.class;
        //获取指定方法
        Method m=clz.getDeclaredMethod("charAt",int.class);
        String string="ndsjknajk";
        //调用方法 ---s.charAt(3)
        char c=(char) m.invoke(string, 3);
        System.out.println(c);//j
        //获取全部的方法
        Method[] m2=clz.getDeclaredMethods();
    }
}

 

反射的缺点:

1.打破了封装原则

2跳过泛型的类型检测

反射跳过泛型检查

 @Test
public void method() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //创建集合
ArrayList<Integer> list = new ArrayList<>();
        //通过对象获取字节码对象
Class<? extends ArrayList> aClass = list.getClass();
        //反射获取add ()
Method method = aClass.getMethod("add", Object.class);
        method.invoke(list,"mlj");
        method.invoke(list, "qq");
        method.invoke(list, 'h');
        System.out.println(list);
        //输出 [mlj, qq, h]

//        分析:反射直接跳过了泛型Integer,list存储String类型值;
//        结论:泛型只是给编译器看的,实际的单列集合,双列集合可以交叉存储任意引用值
}
 

 

反射案例: 实现克隆案例

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

//通过反射实现克隆
public class ClassClone {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Person p1=new Person(10,"徐旺骑");
        Person p2=(Person) clone(p1);
        System.out.println(p2.age+p2.name);
    }
    //实现Clone方法
    public static Object clone(Object obj) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
    {
        //1.获取字节码对象
        Class<Object> clz=(Class<Object>) obj.getClass();
        //2.获取实例对象 ---新对象
        //2.1获取构造方法---保证一定能拿到构造方法
        Constructor c=clz.getDeclaredConstructors()[0];
        //返回拿到的这个构造方法上所有的参数类型的字节码对象
        Class[] cs    =c.getParameterTypes();
        //Object的数组,这个是为了给构造方法给值
        Object[]os=new Object[cs.length];
        //遍历参数数组
        for(int i=0;i<cs.length;i++)
        {
            //判断参数是否是基本类型
            if(cs[i].isPrimitive())
            {
                if(cs[i]==byte.class||cs[i]==short.class||cs[i]==int.class)
                {
                    os[i]=0;
                }
                if(cs[i]==char.class)
                {
                    os[i]='\u0000';
                }
                if(cs[i]==float.class)
                {
                    os[i]=0.0f;
                }
                if(cs[i]==double.class)
                {
                    os[i]=0.0d;
                }
                if(cs[i]==boolean.class)
                {
                    os[i]=false;
                }
                
            }
            else {
                os[i]=null;
            }
        }
        //传值--构造实例对象--新对象
        Object o1=c.newInstance(os);
        //3.获取原对象的所有属性
        Field[] fs=clz.getDeclaredFields();
        //4.把原对象的属性给新对象
        for(Field f:fs)
        {
            //暴力破解
            f.setAccessible(true);
            //获取原对象的属性
            Object o2=f.get(obj); //原对象的每个属性
            //所有属性赋值给新对象
            f.set(o1, o2);

        }
        //5.返回新对象
        return o1;
    }
}
class Person{
    int age;
    String name;
    public Person(int age,String name) {
        this.age=age;
        this.name=name;
    }
}

 

package cn.tedu.reflect;

public class ClassDemo6 {
    
    public static void main(String[] args) {
        //枚举类的字节码对象
    /*    Class<Demo> clz=Demo.class;
        //返回枚举常量
        Demo[] ds=clz.getEnumConstants();
        for (Demo demo : ds) {
            System.out.println(demo); //ABCD
        }*/
        
        //
        Class<String> clz=String.class;
        //没有枚举常量是返回一个null
        String[] ss=clz.getEnumConstants();
        
        //返回的是实现的接口
        Class[] cs=clz.getInterfaces();
        for (Class class1 : cs) {
            System.out.println(class1);
            //interface java.io.Serializable
            //interface java.lang.Comparable
            //interface java.lang.CharSequence
        }
        
        //字节码对象对应类全路径名
        System.out.println(clz.getName());//MethodDemo.java
        
        //返回字节码对象对应类的包的信息
        System.out.println(clz.getPackage());//package java.lang, Java Platform API Specification, version 1.8
        
        //字节码对象对应类的类名
        System.out.println(clz.getSimpleName());//String
        
        //得到父类的字节码对象
        System.out.println(clz.getSuperclass());//class java.lang.Object
    }

}


//
enum Demo{
    A,B,C,D;//枚举常量---对象
}
    //获取字节码对象
        Class<String> clz=String.class;
        //可以获取指定属性
        Field f=clz.getDeclaredField("serialVersionUID");
        //返回属性的数据类型
        System.out.println(f.getType()); //long
public class MethodDemo {
    
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        //
        Class<String> clz=String.class;
        //获取指定方法
        /*Method m=clz.getDeclaredMethod
                ("getBytes", String.class);*/
        Method m=clz.getDeclaredMethod
                ("getBytes", Charset.class);
        /*//返回的是编译时异常
        Class[] cs=m.getExceptionTypes();
        for (Class class1 : cs) {
            System.out.println(class1);
        }*/
        
        //获取参数类型的字节码放到一个数组
        Class[] cs=m.getParameterTypes();
        for (Class class1 : cs) {
            System.out.println(class1);
        }
    }

}

 

posted @ 2019-07-29 12:28  三十六烦恼风x  阅读(155)  评论(0编辑  收藏  举报