黑马程序员---JAVA反射机制

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

反射的基石—Class类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象,是9个预定义的Class对象。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
Java程序中的各个Java类属于同一事物描述这类事物的Java类目就是Class。举个例子:
人 是一类事物—>Person
Java类 是一类事物—>Class

区别class与Class
class 是java的关键字, 在声明java类时使用;
Class 是java JDK提供的一个类,完整路径为 java.lang.Class;

区别是指两个或两个以上的事物间的不同,当两种相似的事物作比较时,它们的不同点便是区别。
那么 class和Class的相似性就只有一个,那都是单词”class”,就是一个为首字母大写,一个为小写.

class和Class的作用:
1. class只用于类声明;
2. Class则用于抽象类的相关信息. java是面向对象的, 一般是把一些事物抽象成一个类,比如将学生信息抽象成Student这个类;Student类会抽象学生的姓名/性别/生日等信息;
那么java中也就把java中的类也抽象成了一个类叫Class;Class中抽象了类的包名/类名/属性数组/方法数组等;

//一般类的定义
Person p1=new Person()
//Class类的定义
Class cls2=Person.class //字节码
得到字节码的三种方式:
类目.class Person.class
对象.getClass p1.getClass();
Class.forName(“类目”) Class.forName(“java.lang.String”)
预定义对象的判断
int.class==Integer.TYPE
数组类型的Class实例对象
Class.isArray()
总之只要是在源程序中出现的类型,都有各自的Class对象,如:int[],void等
下面看一个小例子:

package reflect;

public class ReflectDemo {
    public static void main(String[] args) {
        String str1="abc";
        try {
            Class cls1=str1.getClass();
            Class cls2=String.class;
            Class cls3=Class.forName("java.lang.String");
            System.out.println(cls1==cls2);//true
            System.out.println(cls3==cls2);//true
            System.out.println(cls1.isPrimitive());//false
            System.out.println(int.class.isPrimitive());//true
            System.out.println(int.class==Integer.class);//false
            System.out.println(int.class==Integer.TYPE);//true
            System.out.println(int[].class.isPrimitive());//false
            System.out.println(int[].class.isArray());//true
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

反射概念
反射就是把Java类中的各种成分映射成相应的java类,例如,一个Java类中用一个Class类对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等也是一个类。表示Java类的Class类显然就是提供一系列的方法,来获得其中的变量,方法,构造方法包等信息,这些信息就是用相应的类的实例对象来表示,它们是Field、Method、Package、Constructor等
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

Constructor类
Constructor类代表某个类中的一个构造方法
得到某个类所有构造方法:
Constructor[] constructors = Class.forName(“java.lang.String”).getConstructors();
得到某一个人构造方法:
Constructor constructor = Class.forName(“java.lang.String”).getConstructors(StringBuffer.class);
这个例子得到的是String类的String(StringBuffer buffer)构造方法
//获得方法是要用到类型
创建实例对象:
Constructor constructor=String.class
.getConstructor(StringBuffer.class);
String str2=(String)constructor.newInstance(
newStringBuffer(“abc”));
//调用获得的方法时,要用到上面相同类型的实例对象
Class.newInstance()
例子:String obj=(String) Class.forName(“java.lang.String”).newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象,该方法内部用到了缓存机制来保存默认构造方法的实例对象

Field类
Field类代表某个类中的一个成员变量
问,得到的Field对象时对应到类上面的成员变量,还是对应的对象上的成员变量?类只有一个,而该类的实例对象可能有多个,如果是与对象关联,关联的是哪一个对象呢?所以字段fieldX代表的是x的定义,而不是具体的变量,示例代码:

class ReflectPoint {
    private int x;
    public int y;
    public ReflectPoint(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
package reflect;
import java.lang.reflect.Field;
public class ReflectDemo {
    public static void main(String[] args) {
        try {   
            ReflectPoint pt1=new ReflectPoint(3, 5);
            Field fieldY=pt1.getClass().getField("y");
            //fieldY的值是多少?5 是错的,fieldY不是对象上的变量,而是类上要用它去取某个对象上对应的值
            System.out.println(fieldY.get(pt1));
            Field fieldX=pt1.getClass().getDeclaredField("x");
            fieldX.setAccessible(true);
            System.out.println(fieldX.get(pt1));    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

下面有一个需求,将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”,这是一个经典的例子

public class ReflectPoint {
    public String str1="ball";
    public String str2="basketball";
    public String str3="itcast";
    @Override
    public String toString(){
        return str1+":"+str2+":"+str3;
    }
}

import java.lang.reflect.Field;

public class ReflectDemo {
    public static void main(String[] args) {
        try {
            ReflectPoint pt1=new ReflectPoint();
            changeStringValue(pt1);
            System.out.println(pt1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
        Field [] fields=obj.getClass().getFields();
        for(Field field:fields){
            if (field.getType()==String.class) {//字节码只有一份,所以用==
                String oldValue=(String) field.get(obj);
                String newValue=oldValue.replaceAll("b", "a");
                field.set(obj, newValue);
            }
        }
    }
}

Method类
Method类 代表某个类中的成员方法
得到类中的某一个方法:
Method charAt=Class.forName(“java.lang.String”).getMethod(“charAt”,int.class)
调用方法:
str.charAt(1);
charAt.invoke(str,1)
如果传递给Method对象的invoke()方法的第一个参数为null,这有什么样的意义呢?说明该Method对象对应的是一个静态方法

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

import java.lang.reflect.Method;

public class ReflectDemo {
    public static void main(String[] args) {
        try {
            TestArgument.main(new String[]{"111","222"});//普通方式
            //反射方式
            String startingClassName=args[0];
            Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);
            mainMethod.invoke(null, (Object)new String[]{"111","222","333"});

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

注:
mainMethod.invoke(null, (Object)new String[]{“111”,”222”,”333”}),编译器会做特殊处理,编译时不把参数当数组看待,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值