java-反射

一.反射
反射就是把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());//判断是否为数组
}
}

结果

true
true
false
true
false
true
false
true

三.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());

    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值