本博客写的主要内容的结构,如下:
反射(Reflection)机制:
能够动态获取类的信息以及动态调用对象的方法。
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
如何实现反射机制:
- Class类:代表一个类,是Reflection API 中的核心类。
- Field 类:代表类的成员变量(成员变量也称为类的属性)。
- Method类:代表类的方法。
- Constructor 类:代表类的构造方法。
- Array类:提供了动态创建数组,及访问数组的元素的静态方法。
class对象的作用:
- getName(): 获得类的名称,包括包名
- getSimpleName(): 获得类的名称,不包括包名
- getSuperClass(): 获得本类的父类的class对象
- getInterfaces():获得本类所实现的所有接口的class对象
public Method[] getDeclaredMethods() throws SecurityException
取得所有当前类声明的方法,包括public,protected,默认,private四种访问权限的方法,但是不包括继承的方法public Method[] getMethods() throws SecurityException
取得所有public的方法,包括继承的,接口中声明的和自己定义的Field[] getDeclaredFields()
取得所有当前类自己定义的属性,包括四种访问权限的Field[] getFields()
取得所有public的属性,包括继承的,接口中声明的和自己定义的
代码:
加载Class对象
获取所有公有构造方法
获取公有、无参的构造方法
import java.lang.reflect.Constructor;
public class Constructors {
public static void main(String[] args) throws Exception {
//1.加载Class对象
Class clazz = Class.forName("ref.Student");
/* //2.获取所有公有构造方法
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
} */
System.out.println("*****************获取公有、无参的构造方法*******************************");
Constructor con = clazz.getConstructor(null);
//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
//2>、返回的是描述这个无参构造函数的类对象。
System.out.println("con = " + con);
//调用构造方法
Object obj = con.newInstance();
System.out.println("obj = " + obj);
Student stu = (Student)obj;
System.out.println(stu.name);
System.out.println("******************获取私有构造方法,并调用*******************************");
con = clazz.getDeclaredConstructor(char.class);
System.out.println(con);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
obj = con.newInstance('男');
// System.out.println(obj);
// Student stu2 = (Student)obj;
// System.out.println(stu2.name);
}
}
获取特定的方法:
import java.lang.reflect.Method;
public class MethodClass {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("ref.Student");
//2.获取所有公有方法
System.out.println("***************获取所有的”公有“方法*******************");
stuClass.getMethods();
Method[] methodArray = stuClass.getMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************获取所有的方法,包括私有的*******************");
methodArray = stuClass.getDeclaredMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************获取公有的show1()方法*******************");
Method m = stuClass.getMethod("show1", String.class);
System.out.println(m);
//实例化一个Student对象
Object obj = stuClass.getConstructor().newInstance();
m.invoke(obj, "刘德华");
System.out.println("***************获取私有的show4()方法******************");
m = stuClass.getDeclaredMethod("show4", int.class);
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
System.out.println("返回值:" + result);
}
}
获取含参的构造函数:
public class Student {
//---------------构造方法-------------------
//(默认的构造方法)
Student(String str){
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造方法
public Student(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
private Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+ age);
}
//**********字段*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
//**************成员方法***************//
public void show1(String s){
System.out.println("调用了:公有的,String参数的show1(): s = " + s);
}
protected void show2(){
System.out.println("调用了:受保护的,无参的show2()");
}
void show3(){
System.out.println("调用了:默认的,无参的show3()");
}
private String show4(int age){
System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
return "abcd";
}
//**************main方法***************//
public static void main(String[] args) {
System.out.println("main方法执行了。。。");
}
public void show(){
System.out.println("is show()");
}
}
获取字段(并调用):
import java.lang.reflect.Field;
public class Fields {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("ref.Student");
//2.获取字段
/*System.out.println("************获取所有公有的字段********************");
Field[] fieldArray = stuClass.getFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("************获取所有的字段(包括私有、受保护、默认、公共的)********************");
fieldArray = stuClass.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
} */
System.out.println("*************获取公有字段**并调用***********************************");
Field f = stuClass.getField("name");
System.out.println(f);
//获取一个对象
Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
//为字段设置值
f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
//验证
Student stu = (Student)obj;
System.out.println("验证姓名:" + stu.name);
System.out.println("**************获取私有字段****并调用********************************");
f = stuClass.getDeclaredField("phoneNum");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "18888889999");
System.out.println("验证电话:" + stu);
}
获取Class对象:
public class Fanshe {
public static void main(String[] args) {
//第一种方式获取Class对象
Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
Class stuClass = stu1.getClass();//获取Class对象
System.out.println(stuClass.getName());
//第二种方式获取Class对象
Class stuClass2 = Student.class;
System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
//第三种方式获取Class对象
try {
Class stuClass3 = Class.forName("ref.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
获取Student对象的字节码
获取main方法
调用main方法
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) {
try {
//代码对齐:Ctrl+Shift+F 删除选中行代码:Ctrl+D
// 1、获取Student对象的字节码
Class clazz = Class.forName("ref.Student");
// 2、获取main方法
Method methodMain = clazz.getMethod("main", String[].class);// 第一个参数:方法名称,第二个参数:方法形参的类型,
// 3、调用main方法
// methodMain.invoke(null, new String[]{"a","b","c"});
// 第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
// 这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
// methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
methodMain.invoke(null,new Object[] { new String[] { "a", "b", "c" } });// 方式二
} catch (Exception e) {
e.printStackTrace();
}
}
}