一、反射的概念
反射机制通过获得JVM中的字节码文件来获得类的相关信息。
二、Class类
Class类用来描述一切的类和接口,枚举是一种类,注解是一种接口。
Class实例:对应着JVM中的一份字节码。
Class实例化方法:
1.类名.class(就是一份字节码)
2.Class.forName(String className);根据一个类的全限定名来构建Class对象
3.每一个对象多有getClass()方法:obj.getClass();返回对象的真实类型
三、九大内置对象
byte,short,int,long,char,float,double,boolean ,void关键字
上述8种类型和void关键字,都有class属性.
表示int的Class对象: Class clz = int.class;
表示boolean的Class对象: boolean.class;
四、数组的Class实例
Class clz = String[].class;//此时clz表示就是一个String类型的一维数组类型
所有具有相同元素类型和维数的数组才共享同一份字节码(Class对象);
五、获得构造器
通过字节码获得构造器的四种方法
clz2.getConstructors();
clz2.getDeclaredConstructors();
clz2.getConstructor(参数的字节码实例);
clz2.getDeclaredConstructor(参数的字节码实例);
六、创建对象
Class<User> userClass = (Class<User>) Class.forName("construct.User");
//2.获得要调用的指定构造器(通过参数列表)
Constructor<User> con = userClass.getDeclaredConstructor();
//3.调用newInstance方法获得对象
User u = con.newInstance();
con = userClass.getConstructor(String.class);
u = con.newInstance("Tom");
//在调用私有型构造方法前,要设置方法的可访问性为true
/*对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。*/
con = userClass.getDeclaredConstructor(String.class,int.class);
con.setAccessible(true);
u = con.newInstance("Tom",22);
七、获取类中的方法
package construct;
import java.lang.reflect.Method;
/**
* 获得类中方法的步骤:
* 1、获得类的字节码
* 2、通过getMothod等方法获得方法体。
*
* Class类中有关获得Method的常用方法:
* 1、public Method[] getMethods():
* 返回一个Method对象数组,包括类和接口(包括超类和超接口中声明的)中的所有公共方法
* 2、public Method[] getDeclaredMethods():
返回一个Method对象数组,包含类和接口(不包括超类)中的所有方法
*
*
* 3、public Method getMethod(String name,
Class<?>... parameterTypes)
返回一个Method对象,包含类和接口(包括超类)中的匹配的方法
参数:
name - 方法名
parameterTypes - 参数列表
返回:
与指定的 name 和 parameterTypes 匹配的 Method 对象
4、public Method getDeclaredMethod(String name,
Class<?>... parameterTypes)
参数:
name - 方法名
parameterTypes - 参数列表
返回:
与指定的 name 和 parameterTypes 匹配的 Method 对象
* */
public class GetMothodDemo {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
getMethods();
System.out.println("-------------------");
getOneMethod();
}
public static void getMethods() throws Exception{
Class cla = Class.forName("construct.User");
Method[] methods = cla.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("----------------------------");
methods = cla.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m);
}
}
public static void getOneMethod() throws Exception{
Class cla = User.class;
Method method = cla.getMethod("sayHi");
method = cla.getMethod("toString");
System.out.println(method);
method = cla.getDeclaredMethod("sayHello");
System.out.println(method);
}
}
八、调用方法
package construct;
import java.lang.reflect.Method;
/**
* 方法调用的步骤:
* 1、获得字节码
* 2、获得方法
* 3、调用方法
* Method类中,invoke方法用于实现方法调用
* public Object invoke(Object obj,
* Object... args)
* obj - 从中调用底层方法的对象
* args - 用于方法调用的参数
* 对于静态方法的调用:
* 如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
*
* 对于可变参数列表:
* 方法的类型为对应的数组类型,
* 个别参数被自动解包,以便与基本形参相匹配,所以,使用Object数组进行封包。
*
* */
public class MethodInvokeDemo {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class clz = User.class;
Method say = clz.getMethod("sayHi");
say.invoke(clz.newInstance());
say = clz.getDeclaredMethod("sayHello");
say.setAccessible(true);
say.invoke(clz.newInstance());
System.out.println("-----------------------");
clz = MethodInvokeDemo.class;
Method staticMethod = clz.getMethod("hello");
staticMethod.invoke(null);
System.out.println("-----------------------");
staticMethod = clz.getMethod("hello2", String[].class);
staticMethod.invoke(null,new Object[]{new String[]{"TOM","Jerry"}});
}
public static void hello(){
System.out.println("hello");
}
public static void hello2(String ...strings){
for (String string : strings) {
System.out.println(string);
}
}
}
九、字段操作
package construct;
import java.lang.reflect.Field;
/**
* 获得字段的步骤:
* 1、获得字节码
* 2、从字节码中获得字段
* 常用方法:
* public Field[] getFields():获得所有公有字段,包括继承字段
* public Field getField(String name):获得指定的公有字段
* public Field[] getDeclaredFields():获得所有字段,不包括继承字段
* public Field getDeclaredField(String name):获得指定字段
*
* 使用字段:
*
* 为指定字段设置值和获取值。
* 设置值:
* 使用Field类中的相关set方法
*
* 获取值:get方法
*
*
* */
class Emp{
public String name = "Jerry";
private int age;
private boolean sex;
@Override
public String toString() {
return "Emp [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
public class GetFilderDemo {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// getFileds();
// getFiled();
setValue();
getValue();
}
public static void getFiled() throws Exception{
Class clz = Emp.class;
Field field = clz.getField("name");
System.out.println(field);
}
public static void getFileds(){
Class clz = Emp.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------------");
fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
public static void setValue() throws Exception {
Class clz = Emp.class;
Field field = clz.getField("name");
Object emp = clz.newInstance();
field.set(emp, "Tom");
System.out.println(emp);
}
public static void getValue() throws Exception {
Class clz = Emp.class;
Field field = clz.getField("name");
Object obj = clz.newInstance();
String name = (String) field.get(obj);
System.out.println(name);
}
}