反射

反射   重要的底层技术  开发工具和框架 1.2时就出现了
一、基本概念
(1)java类 用于描述一类事物的共性,只负责告诉我们这个类有什么属性,没有什么属性,至于属性的值是由实例对象来决定的。
(2)类对象和类的对象:类对象:类加载的产物,记录了类的信息。这个类是Class.
    1、补充:
         这就能过解释为什么强转的时候,编译器会知道,一个类的父类和子类是什么,因为信息被一个类记录了,根据信息,编译器就能过限制很多写法。
         接口在强转中比较特殊,是因为如果是一个接口的话,编译器可能不会去找它的继承关系,都认为有类继承于它或者它实现别的类。
         例子: class Student{}
                interface snior extends Student{}//编译不通过 因为是接口 所以接口只能继承接口 不能继承普通类
          这个波重要:这就是可以从技术上解释这个规范,剩下的就是从生活中解释规范
    2、语法:
        Class cls = 字节码;
        可以解释编译的情况,编译的时候是会扫描字节码文件,如果不存在会报错。而负责这个的是系统组件ClassLoader,即当遇到一个未知的类时(系统没有,之前也没加载的)会生成字节码,然后后面的使用,才能拿到类的信息。
        所以字节码文件存的是一个类的信息。 Class会创建一个引用指向它。
(3)获得类对象的方式:
1)  类名.class   直接获得类对象   还可以获得基本类型的类对象  double.class
2)  类的对象.getClass()  获得对应的类对象
3)  Class.forName("类的全名")  通过类名获得类对象 两个意思:没有加载的要加载 加载的我要拿到
 
(4)常见方法
newInstance(): 通过类对象 创建类的对象 (调用类的无参构造方法)
    代替了构造方法中的newInstance 简化了步骤
    源代码也揭示了反射比较耗时,影响效率。
invoke():来自Method方法  对某对象调用该方法
Class.isPrimitive int.class = Integer.TYPE;这个对象是否是基本类型(原始类型)
int[].Class.isPrimitive 是对数组的类型判断 不是对数组的中的元素类型判断 所以这个方法的结果不是原始类型 因为数组是对象类型
int[].Class.isArray 判定原类型是否是数组
(5)9个预定义的的Class文件 8种基本类型和void类型
只要程序中出现的类型,都有各自的Class实例对象。例如int[],void
(6)反射
1、定义:将java类中的各种成分映射成相应的java类
2、应用:
    (1)得到一个类的构造方法
            String className = "java.lang.String";
            Constructor[] constructors = Class.forName(className).getConstructors();
            Constructor constructor = Class.forName(className).getConstructor(StringBuffer.class);
            System.out.println(constructors.length);
            System.out.println(constructor.toString());
            Constructor constructor = Class.forName(className).getConstructor(2);//这句代码执行不通过 由于构造方法是并列的,不能按照顺序取出构造方法。
            getConstructor()方法的参数列表形式:Class<?> parameterType
            getConstructor(StringBuffer.class,int.class);//编译不通过,要求可变的参数的类型都是相同的
            //构造的方法的newInstance()
            String className = "java.lang.String";
            Constructor constructor = Class.forName(className)
            .getConstructor(StringBuffer.class);//选择StringBuffer
            //构造方法
            String s = (String) constructor.newInstance(
                    new StringBuffer("a"));//用这个对象的时候要
            //传一个这个StringBuffer参数
            //不好的地方 程序猿可能不知道constructor的所属是Data还是String
            //的构造方法
    (2)得到成员变量
    class ReflectPoint{
    private int x;
    public int y;
    public ReflectPoint(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
    
}
    public static void main(String[] args) throws Exception{
        /*ReflectPoint rflctPoint = new ReflectPoint(1,2);
        //得到字节码,拿到成员变量的信息
        Class cls = rflctPoint.getClass();
        //拿到要求的、特定的成员变量的信息
        Field fld = cls.getField("y");
        //根据拿到的信息,实例化一个信息
        System.out.println(fld.get(rflctPoint));*/
        //暴力反射访问私有
        /*ReflectPoint r = new ReflectPoint(4,5);
        Class cls = r.getClass();
        Field fld = cls.getDeclaredField("x");//能够看到了 但拿不到
        fld.setAccessible(true);//我要拿到它
        System.out.println(fld.get(r));*///拿到了
        
    }
    //例子
    public class practice {
    public static void main(String[] args) throws Exception{        
        ReflectPoint f = new ReflectPoint(1,2);
        changeValue(f);
        System.out.println(f);
    }
    public static void changeValue (Object obj)throws Exception{
        Field[] flds = obj.getClass().getDeclaredFields();
        //System.out.println(flds.length);
        for(Field fld:flds){
            //System.out.println(fld.getType()==String.class);
            if(fld.getType()==String.class){
                String oldValue =(String)fld.get(obj);
                String newValue = oldValue.replace('b', '2');
                System.out.println(newValue);
                fld.set(obj, newValue);
            }
        }
    }
}

class ReflectPoint{
    private int x;
    public int y;
    public String s1 = "abc";
    public String s2 = "bcd";
    public String s3 = "cde";
    public ReflectPoint(int x, int y) {
        //super();
        this.x = x;
        this.y = y;
    }
    @Override
    public String toString() {
        return "ReflectPoint [s1=" + s1 + ", s2=" + s2 + ", s3=" + s3 + ", x="
                + x + ", y=" + y + "]";
    }
    
}
    (3)方法
        //得到String中CahrAt的方法
        Method mthd = String.class.getMethod("charAt", int.class);
        String s = "abc";
        //再得到特定对象的CharAt的方法
        System.out.println(mthd.invoke(s,1));//s如果是一个null表示调用的是静态方法
    (4)对接收数组参数的成员方法进行反射
    public class practice {
    public static void main(String[] args) throws Exception{        
        //根据用户给我的类,我来调用它里面的main方法
        //找到用户给我类的Class信息
        String className = "test.Test";
        Class cls = Class.forName(className);
        //根据给的信息,找到需要的方法
        Method mtd = cls.getMethod("main", String[].class);        
        //调用该方法
        mtd.invoke(null, (Object)new String[]{"aaa","bbb","ccc"});
        //mtd.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}});
        //mtd.invoke(null, new String[]{"aaa","bbb","ccc"});//这个方法不会出结果,因为为了兼容5.0一下版本,会将这个数组打散成三个元素,而main中的参数要求是一个对象类型 的单个元素。前两种方法是解决办法。
    }

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

其中的main方法不是static
public static void main(String[] args) throws Exception{        
        //对接收数组参数的成员方法进行反射
        //根据用户给我的类,我来调用它里面的main方法
        //找到用户给我类的Class信息
        String className = "test.Test";
        Class cls = Class.forName(className);
        //根据给的信息,找到需要的方法
        Object obj = cls.newInstance();
        Method mtd = cls.getMethod("main", String[].class);        
        //调用该方法
        mtd.invoke(obj, (Object)new String[]{"aaa","bbb","ccc"});
        //mtd.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}});
        //mtd.invoke(null, new String[]{"aaa","bbb","ccc"});//这个方法不会出结果,因为为了兼容5.0一下版本,会将这个数组打散成三个元素,而main中的参数要求是一个对象类型 的单个元素。前两种方法是解决办法。
    
    class Test{
    public  void main(String[] args){
        for(String arg:args){
            System.out.println(arg);
        }
    }
}
    (5)数组与Object的关系及反射类型
        数组的元素类型和纬度相同,那么这些数组的Class也相同
        例子:int[] a1 = new int[3];
        int[] a2 = new int[2];
        int[][] a3 = new int[3][4];
        String[] a4 = new String[3];
        System.out.println(a1.getClass() == a2.getClass());
        //System.out.println(a1.getClass() == a3.getClass());
        //System.out.println(a1.getClass() == a4.getClass());
        System.out.println(a1.getClass().getName());
        System.out.println(a3.getClass().getName());
        System.out.println(a4.getClass().getName());
        System.out.println(a1.getClass().getSuperclass().getName());
        System.out.println(a1.getClass().getSuperclass().getName());
        Object o1 = a1;
        Object o2 = a3;
        Object o3 = a4;
        //Object[] o3 = a1;//报错
        Object[] o5 = a3;
        Object[] o6 = a4;
        //这个地方是比较奇特的。。。。用数组对象的引用指向一个数组对象 而不是用一个对象引用指向数组对象
        看这个问题的应用:
            //这个地方的应用可以解释这个下面现象,当a1是int时,不会使用4.0的方式
        //就是参数不是数组。5.0参数可以变化 String就可以打印出来
        System.out.println(Arrays.asList(a1));
        System.out.println(Arrays.asList(a4));
        System.out.println(Arrays.asList(a3));
    (6)数组的反射应用
    用反射的方式操作数组,例如:我们常要遍历数组,或者更改某一个数组元素的值,或者取出某个特定下标的元素。
    //数组的反射应用
    public void printObject(Object obj){
        Class cls = obj.getClass();
        if(cls.isArray()){//判断是否数组
            //遍历数组
            //Array利用反射操作数组的工具类
            int length = Array.getLength(obj);
            for(int i=0;i<length;i++){
                System.out.println(Array.get(obj, i));
            }
        }else{
            System.out.println(obj);
        }
    }
    
    利用反射得到数组的类型的一个问题:
    Object[] objs = new Object[]{"1",1};
    类型是什么?
        Object[] objs = new Object[]{"1",1};
        Object obj = objs[0].getClass().getName();
        //String
        Object obj = objs[1].getClass().getName();
        //Integer
        System.out.println(obj);
    数组之前所学说,是同类型的元素放到一起,现在看,这个就有问题了。
    (7)框架的概念及用反射技术开发框架的原理
    我们使用的类有两种:我们使用别人的:工具类。别人使用我们的:框架。
    框架要解决的问题:我们写的框架,可以调用以后人们写的类。
    1、加载配置文件
    2、生成实例newInstance()
package test;

import java.util.*;
import java.io.*;
public class TestReflection {
    public void reflectionApp() throws Exception{
        InputStream ips = new FileInputStream("config.propertis");
        Properties props = new Properties();
        props.load(ips);
        ips.close();
        String className = props.getProperty("className");
        
        Collection<ReflectionPoint> collections = (Collection)Class.forName(className).newInstance();
        ReflectionPoint rfctp1 =new ReflectionPoint(3,3);
        ReflectionPoint rfctp2 =new ReflectionPoint(3,4);
        ReflectionPoint rfctp3 =new ReflectionPoint(3,5);
        ReflectionPoint rfctp4 =new ReflectionPoint(3,3);
        collections.add(rfctp1);
        collections.add(rfctp2);
        collections.add(rfctp3);
        collections.add(rfctp4);
        collections.add(rfctp1);
        System.out.println("ArrayList");
        for(ReflectionPoint rfctp:collections){
            System.out.println(rfctp);
        }
        collections = new HashSet<ReflectionPoint>();
        collections.add(rfctp1);
        collections.add(rfctp2);
        collections.add(rfctp3);
        collections.add(rfctp4);
        collections.add(rfctp1);
        System.out.println("HashSet");
        for(ReflectionPoint rfctp:collections){
            System.out.println(rfctp);
        }
    }
}

class ReflectionPoint{
    //属性
    private double x;
    private double y;
    //构造方法
    public ReflectionPoint(){}
    public ReflectionPoint(double x,double y){
        this.x = x;
        this.y = y;
    }
    //set和get方法
    public double getX(){return x;}
    public double getY(){return y;}
    public void setX(double x){this.x = x;}
    public void getY(double y){this.y = y;}
    
    //toString
    public String toString(){
        return "X = " + x + " Y = " + y;
    }
    
    //equals
    public boolean equals(Object o){
        /*if(this == o) return true;
        if(o == null) return false;
        if(this.getClass()!=o.getClass())return false;
        ReflectionPoint rf = (ReflectionPoint)o;
        if(rf.getX()!=x)return false;
        if(rf.getY()!=y)return false;
        if(rf.getX()!=x)return false;
        if(rf.getY()!=y)return false;*/
        System.out.println(" equals "+x+"+"+y);
        return true;
    }
    
    //hashcode
    public int hashCode(){
        return (int)x;
    }
}
(8)用类加载器的方法管理资源和配置文件
 配置文件存放路径:当前工作路径。
 解决配置文件存放路径遇到的问题:用户将信息存放在配置文件中,程序是通过get配置文件信息的方式来找到配置文件。简单来说就是:配置文件管理配置文件。
 例子:得到项目的绝对路径之后找到项目中的配置文件。即:绝对路径+相对路径。
 应用:将配置文件放到统一的目录中。
 
 类加载器:可以加载类也可以加载类的配置文件信息。
ClassLoader.getResourceAsStream(String ProjectPath);
ProjectPath = "it\cast\day1\config.properties";
Class.getResourceAsStream(String ProjectParh);
ProjectPath = "config.properties";知道是在我的包里的。
ProjectPath = "it\cast\day1\config.properties";也可以用这个路径,我会判断是否是在我的包里。 框架中都是将配置文件放到ClassPath中,就是因为内部的机制是使用类加载器加载的配置文件


   
发布了33 篇原创文章 · 获赞 1 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章