------- android培训、java培训、期待与您交流! ----------
一 反射的基石:Class类
1 Class类:描述java程序中的java类。例如:描述人这类事物用Person类。描述java中的类就用Class类。
(1)该类所描述的是类所属的包,该类实现的接口,该类中定义的成员等等,都可以通过Class类得到。
(2)Class类的实例对象是字节码文件对象。
(3)什么是字节码文件对象呢。当我们使用到某个类时,会从硬盘上将类编译成class文件的字节码,将字节码加载进内存在创建出一个个的实例对象。
(4)那么获取字节码实例对象有三种方式
第一种: Class cls1=类名.class
第一种: Class cls2=对象.getClass()
第一种: Class cls3=Class.forName(类的完整名字)
2 九个预定义的实例对象
基本数据类型boolean、byte、char、short、int、long、float、double和关键字 void 也表示为 Class 对象。只要源代码使用到对应的数据类型,内存就会产生对应的字节码示例对象。
int.class==Integer_TYPE;
3 例子:
class ClassDemo
{
public static void main(String[] args) throws Exception
{
//创建String类对象
String s="aaa";
//获取String类的字节码
Class cls1=String.class;
Class cls2=s.getClass();
Class cls3=Class.forName("java.lang.String");
//判断是否是同一个字节码
System.out.println(cls1==cls2);//结果为true
System.out.println(cls1==cls3);//结果为true
//判断String类是不是原始类型
System.out.println(cls1.isPrimitive());//结果为false
//判断int类是不是原始类型
System.out.println(int.class.isPrimitive());//结果为true
}
}
二 反射
1 概念:反射就是把java类中的各个成分映射成java类。
例如:java类中有成员函数,成员方法,构造函数。通过Class类可以获得这些信息。他们的类型分别是Field,Method,Constructor,他们也是java类。
2 Constructor类,用于描述类中的构造方法。可以通过Constructor类创建实例对象
(1)获取构造方法的方式:
第一:Class类对象.getConstructors();//获取某个类的全部构造方法,返回Constructor[]数组
第二:Class类对象.getConstructors(Class<?>... parameterTypes);//获取某个类的一个构造方法,而具体是哪个要看构造方法对应的参数列表
3 通过获取构造方法可以创建对应的实例对象
方法:Constructor的实例对象.newIntance(Object... initargs);//需要对返回类型进行强转
4 例子:
import java.lang.reflect.*;
class ConstructorDemo
{
public static void main(String[] args) throws Exception
{
//获取Person类的字节码对象
Class cls1=Person.class;
//获取Person类的全部构造方法
Constructor[] cons=cls1.getConstructors();
System.out.println(cons.length);//获取构造方法数量
//获取Person中的某个构造方法
Constructor con=cls1.getConstructor(String.class,int.class);
//通过构造方法创建实例对象
Person p1=(Person)con.newInstance("zhangsan",15);
//用创建的实例对象调用方法
System.out.println(p1.name+":"+p1.age);
}
}
class Person
{
String name;
int age;
public Person(){}
public Person(String name)
{
this.name=name;
}
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
}
5 Field类,用于描述类中的成员变量
(1)获取类中的某个成员变量的Constructor对象用getField(String name),此方法不能获取私有的变量
(2)获取类中私有的变量的Constructor对象用getDeclaredField(String name);
(3)例子:
import java.lang.reflect.*;
class FieldDemo
{
public static void main(String[] args) throws Exception
{
//创建学生对象
Student s=new Student("lisi",25);
//获取学生类字节码对象
Class cls1=s.getClass();
//获取学生类的某个成员变量
Field fieldName=cls1.getField("name");
//获取某个学生对象的成员变量的值
String s_name=(String)fieldName.get(s);
System.out.println(s_name);
//获取学生类中的私有成员变量
Field fieldAge=cls1.getDeclaredField("age");
//将私有变量设置为可访问的
fieldAge.setAccessible(true);
//获取s学生对象的age值
int s_age=(int)fieldAge.get(s);
System.out.println(s_age);
}
}
class Student
{
public String name;
private int age;
public Student(String name,int age)
{
this.name=name;
this.age=age;
}
}
(4) Field类反射练习:
//将一个java类中的String类型的成员变量中的值的字母改掉
/*
思想:
1 获取类中所有的成员变量的Field对象数组
2 遍历Field数组并判断类型
3 如果是String类型的就获取他的值并将对应的字母换成指定的字母
*/
import java.lang.reflect.*;
class FieldTest
{
public static void main(String[] args) throws Exception
{
//创建男人对象
Man m=new Man();
//获取Man类的字节码对象
Class cls1=m.getClass();
//获取类中成员变量的Field数组
Field[] fields=cls1.getFields();
System.out.println(fields.length);
//遍历数组
for(Field field:fields)
{
//判断成员变量所属的类型
if (field.getType()==String.class)
{
//获取变量的值
String oldVal=(String)field.get(m);
//将变量的值改掉
String newVal=oldVal.replace('n','m');
//将m对象变量上此 Field 对象表示的字段设置为指定的新值
field.set(m,newVal);
}
}
System.out.println(m.toString());
}
}
class Man
{
public String name="nanren";
public int age=20;
public String id="work000";
public String sex="man";
public String toString()
{
return name+":"+id+":"+sex;
}
}
6 Method类,用于描述类中的成员函数
(1)例子:
//用反射的方法调用Person类中的getName()方法
import java.lang.reflect.*;
class MethodDemo
{
public static void main(String[] args) throws Exception
{
//创建人对象
Person p=new Person();
//获取Person字节码对象
Class cls1=p.getClass();
//获取Person类中的setName()方法Method对象
Method method_setName=cls1.getMethod("setName",String.class);
//调用setName()方法
method_setName.invoke(p,"lisi");
//获取Person类中的getName()方法Method对象
Method method_getName=cls1.getMethod("getName");
//调用Method类的getName()方法
String name=(String)method_getName.invoke(p);
System.out.println(name);
}
}
class Person
{
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
}
7 数组的反射
(1)具有相同维数和数据类型的数组具有相同的Class字节码实例对象。
(2)基本数据类型的一位数据可以被当作Object使用,不可以被当作Object[]使用。引用数据类型的一维数组可以被当作Object使用也可以被当作Object[]使用。
(3)例子:
import java.lang.reflect.*;
class ArrayDemo
{
public static void main(String[] args)
{
int[] arr1=new int[]{1,2,3};
int[] arr2=new int[2];
String[] arr3=new String[3];
int[][] arr4=new int[2][3];
//分别获取数组的Class字节码对象
Class cls1=arr1.getClass();
Class cls2=arr2.getClass();
Class cls3=arr3.getClass();
Class cls4=arr4.getClass();
System.out.println(cls1==cls2);//true
System.out.println(cls1==cls3);//flase
System.out.println(cls1==cls4);//false
//结论:只有维数和数据类型一致,对应的字节码对象是同一份
//获取父类
System.out.println(cls1.getSuperclass().getName());//返回java.lang.Object
System.out.println(cls3.getSuperclass().getName());//返回java.lang.Object
//调用方法打印对象
print(arr1);
}
//定义方法用反射打印对象
public static void print(Object obj)
{
//获取Object的字节码对象
Class cls=obj.getClass();
//判断是不是数组
if(cls.isArray())
{
//遍历数组并打印
for(int x=0;x<Array.getLength(obj);x++)
{
System.out.println(Array.get(obj,x));
}
}
else
System.out.println(obj);
}
}