java-反射

来源:互联网 发布:基本款手提包 知乎 编辑:程序博客网 时间:2024/06/07 10:23

一.反射
反射就是把java类中的各个成分映射成相应的java类。
各个成分所对应的对象:Field Method Contructor Package
二.class类
java程序中的各个Java类属于同一个事务,描述这类事务java类的名字叫Class
字节码:
先将编译后的字节码加载到内存到,然后才能创建一个个对象。
每一个类创建一份字节码,
Person p1=new Person();

    Pair<String> pair=new Pair<>();    System.out.println(pair.getClass());    Class.forName("day07.Pair");

Class.forName的作用是返回字节码,一种是字节码已经被加载过,另一种还没有加载,使用类加载器进行加载到虚拟机中。
获取类名的字节码:
类名.class;
对象.getClass();new Date().getClass()
Class.forName(“类名”),例如,Class.forName(“java.util.Date”)//反射经常用,类加载之前

public class Reflect {public static void main(String[] args) throws ClassNotFoundException {    String str1="abc";    Class class1=str1.getClass();//对象获取class的方法    Class class2=String.class;//类型获取class的方法    Class class3=Class.forName("java.lang.String");    System.out.println(class1==class2);    System.out.println(class2==class3);}}

原始的基本类型:八大基本类型

public class Reflect {public static void main(String[] args) throws ClassNotFoundException {    String str1="abc";    Class class1=str1.getClass();//对象获取class的方法    Class class2=String.class;//类型获取class的方法    Class class3=Class.forName("java.lang.String");    System.out.println(class1==class2);    System.out.println(class2==class3);    //确定指定 类对象代表一个原始类型。    System.out.println(class1.isPrimitive());//isPrimitive()确定指定 类对象代表一个原始类型(8大基本类型)。    System.out.println(int.class.isPrimitive());//是原始的基本类型    System.out.println(int.class==Integer.class);//两个不相等    System.out.println(int.class==Integer.TYPE);//TYPE类代表原始类型的实例 int。    System.out.println(int[].class.isPrimitive());//不是原始的基本类型    System.out.println(int[].class.isArray());//判断是否为数组}}

结果

truetruefalsetruefalsetruefalsetrue

三.constructor类
constructor类:代表某个类中的构造方法
getConstructors():得到所有的构造方法
getConstructor():得到一个构造方法
四.成员变量的映射(Field类)
Field类代表某个类中的一个成员变量

Reflect_Point类public class Reflect_Point {private int x;public  int y;public Reflect_Point(int x, int y) {    super();    this.x = x;    this.y = y;}}Reflect_Test类import java.lang.reflect.Field;public class Reflect_Test {    public static void main(String[] args) throws ReflectiveOperationException, Exception {        Reflect_Point r1=new Reflect_Point(3, 5);        Field f1=r1.getClass().getField("y");//getclass获取字节码,getFiled获取字段        //f1不是对象身上的变量,而是类上的,用它取对象上对应的值        System.out.println(f1.get(r1));/*      Field f2=r1.getClass().getField("x");        System.out.println(f1.get(r1));//此处取不出来,因为x为私有的,不可以取*/      Field f3=r1.getClass().getDeclaredField("x");//能访问,但不能取出来        f3.setAccessible(true);//设置可以访问,暴力反射        System.out.println(f3.get(r1));    }}

练习:将任意一个对象中的所有String类型的成员变量所对用的字符串的字符串内容中的”b”改成”a”。

Reflect_Point实体类public class Reflect_Point {        private int x;        public int y;        public String str1="ball";        public String str2="basketball";        public String str3="itcast";    @Override    public String toString() {    // TODO Auto-generated method stub        return str1+":"+str2+":"+str3;    }}Reflect_Point_Test类package day13;import java.lang.reflect.Field;public class Reflect_Point_Test {    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {        // TODO Auto-generated method stub        Reflect_Point rp =new Reflect_Point();        changeStringValue(rp);        System.out.println(rp);    }    private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException {        // TODO Auto-generated method stub            Field[] fields=obj.getClass().getFields();//获取字段            for(Field field:fields)            {                //field.getType();//获取字段的类型                //field.getType().equals(String.class)                //字节码的比较实用“==”                if(field.getType()==String.class){                    String oldValue=(String)field.get(obj);//获取String类型的值                    String newValue=oldValue.replace('b', 'a');                    field.set(obj, newValue);//设置新值                }            }    }}aall:aasketaall:itcast

五.成员方法的反射(Method类)

得到类中的某一个方法:例如:Method charAt=Class.forName("java.lang.string").getMethod("charAt",int.class);调用方法:    通常方式:system.out.println(str.charAt(1))    反射方式:system.out.println(charAt.invoke(str,1))

案例

import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Re_Method {public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {    String str1="abc";//String类名.class    //目的:str1.charAt(1)    //string的数组    Method method=String.class.getMethod("charAt", int.class);    System.out.println(method.invoke(str1, 1));//  System.out.println(method.invoke(str1, new Object[](2)));//1.4的版本中使用,结果是c}}

练习:用反射方式执行某个类中的 main方法
1.使用静态的方式去调用

package day13;public class Reflect_learning {    public static void main(String[] args) {        // TODO Auto-generated method stub        TestArgument.mian(new String[]{"1111","22222","333"});//静态方法调用main方法    }}class TestArgument{    public static void mian(String[] args)    {        for(String arg:args)        {            System.out.println(arg);        }    }}

2.使用反射的方式去调用(不知道类的名字)

目的:用反射的原因是不知道执行哪一个类问题:    启动java程序的main方法的参数是一个字符串的数组,即public static void main(String[] args),通过反射方式调用这个Main方法时,    如何为Invoke调用方法传递参数(jdk1.5以后:整个数组是一个参数)解决办法:----------mainMethod.invoke(null,new Object[]{new String[]{"xxxx"}});----------mainMethod.invoke(null,(Object)new String[]{"xxxx"});//编译器会特殊处理,编译时不把参数当做数组看待,也就不会数组打散成若干个参数了。数组下标越界测试代码

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

public class Reflect_learning {

public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {    // TODO Auto-generated method stub    //TestArgument.main(new String[]{"1111","22222","333"});//静态方法调用main方法    String startClassName=args[0];    Method mainMethod=Class.forName(startClassName).getMethod("main", String[].class);    //mainMethod.invoke(null, new String[]{"1111","22222","333"});//(test2)静态的方法不需要传递对象,所以为null    //原因是:传递的参数不能对称,打包成object    //mainMethod.invoke(null, new Object[]{new String[]{"1111","22222","333"}});//(test3)此处就不会出现错误    /**     * 结果     * 1111        22222        333     */    mainMethod.invoke(null, (Object)new String[]{"1111","22222","333"});//(test4)强制转换}

}
class TestArgument{
public static void main(String[] args)
{
for(String arg:args)
{
System.out.println(arg);
}
}
}

对TestArgument类按键F2,复制类名;同时在该类下右击选择Run As-->Run configures-->Arguments(复制上面的类名)上面的步骤可以得出字节码,然后可以得出main方法出错:            Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)                at java.lang.reflect.Method.invoke(Method.java:483)                at day13.Reflect_learning.main(Reflect_learning.java:13)

六.数组的反射
1.定义:
具有相同的维度和元素类型的数组属于同一个类型,即具有相同的class实例对象
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
public 类

数组与Object的关系及其反射类型:public class Re_Array_Test {    public static void main(String[] args) {        // TODO Auto-generated method stub        int []a1=new int[3];        int []a2=new int[4];        int [][]a3=new int[2][3];        String []a4=new String[5];        System.out.println(a1.getClass().getName());//返回的是[I,查看class的getName方法        System.out.println(a1.getClass()==a2.getClass());        //具有相同的维度和元素类型的数组属于同一个类型,即具有相同的class实例对象//      System.out.println(a1.getClass()==a3.getClass());//编译器直接报错//      System.out.println(a1.getClass()==a4.getClass());//编译器直接报错        System.out.println(a3.getClass().getName());//[[I        System.out.println(a4.getClass().getName());//[Ljava.lang.String;        System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object        System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object        System.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object        Object ob1=a1;        Object ob2=a4;//自动装箱//      Object[] ob3=a1;//此处不可以,基本类型的数组不能转换成object        Object[] ob4=a3;//object中存放int[]的一维数组可以        Object[] ob5=a4;    }}

2.数组反射的应用
a.反射的方式求:数组的遍历

Arrays.asList()方法用于处理int()和String[]时的差异import java.util.Arrays;public class Re_Array_Test {    public static void main(String[] args) {        // TODO Auto-generated method stub        int []a1=new int[]{1,2,3};        int []a2=new int[4];        int [][]a3=new int[2][3];        String []a4=new String[]{"a","b","c"};        Object ob1=a1;        Object ob2=a4;//自动装箱//      Object[] ob3=a1;//此处不可以,基本类型的数组不能转换成object        Object[] ob4=a3;//object中存放int[]的一维数组可以        Object[] ob5=a4;        System.out.println(a1);//不能直接打印数组,返回hashcode值        System.out.println(a4);//不能直接打印数组,返回hashcode值        //Arrays工具类asList方法返回由指定数组支持的一个固定大小的列表。        //(改变返回列表“写”到数组。)该方法作为基于阵列和基于集合API之间的桥梁,结合 Collection.toArray()。返回的列表是可序列化的实现 RandomAccess。        System.out.println(Arrays.asList(a1));//[[I@15db9742]        //原因是int类型不可以转换成object类型,只能转换成Integer        System.out.println(Arrays.asList(a4));//[a, b, c]    }}

b.反射的方式求数组的值和大小

Array工具类用于完成对数组的反射操作。怎么得到数组的类型?(暂时不能完成):Object[] a=new Object[]("a",1)a[0].getClass().getName();//此处只能选取单个的反射
public class Re_Array_Test {    public static void main(String[] args) {        // TODO Auto-generated method stub    int []a1=new int[]{1,2,3};        int []a2=new int[4];        int [][]a3=new int[2][3];        String []a4=new String[]{"a","b","c"};         printObject(a4);//数组拆开         printObject("xys");//数组为拆开        }    private static void printObject(Object obj) {        // TODO Auto-generated method stub        Class class1=obj.getClass();        if(class1.isArray())//判断是否object为数组        {            int len=Array.getLength(obj);//获取obj的长度            for(int i=0;i<len;i++)            {                System.out.println(Array.get(obj, i));//获取对象            }        }else{            System.out.println(obj);        }    }}

七.反射的应用
ArrayList_HashSet的比较及Hashcode分析
这里写图片描述

这里写图片描述
八、反射的作用–框架的实现
反射的作用->实现框架功能
—–框架与框架要解决的核心问题
—–框架与工具类的区别(工具类被用户使用,而框架则是调用用户提供的类)
配置文件的配写
这里写图片描述
实现的步骤:

——加载配置文件(创建对象时尽量使用父类或者接口)

Reflect_Point类public class Reflect_Point {        private int x;        public int y;        public String str1="ball";        public String str2="basketball";        public String str3="itcast";    public Reflect_Point() {            super();            // TODO Auto-generated constructor stub        }    public Reflect_Point(int x, int y) {        super();        this.x = x;        this.y = y;    }    @Override    public String toString() {    // TODO Auto-generated method stub        return str1+":"+str2+":"+str3;    }}Reflect_Point_Test2类package day13;import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class Reflect_Point_Test2 {    public static void main(String[] args) throws Exception {        // TODO Auto-generated method stub        InputStream ips =new FileInputStream("config.properties");//        Properties props =new Properties();//存放的值相当于hashmap(存放的是键值对)        props.load(ips);        ips.close();//会有内存泄露,此处关闭的是系统内存。不是本对象(虚拟机中还在运行)        String className=props.getProperty("className");        Collection collections=(Collection)Class.forName(className).newInstance();        Reflect_Point pt1=new Reflect_Point(3,3);        Reflect_Point pt2=new Reflect_Point(5,5);        Reflect_Point pt3=new Reflect_Point(3,3);        collections.add(pt1);        collections.add(pt2);        collections.add(pt3);        collections.add(pt1);        System.out.println(collections.size());    }}config.properties//放在整个工程里面(而不是源程序的包)className=java.util.ArrayList

实际运行中修改上面的操作形式
用类加载器的方式管理资源和配置文件
getRealPath()//外部地址–内部地址
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。

Reflect_Point类同上,此处的config.properties存放的位置不同import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class Reflect_Point_Test2 {    public static void main(String[] args) throws Exception {        // TODO Auto-generated method stub        //一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的        //InputStream ips =new FileInputStream("config.properties");        //此处使用类加载器        //InputStream ips=Reflect_Point_Test2.class.getClassLoader().getResourceAsStream("day13/config.properties");        //day13/config.properties:此处不能再开始处加/(此处需要加载包)        //        InputStream ips=Reflect_Point_Test2.class.getResourceAsStream("config.properties");        Properties props =new Properties();//存放的值相当于hashmap(存放的是键值对)        props.load(ips);        ips.close();//会有内存泄露,此处关闭的是系统内存。不是本对象(虚拟机中还在运行)        String className=props.getProperty("className");        Collection collections=(Collection)Class.forName(className).newInstance();        Reflect_Point pt1=new Reflect_Point(3,3);        Reflect_Point pt2=new Reflect_Point(5,5);        Reflect_Point pt3=new Reflect_Point(3,3);        collections.add(pt1);        collections.add(pt2);        collections.add(pt3);        collections.add(pt1);        System.out.println(collections.size());    }}
原创粉丝点击