天天看点

黑马程序员——Java基础——反射反射

反射

透彻分析反射的基础_Class类

Java类用于描述一类事物的共性、描述该类应该具有的属性,而属性具体的值则由这个类的实例对象来确定

Class类是描述Java程序中的各个Java类的类型,通过class可以得到类方方面面的信息

Method[] ——getMethods();

String——getName();

Package——getPackage();

Class——getInterfaces();

字节码:类的代码编译成的二进制代码

Class cls = 字节码;

得到字节码的三种方式

public class ReflectTest {
    public static void main(String[] args) throws Exception{
        String str = "123";
        Class class1 = str.getClass();//字节码
        Class class2 = String.class;//字节码
        Class class3 = Class.forName("java.lang.String");//字节码
    }
}
           

九个预定义Class实例对象

八个基本类型和void

public class ReflectTest {
    public static void main(String[] args){
        Class class = String.class;//字节码

        sop(class.isPrimitive());//class对象的类型是否是几种预定义类型
        sop(int.class.isPrimitive);

        sop(int.class == Integer.class);//False
        sop(int.class == Integer.TYPE);//True,Integer.TYPE表示包装类中被包装类型的字节码,九种预制类型中有这个属性
}
    public static void sop(Object obj){
        System.out.println(obj);
    }
}
           

数字类型Class实例对象

class TestReflectTest{
    public static void main(String[] args){
        System.out.println(int[].class.isPrimitive);//False,这个是数组类型
        System.out.println(int[].class.isArray);
    }
}
           

总结:只要是在源程序中出现的类型,都有各自的Class类型实例对象

理解反射的概念

反射就是把Java类型中的每一个成分(包、方法、字段等)映射(解析成)相应的类型

通过写程序可以得到Java类型中的各个成分所对应的类的对象

构造方法的反射应用

得到一个类中的构造方法

public class ConstructorReflect {
    public static void main(String[] args) throws Exception{
        //得到类中的所有构造方法
        Constructor[] cons = 
                            Class.forName("java.lang.String").getConstructors();
        //根据参数得到类中一个构造方法
        Constructor con = 
                            Class.forName("java.lang.String").getConstructor(String.class);
    }
}
           

通过反射实现创建对象

public class ConstructorReflect {
    public static void main(String[] args) throws Exception{
        //String str = new String(new StringBuffer("abc"));
        Class cls = String.class
        Constructor con = cls.getConstructor(StringBuffer.class);
        String str = (String)con.newInstance(new StringBuffer("abc"));
        System.out.println(str.charAt());
    }
}
           

Class.newInstance()方法

在创建class对象的时候,调用对象的newInstance方法,会将无参的函数缓存起来,方便再次调用无参构造方法

public class ConstructorReflect {
    public static void main(String[] args) throws Exception{
        Class clsStud = Student.class;
        //当class类对象调用newInstance方法的时候,会直接调用无参构造方法,并且缓存方便调用
        Student s1 = (Student)clsStud.newInstance();

        //要调用有参数的构造函数,则需要通过反射的原理
        Constructor con = clsStud.getConstructor(String.class, int.class);
        Student s2 = (Student)con.newInstance(new String("zhangsan"), );
        System.out.println(con.toString());
    }
}
class Student{
    private String name;
    private int age;
    public Student(){
        System.out.println("I`M A STUDENT");
    }
    public Student(String name, int age){
        this.name = name;
        this.age = age;
        System.out.println(name + "::" + age);
    }
}
           

总结:反射会导致程序性能下降

成员变量的反射

public class ReflectTest {
    public static void main(String[] args) throws Exception{
        ReflectPoint pt = new ReflectPoint(,);

        //fieldY不是对象里的变量,而是将字节码里面的某个变量赋给它
        Field fieldY = ReflectPoint.class.getField("y");
        //Field fieldY = pt1.getClass().getField("y"));这句话和上面语句是一个意思
        sop(fieldY.get(pt));

        //x成员变量是私有的,对getField()方法不可见
        //Field FieldX = pt.getClass().getField("x");此方法对私有变量无效
        //用getDeclaredField()方法可以读取到私有成员变量,但是不能使用
        Field fieldX = ReflectPoint.class.getDeclaredField("x");
        //需要通过setAccessible()方法进行设置,暴力反射
        fieldX.setAccessible(true);
        sop(fieldX.get(pt));
    }
    public class ReflectPoint {
        private int x;
        public int y;

        public ReflectPoint(int x, int y) {
            super();
            this.x = x;
            this.y = y;
        }
    }
    public static void sop(Object obj){
        System.out.println(obj);
    }
}
           

反射的综合案例

字段的反射:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”

public class ReflectTransB {
    public static void main(String[] args) throws Exception{
        ReflectPoint pt = new ReflectPoint();
        changeStringValue(pt);
        System.out.println(pt.toString());
    }
    public static void changeStringValue(Object obj) throws Exception{
        Field[] fields = obj.getClass().getFields();
        for(Field temp: fields){
            //字节码只有一份,用“==”比较更好
            if(temp.getType()==String.class){
                String oldValue = (String)temp.get(obj);
                //replave(oleChar, newChar);
                String newValue = oldValue.replace('b', 'a');
                temp.set(obj, newValue);
            }
        }
    }
    class ReflectPoint {
        public String str1 = "ball";
        public String str2 = "basketball";
        public String str3 = "nothave";
        public String toString() {
            return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="
                                + str3 + "]";
        }
    }
}
           

成员方法的反射

public class ReflectTest(){
    public static void main(String[] args){
        String str = "abc";
        //通常方式
        System.out.println(str.charAt());
        //反射方式
        Method methodCharAt = String.class.getMethod("charAt", int.class);
        System.out.println(methodCharAt.invoke(str, ));//invoke()调用
        //在调用静态方法的时候,是不需要穿参数的,用null代替
        //System.out.println(methodCharAt.invoke(null, 1));
        //兼容1.4之前的版本问题
        System.out.println(methodCharAt.invoke(str, new Object[]{}));
    }
}
           

对接受数组参数的成员方法进行反射

写一个程序能够根据用户提供的类名,去执行该类中的main方法

public class ReflectTest {
    public static void main(String[] args) throws Exception{
        //通常调用方法
        TestArguments.main(new String[]{"111", "222", "333"});
        System.out.println("**************************************");
        //为什么要用反射的方式调用
        //String startClassName = args[0];启动的时候,传入的args[]数据中要含有要运行类的名称
        String startClassName = "TestReflect.TestArguments";
        Method mainMethod = Class.forName(startClassName).getMethod("main", String[].class);
        //为了兼容JDK1.4版本,传入的参数new String[]{"111", "222", "333"}会被拆成三个参数
        //所以在外面在包一个Object数组
        //mainMethod.invoke(null, new Object[]{new String[]{"111", "222", "333"}});
        mainMethod.invoke(null, (Object)new String[]{"111", "222", "333"});
    }
}
class TestArguments{
    public static void main(String[] args){
        for(String arg: args){
            ReflectTest.sop(arg);
        }
    }
}
           

数据与Object关系及其反射类型

具有相同类型的和相同维度的数据的Class字节码文件相同

public class ReflectArray {
    public static void main(String[] args){
        int[] a1 = new int[];
        int[] a2 = new int[];
        int[][] a3 =  new int[][];
        String[] a4 = new String[];
        sop(a1.getClass() == a2.getClass());
        sop(a1.getClass().getName());
        sop(a1.getClass().equals(a3.getClass()));
        sop(a1.getClass().equals(a4.getClass()));
        //以下三条显示为:“java.lang.Object”
        sop(a1.getClass().getSuperclass().getName());
        sop(a3.getClass().getSuperclass().getName());
        sop(a4.getClass().getSuperclass().getName());
        Object aObj1 = a1;
        Object aObj2 = a4;
        //int[]中装的是基本类型int,基本类型的父类不是Object
        //Object[] aObj3 = a1;
        //二维数据int[][]可以看做是装着int数组的数组,int数组的父类是Object,所以二维数据可以放入Object[]中
        Object[] aObj4 = a3;
        Object[] aObj5 = a4;
        sop("###########################################");
        int[] arri = new int[]{,,};
        String[] arrs = new String[]{"abc", "efd", "hij"};
        sop(arri);
        sop(arrs);
        sop(Arrays.asList(arri));
        sop(Arrays.asList(arrs));
        /*
        [[email protected]
        [Ljava.lang.String;@2afbb5f5
        [[[email protected]]
        [abc, efd, hij]
        这个就是解释了int[]中装的是基本类型int,基本类型int的父类不是Object,
        所以转换的时候将int[]作为一个元素存入list中
        */
    }
    public static void sop(Object obj){
        System.out.println(obj);
    }
}
           

数组的反射应用

public class ReflectArray {
    public static void main(String[] args){

        String[] arrs = new String[]("123", "asd", "zxc");
        printObject(arrs);
        printObject("asd");

    }
    public static void printObject(Object obj){
        Class classObj = obj.getClass();
        if(classObj.isArray()){
            int len = Array.getLength(obj);
            for(int i = ; i < len; i++){
                System.out.println(Array.get(obj, i));
            }
        }else{
            System.out.println(obj);
        }
    }
}
           

ArrayList_HashSet的比较及Hashcode分析

public class ReflectTest {
    public static void main(String[] args){
        Collection collections = new HashSet();
        ReflectPoint pt1 = new ReflectPoint(,);
        ReflectPoint pt2 = new ReflectPoint(,);
        ReflectPoint pt3 = new ReflectPoint(,);

        collections.add(pt1);
        collections.add(pt2);
        collections.add(pt3);
        collections.add(pt1);
        //ArrayList的容量为4
        //HashSet的容量为3
        //重写ReflectPoint类的equals方法后,HashSet的容量为2
        System.out.println(collections.size());

        pt1.y = ;
        collections.remove(pt1);
        //修改y值后,hashCode值改变,删除操作会在原来的hashCode值区域查找,删除无效HashSet的容量为2
        //持续修改对象删除该对象,就会造成内存泄露
        //如果不修改,删除后,HashSet的容量为1
        System.out.println(collections.size());
    }
}
           

框架的概念及用反射技术开发框架的原理

public class ReflectTest {
    public static void main(String[] args) throws Exception{
        FileInputStream fis = new FileInputStream("config.properties");
        Properties props = new Properties();
        props.load(fis);
        fis.close();
        String className = props.getProperty("className");
        Collection collection = (Collection)Class.forName(className).newInstance();
        ReflectPoint rp1 = new ReflectPoint(,);
        ReflectPoint rp2 = new ReflectPoint(,);
        ReflectPoint rp3 = new ReflectPoint(,);

        collection.add(pt1);
        collection.add(pt2);
        collection.add(pt3);
        collection.add(pt1);
        System.out.println(collection.size());
    }
}
           

配置文件config.properties

className = java.util.HashSet