黑马程序员_Java基础_高级反射

本文深入探讨了Java反射机制的原理与应用,包括获取类的字节码、使用Constructor类创建实例对象、使用Method类调用方法以及使用Field类访问字段。同时,通过实例演示了如何使用反射技术动态创建类对象、调用类方法和访问类字段,并讨论了反射在处理数组、基本类型数组以及集合操作中的应用。最后,展示了如何通过反射实现动态调用类的main方法和修改对象中特定字段的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------- android培训java培训、期待与您交流! ----------

 
 反射机制:
 
 Java程序中的各个java类属于同一类事务,描述这类事物的java类就是Class
 如:人————>Person
  java类————>Class
  
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码
不同的类的字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间分别是一个个对象来表示,
这些对象显然具有相同的类型
获取字节码对一个的实例对象方式:
1.类名.class    例如:System.class
2.对象.getClass()    例如:new Date.getClass()
3.Class.forName("类名")   例如:Class.forName("java.lang.String")

课外需知: static Class<Integer> Integer.TYPE  表示基本类型 int 的 Class 实例
常用方法:
1.Class.isArray()   判定此 Class 对象是否表示一个数组类
2.Class.isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。

Constructor类代表某个类中的一个构造方法
常用方法:
获取所有的构造方法:     Constructor[] constructor = Class.forName("java.lang.String").getConstructor();
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));

Class.newInstance()方法:
String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象 
例子1: 
<strong>public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        // TODO Auto-generated method stub
        String  str = "abc";
        Class cls1 = str.getClass();
        Class cls2 = Class.forName("java.lang.String");
        Class cls3 = String.class;
        
        System.out.println(cls1 == cls2);  //true
        System.out.println(cls1 == cls3);   //true
        
        //结论:三种方式获取的Class对象是一致的:
        
        
        
        //isPrimitive() 判定指定的 Class 对象是否表示一个基本类型
        System.out.println(cls1.isPrimitive());   //false
        System.out.println(int.class.isPrimitive());   //true
        System.out.println(Integer.class.isPrimitive()); //false   Interger是类,不是基本数据类型
        System.out.println(int[].class.isPrimitive());   //false    数组不是基本数据类型
        
        //  判定此 Class 对象是否表示一个数组类
        System.out.println(int[].class.isArray());      //true
        
        System.out.println(int.class == Integer.class);  //false
        System.out.println(int.class == Integer.TYPE);   //true
        
        
        //----------------------------------------------
        //使用Constructor获取String中的构造方法
        Constructor constructor = String.class.getConstructor(StringBuffer.class);
        //使用该类创建对象,
        //等同与new String(new StringBuffer("abc"));
        String str1 = (String) constructor.newInstance(new StringBuffer("abc"));
        System.out.println(str1.charAt(2));   //输出c
        
        
    }
}</strong>
  需求:写一个小的框架,从配置文件中读取数据并,动态创建类对象
 
 相当于框架,一般框架都是采用映射技术实现的
例子2: 
public class Point {
    public int x;
    private int y;
    public String str1 = "123";
    public String str2 = "453";
    public String str3 = "783";
    
    public Point(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Point other = (Point) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }
    @Override
    public String toString() {
        return "Point [str1=" + str1 + ", str2=" + str2 + ", str3=" + str3
                + "]";
    }
    
    
}

例子3:
 
<strong>public class ReflectDemo2 {
 
    public static void main(String[] args) throws FileNotFoundException,
            IOException, InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        // TODO Auto-generated method stub
        /*
         * 需求:写一个小的框架,从配置文件中读取数据并,动态创建类对象
         */
        // InputStream in = new FileInputStream("prop.properties");
        // 使用雷加载器进行加载配置文件,项目中都是这么加载配置文件的
        InputStream in = ReflectDemo2.class.getClassLoader()
                .getResourceAsStream("day13_Reflect/prop.properties");
        
        Properties prop = new Properties();
        prop.load(in);
        String className = prop.getProperty("className");
        in.close();// 释放资源
        // 等同于 Collection collection = new HashSet();
        Collection collection = (Collection) Class.forName(className)
                .newInstance();
        Point p1 = new Point(3, 3);
        Point p2 = new Point(5, 5);
        Point p3 = new Point(3, 3);
        collection.add(p1);
        collection.add(p2);
        collection.add(p3);
        System.out.println(collection.size());
        // 输出结果:2
        p1.x = 7;
        collection.remove(p1);
        System.out.println(collection.size());
        // 输出结果:2
        // 结论:当类使用hashCode算法进行集合的操作时,我们去改变对象的hashCode值,
        // 会使得对象无法移除,造成“内存溢出”
    }
}
</strong>
 Method:代表某个类中的一个成员方法
 
 调用方法:
 通过方式:System.out.println(str.charAt());
 反射方式:System.out.println(charAt.invoke(str,1));
 
  提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 
  
  
  
数组的反射;
具有相同维数和元素类型的数组属于同一个类型,既具有相同的Class实例对象

代表数组的Class实例对象的getSuperClass方法返回的父类为Object类对应的Class

重点)基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用
非基本类型的一维数组,既可以当作Object类型使用,也可以当作Objcet[]类型使用
Arrays.asList()方法处理int[]和String[]时的差异
例子4: 
public class MethodDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException,
            ClassNotFoundException {
        String  str = "abc";
        
        //反射得到String类中的charAt()方法
        Method method = String.class.getMethod("charAt", int.class);
        
        //使用Method将从String中获取到的charAt()方法进行应用;
        //这就是反射的真正奥秘
        
        //通常方式:str.charAt(2);
        System.out.println(method.invoke(str, 2));   //结果:c
        System.out.println(method.invoke(str, 1));   //结果:b
        
        
        /*
         * 需求:写一个程序,这个程序根据用户提供的类名,去执行该类中的main方法
         * 
         * 解决方法:
         * mainMethod.invoke(null,new Object[]{new String[]{"xxx"}})
         * 
         */
        
        //通常方式:TestMain.main(new String[]{"11","22","33"});
        
        //放射方式:
        //使用反射技术将TestMain类中的main方法进行使用
        //需要在运行主方法是将参数day13_Reflect.TestMain带上
        String testmain = args[0];
        Method method2 = Class.forName(testmain).getMethod("main", String[].class);
        //在使用的是静态方法时,第一参数为null
        method2.invoke(null, (Object)new String[]{"11","22","33"});
        
    }
}
class TestMain{
    public static void main(String[] args) {
        for(String arg : args){
            System.out.println(arg);
        }
    }
}
Field类:
 代表某个类中的一个成员变量
提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。 

Array 允许在执行 get 或 set 访问操作期间进行扩展转换,但如果将发生收缩转换,则抛出一个 IllegalArgumentException。 

例子5:
public class FieldDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchFieldException, IllegalArgumentException,
            IllegalAccessException {
        // TODO Auto-generated method stub
        Point p = new Point(3, 4);
        // 获取一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
        Field fieldX = p.getClass().getField("x");
        // 类中的X成员变量是公有的
        System.out.println(fieldX.get(p)); // 输出3
        // 类中的Y成员变量是私有的,直接取出会抛出java.lang.NoSuchFieldException异常
        // 我们必须使用“暴力反射”
        Field fieldY = p.getClass().getDeclaredField("y");
        fieldY.setAccessible(true);
        System.out.println(fieldY.get(p)); // 输出4
        changStringValue(p);
        System.out.println(p);
        // 结果:Point [str1=129, str2=459, str3=789]
    }
    // 使用反射机制,将一个对象中的数据改变
    //需求:将任意一个对象中的所有String类型的成员变量锁对应的字符串内容中的‘3’改成‘9’
    public static void changStringValue(Object obj)
            throws IllegalArgumentException, IllegalAccessException {
        // TODO Auto-generated method stub
        Field[] fields = obj.getClass().getFields();
        for (Field field : fields) {
            if (field.getType() == String.class) {
                String old = (String) field.get(obj);
                String newstr = old.replace('3', '9');
                field.set(obj, newstr);
            }
        }
    }
}
 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值