反射:
概述: java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
反射常用对象的概述:
Class:
--Class类的实例表示正在运行的java应用程序中的类和接口
Constructor:
--关于类的单个构造方法的信息以及对它的访问权限
Filed:
--提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
Method:
--提供关于类或接口上单独某个方法的信息
测试对象(以下eg例子的测试对象):
public class Person { public String name; private int age; public Person(){ super(); } public Person(String name, Integer age) { this.name = name; this.age = age; } // public String getName() { // return name; // } // // public void setName(String name) { // this.name = name; // } // // public int getAge() { // return age; // } // // public void setAge(int age) { // this.age = age; // } public void eat(){ System.out.println("吃....."); } public void speak(){ System.out.println(name + ":" + age); } private void run(){ System.out.println("跑。。。。。"); } private String say(String name){ return "Hello " + name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
Class类:Class类代表某个类的字节码,并提供了加载字节码的方法:
Java.lang.Class类用于表示一个类的字节码(.class)文件
如何得到某个class文件对应的Class对象:
1、 已知类和对象的情况下:
a) 类名.class
b) 对象.getClass() ---Object类提供的
2、 未知类和对象的情况下:
a) Class.forName(“包名.类名”)
forName方法用于加载类字节码到内存中,并封装成一个Class对象
eg:
importorg.junit.jupiter.api.Test;
public classClassTest {
@Test
/**
* Class对象的获取:
*/
public void demo(){
//1、类名.class
Class clazz1 = Person.class;
//2、对象.getClass()
Person p = new Person();
Class clazz2 = p.getClass();
try {
//3、Class.forName("包名.类名");
Class clazz3 =Class.forName("com.luyue.classtest.Person");//推荐使用
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Constructor类:
Constructor类的实例对象代表类的一个构造方法
1、 得到某个类所有的构造方法
Constructor[] constructors = Class.forName(“java.lang.String”).getConstructors();
2、 得到指定的构造方法并调用:
Constructorconstructor = Class.forName(“java.lang.String”).getConstructor(String.class);
String str = (String)constructor.newInstance(“abc”);
3、 Class类的newInstance()方法用来调用类的默认构造方法
String obj = (String)Class.forName(“java.lang.String”).newInstance();
Eg:
importorg.junit.jupiter.api.Test;
importjava.lang.reflect.Constructor;
importjava.lang.reflect.InvocationTargetException;
public classConstructorTest {
@Test
/**
* 获得无参构造方法
*/
public void demo() throws Exception{
//先获得Class对象
Class clazz =Class.forName("com.luyue.classtest.Person");
//获得Constructor对象
Constructor constructor =clazz.getConstructor();//无参构造不需要参数
Person person =(Person)constructor.newInstance();//实例化一个对象
person.eat();
}
@Test
/**
* 获得有参数的构造方法
*/
public void demo1() throws Exception {
//一样先获得Class对象
Class clazz =Class.forName("com.luyue.classtest.Person");
//获得Constructor对象
Constructor constructor =clazz.getConstructor(String.class, Integer.class);
//实例化一个对象
Person person =(Person)constructor.newInstance("我", 11);
person.eat();
person.speak();
}
}
Field类:
Field类代表某个类中的一个成员变量,并提供动态的访问权限
Field对象的获得:
1、 得到所有的成员变量:
a) Field[] fields = claszz.getFields();//取得所有public属性(包括父类继承)
b) Field[] fields = claszz.getDeclaredFields();//取得所有声明的属性
2、 得到指定的成员变量:
a) Field name = claszz.getField(“name”);
b) Field name = claszz.getDeclaredField(“name”);
field.setAccessible(Boolean);//设置Filed变量是否可以访问,设置为true,那么私有属性可以被访问
3、 Field变量值的读取和设置
--field.get(obj)//读取
--field.set(obj,value);//设置
Eg:
importorg.junit.jupiter.api.Test;
importjava.lang.reflect.Field;
publicclass FieldTest {
@Test
/**
* 测试共有属性
*/
public void demo() throws Exception {
//获取Class
Class clazz = Class.forName("com.luyue.classtest.Person");
//获得公有属性
Field field =clazz.getField("name");
//操作属性
//设置值
Person p = (Person)clazz.newInstance();
field.set(p, "李四");
System.out.println(p);
//获得值
Object obj = field.get(p);
System.out.println(obj);
}
@Test
/**
* 测试私有属性
*/
public void demo2() throws Exception {
//一样先获取Class
Class clazz =Class.forName("com.luyue.classtest.Person");
//获得Field
Field field =clazz.getDeclaredField("age");
//操作属性,这里有个前提:操作私有属性之前先要设置field变量是否可以被访问
Person p = (Person)clazz.newInstance();
field.setAccessible(true);//设置field可以被访问
//设置值
field.set(p, 20);
System.out.println(p);
//获取值
Object obj = field.get(p);
System.out.println(obj);
}
}
Method类:
代表某个类的一个成员方法
Method对象的获得
---获得所有方法:
getDeclaredMethods()//获得所有方法,无论公有私有
getMethods() //获得所有公有的方法
---获得指定的方法
getDeclaredMethod(Stringname, Class<?>…parameterTypes)
getMethod(Stringname, Class<?>…parameterTypes)
通过反射执行方法:
invoke(Objectobj, Object..args)
eg:
importorg.junit.jupiter.api.Test;
import java.lang.reflect.Method;
public class MethodTest {
@Test
/**
* 测试无参公有方法
*/
public void demo1() throws Exception{
//获取Class
Class clazz = Class.forName("com.luyue.classtest.Person");
Person p = (Person)clazz.newInstance();
//获取Method
Method method = clazz.getMethod("eat");
//执行
method.invoke(p);
}
@Test
/**
* 测试无参私有方法
*/
public void demo2() throws Exception{
//获取Class
Class clazz = Class.forName("com.luyue.classtest.Person");
Person p = (Person)clazz.newInstance();
//过得Method
Method method = clazz.getDeclaredMethod("run");
//设置访问权限
method.setAccessible(true);
//执行
method.invoke(p);
}
@Test
/**
* 测试有参私有方法,有参公有方法一样
*/
public void demo3() throws Exception{
//获得Class
Class clazz = Class.forName("com.luyue.classtest.Person");
Person p = (Person)clazz.newInstance();
//获得Method
Method method = clazz.getDeclaredMethod("say", String.class);
//设置访问权限
method.setAccessible(true);
//执行
Object obj = method.invoke(p, "辛巴");
System.out.println(obj);
}
}
补充一点:如果方法参数中有数组参数,需要稍微变一下
因为:
invoke方法的第二个参数接受的是Object数组,并把数组的每一个元素作为方法的一个参数。所以如果某一个参数为数组,要在外面用newObject[]{}包起来
像这样: