反射(一)类成分的获取和使用

1.Class类对类的一种抽象,包含类的公共特性如类都有类名,包名,方法,属性等

2.Class类型是类的字节码:获取类的字节码方式有三种:(如person类)

   Person.class

   new Person().getClass()

   Class.forName("Person")

3. 基本类型判断,基本类型和包装类型不是同一类型,以及类型的判断

4.反射就是把类的成分映射成各种类,可以通过字节码获取和使用它们( 类的成分类型Field、Method、 Contructor、Package等等)

4.1.Constructor类代表构造方法(通过字节码获取够准确)

得到某个类所有的构造方法:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一个构造方法:Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class); //通过参数类型获取指定构造器

普通方式和反射生成对象的例子:

通常方式:

String str = new String(new StringBuffer("abc"));

反射方式:

String str = (String)constructor.newInstance(new StringBuffer("abc"));//通常创建对象需要先获取构造器类(该构造器类一般是有参数的而不是默认无参的)

直接使用默认构造器:

String obj = (String)Class.forName("java.lang.String").newInstance(); //该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。

 

4.2Field类代表某个类中的一个成员变量(获取对象的属性值:a.得到类字节码 b.得到字段类 c.调用字段的get方法传入对象参数得到属性值)

ReflectPoint point = new ReflectPoint(1,7); 
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");

System.out.println(y.get(point)); 
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");抛出异常;因为属性x是私有的。需要使用getDeclareFiled();

Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");//这只是获取特定的字段类

x.setAccessible(true);//要想获取私有属性的值,需要设置其是可访问的

System.out.println(x.get(point));//获取对象中字段的值

 

将一个对象字段值修改的例子:(将‘b'用’a'替换)

 

4.3Method类

Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);//通过类的字节码获取方法类需要知道方法名称和参数类型

调用方法:
通常方式:System.out.println(str.charAt(1)); 
反射方式: System.out.println(charAt.invoke(str, 1));

如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法

jdk1.4和jdk1.5的invoke方法的区别:

Jdk1.5:public Object invoke(Object obj,Object... args)

Jdk1.4:public Object invoke(Object obj,Object[] args),即charAt.invoke(“str”, new Object[]{1})形式。

关于方法参数本身是数组类型时:而反射默认方法的参数是数组,表示参数的个数;会自动拆分参数。比如反射调用main方法时:

mainMethod=getMethod("main", String[].class);

mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行 理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题.

解决办法:

mainMethod.invoke(null,new Object[]{new String[]{"xxx",“xx”}});

mainMethod.invoke(null,(Object)new String[]{"xxx","xx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了

4.4数组(基本类型不是继承object所以是不能直接向上转型的但是基本类型的数组是继承object可以自动向上转型的

判断数组是否是同一类型:(相同的类型具有相同的class对象)

具有相同维数和元素类型的数组属于同一个类型(与长度无关)。

基本类型的一维数组可以被当作Object类型使用(数组继承object),不能当作Object[](一个存放objec类型t的数组)类型使用;

非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用

(二位数组就是存放数组的数组)

将一个数组转换成列表时候:(编译器首先1.4判断是否是对象数组,不是的话,采用1.5可变参数方式处理)

Arrays.asList(T.. t)方法参数是一个可变参数,也当成Object[]来处理的:处理参数是int[]和String[]时有差异的

如果是int[]会当成一个object类型来处理(因为int[]不能直接转换成object[]类型,就当一个可变参数)变成一个元素是数组的列表

如果是Sting[]会作为一个object[]方式来处理,变成的是元素是字符串的列表

Array工具类用于完成对数组的反射操作:

注意:关于数组的类型,如果是object[]那么具体元素的类型可能不一样,直接通过获取数组类型并不能精确知道每个具体元素的类型;

原文地址:https://www.cnblogs.com/straybirds/p/5191545.html