反射的基石–>Class类
- Java程序中的各个Java类属于同一类事物,描述这一类事物的Java类名就是Class.
- 众多的人用什么类表示?众多的Java类用一个什么类表示?
- 人—>Person
- 类—>Class
那么,Person类代表张三李四,实实在在的对象.那么Class类的对象是什么呢?
- 对应各个类在内存中的字节码,例如Person类的字节码,ArrayList类的字节码等.
- 一个类被类加载器加载到内存,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不用的.
用于描述一类事物的共性,该类事物有什么属性,没有什么属性.Java中各个类属于同一类事物,这个类就是Class.
Person p1 = new Person();
Student s2 = new Student ();
Class cls1 = 字节码(Person.class);
Class cls2 = 字节码(Student.class);
p1.getClass == Class.forName(“Person”)==Person.class; 得到字节码的方式三种 true
Class.forName作用:返回字节码.第一种:曾经被加载过的字节码:直接返回.没有加载过,用类加载器加载,返回.
主要使用Class.forName(),因为在写源程序的时候还不知道类的名字,把forName()里面定义一个变量,通过字符串传进来.这个字符串包含了一个类的名字.
int.class = Integer.TYPE;
数组类型的Class不是基本数据类型,Class.isArray()判断数据类型是否为数组
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
/**
*
*/
package reflect;
/**
* @author LYG
*
*/
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// TODO Auto-generated method stub
String str1 = new String("abc");
Integer i = 3;
int i1 = 3;
Class<? extends String> cls1 = str1.getClass();
Class<String> cls2 = String.class;
Class<?> cls3 = Class.forName("java.lang.String");
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
System.out.println("String是基本类型吗:"+cls1.isPrimitive());
System.out.println("Integer是基本类型吗:"+i.getClass().isPrimitive());
System.out.println(int.class.isPrimitive());
System.out.println(int.class == Integer.class);
System.out.println(int.class == Integer.TYPE);
System.out.println(double.class == Double.TYPE);
System.out.println(void.class == Void.TYPE);
//TYPE代表所包装的基本数据类型
System.out.println(int[].class.newInstance());
System.out.println(cls1.newInstance());
}
}
运行结果:
cls1cls2:true
cls1cls3:true
String是基本类型吗:false
Integer是基本类型吗:false
int.class.isPrimitive():true
int.class == Integer.class:false
int.class == Integer.TYPE:true
double.class == Double.TYPE:true
void.class == Void.TYPE:true
反射就是把Java类中的各种成分映射成相应的Java类,例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造函数,包等等信息.这些信息也用一个个的Java类表示,就像汽车是一个类,汽车中的发动机,变速箱也是一个个的类.表示Java类的Class类显然要提供一系列的方法来获得其中的变量,方法,构造函数,修饰符,包等信息.这些信息就是相应类的实例对象来表示,他们是Field,Method,Constructor,Package等等.
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示.通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这就是学习和应用反射的要点.
Constructor类:代表某个类中的一个构造方法.
得到某各类所有的构造方法:
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
Constructor con = String.class.getConstructor(StringBuffer.class);
String s = (String) con.newInstance(new StringBuffer("aaa"));
System. out.println(s );
编译器不知道con属于哪个类的字节码,因此类型不确定,要强转才可以使用.
class–>constructor–>newInstance
class–>newInstance 这个方法调用的是空参构造方法!
Class类放在 java.lang包中。java.lang.reflect包是关于反射的包。用Class类实例化其他类的对象,能够被Class类实例化的类的构造函数要被public修饰,暴露出去。
用Class类实例化其他类的对象的步骤:
1,用Class类中的静态方法forName(类名)返回一个Class类对象,就是定义需要操作哪一个类的字节码文件
2,用getConstructor(构造函数参数列表的class类型)方法返回一个Constructor对象,这也是确定了该类的某个构造函数。
3,用newInstance(构造函数参数列表的实例对象)方法返回一个Object对象。
其中2和3步骤中的括号里面构造函数的参数列表需要一致,不同的只是步骤2括号里面的是构造函数参数列表的class类型,步骤3里面的是构造函数参数列表的实例对象
Class类里面也有自己的newInstance方法:
1,先从内部获取不带参数的构造函数,
2,然后可以用这个构造函数建立实例对象,举例:
Stringstr=(String)Class.forName(“java.lang.String”).newInstance() ;
当然,通过Class来获取其他类的所有构造函数:
Class<?> class=Class.forName("Person");
//Class类和Constructor类最好写上泛型限定
Constructor<?> con[]= cla.getConstructors();
利用反射获取类的成员变量
确定需要操作的类的字节码文件
调用getField方法获取类中的public修饰的成员变量,返回一个Field类对象
这里注意:是类中的成员变量,不是对象的变量,
要注意是否有初始化。
getDeclaredField方法则是无论公有还是私有变量可以获取,推荐使用该方法。
用get方法确定该变量在哪一个对象上的所对应的值,该方法用于public修饰的变量上,
如果先用setAccessible(true)方法设定好可以暴力反射,
那么再用get方法可以暴力获取该变量在哪一个对象上的所对应的值。
注意:get 返回的是Object类型
利用反射获取类的方法
1,确定要被操作的类的字节码
2,用getMethod(方法名,参数列表的.class形式) 方法获取该方法
getMethod方法返回的是一个Method类的变量
3,调用Method类中的invoke(类的实例对象,实际参数)方法
来获取Method类对象对应的该方法在类的对象上对应的结果