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

来源:互联网 发布:有声读书软件 编辑:程序博客网 时间:2024/05/22 16:08

——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