基础知识
获取Class对象
/**
* 获取Class对象
* 1通过Object对象的 getClass()方法
* public final Class<?> getClass()返回此 Object 的运行时类。
* 返回的 Class 对象是由所表示类的 static synchronized 方法锁定的对象
* 2使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象
* System.out.println("The name of class Foo is: "+Foo.class.getName());
* 3通过Class对象的 forName(String className)
* public static Class<?> forName(String className) throws ClassNotFoundException
* 返回与带有给定字符串名的类或接口相关联的 Class 对象。
*
*/
public class ClassTest {
@Test
//通过Object getClass()方法
//public final Class<?> getClass()
public void test1(){
User user = new User();
Class<?> clazz = user.getClass();
System.out.println(clazz);
}
@Test
//使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象
public void test2(){
Class<?> clazz = User.class;
System.out.println(clazz);
}
@Test
//通过Class类的 forName(String className)
//public static Class<?> forName(String className) throws ClassNotFoundException
public void test3() throws ClassNotFoundException{
Class<?> forName = Class.forName("com.itheima.reflect.User");
System.out.println(forName);
}
}
获得构造方法
/**
获得构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
Constructor<?>[] getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
public void setAccessible(boolean flag) throws SecurityException
将此对象的 accessible 标志设置为指示的布尔值。
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
值为 false 则指示反射的对象应该实施 Java 语言访问检查。
public T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。个别参数会自动解包,以匹配基本形参,必要时,基本参数和引用参数都要进行方法调用转换。
如果底层构造方法所需形参数为 0,则所提供的 initargs 数组的长度可能为 0 或 null。
如果构造方法的声明类是非静态上下文的内部类,则构造方法的第一个参数需要是封闭实例;请参阅Java 语言规范 第 15.9.3 节。
如果所需的访问检查和参数检查获得成功并且实例化继续进行,这时构造方法的声明类尚未初始化,则初始化这个类。
如果构造方法正常完成,则返回新创建且已初始化的实例。
参数:
initargs - 将作为变量传递给构造方法调用的对象数组;基本类型的值被包装在适当类型的包装器对象(如 Float 中的 float)中。
返回:
通过调用此对象表示的构造方法来创建的新对象
抛出:
IllegalAccessException - 如果此 Constructor 对象实施 Java 语言访问控制并且底层构造方法是不可访问的。
IllegalArgumentException - 如果实参和形参的数量不同;如果基本参数的解包转换失败;如果在可能的解包后,无法通过方法调用转换将参数值转换为相应的形参类型;如果此构造方法属于枚举类型。
InstantiationException - 如果声明底层构造方法的类表示抽象类。
InvocationTargetException - 如果底层构造方法抛出异常。
ExceptionInInitializerError - 如果此方法引发的初始化失败
*/
public class ConstructorTest {
//获得无参构造方法
//public Constructor<T> getConstructor(Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException
@Test
public void test1() throws Exception{
//获得Class对象
Class<?> clazz = Class.forName("com.itheima.reflect.User");
System.out.println(clazz);
//获得无参构造方法
Constructor<?> constructor = clazz.getConstructor();
System.out.println(constructor);
//通过构造方法创建对象
Object user = constructor.newInstance();
System.out.println(user);
}
//获得有参构造
@Test
public void test2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//获得Class对象
Class<?> clazz1 = Class.forName("com.itheima.reflect.User");
//通过Class对象获得构造方法
// Constructor<?> cons = clazz1.getConstructor(String.class);
Constructor<?> cons = clazz1.getDeclaredConstructor(String.class);
System.out.println(cons);
//通过构造方法获得对象
//获取权限
cons.setAccessible(true);
Object user = cons.newInstance("sz");
System.out.println(user);
}
//获得所有构造参数
@Test
public void test3() throws ClassNotFoundException{
//获得Class对象
Class<?> class1 = Class.forName("com.itheima.reflect.User");
System.out.println(class1);
//通过Class对象获得所有的构造方法
Constructor<?>[] constructors = class1.getDeclaredConstructors();
for(Constructor con : constructors){
System.out.println(con);
}
}
}
获取成员变量
/**
获取成员变量
Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
Field[] getDeclaredFields()
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
void set(Object obj, Object value)
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
Object get(Object obj)
返回指定对象上此 Field 表示的字段的值
*/
public class FieldTest {
//获取成员变量值
@Test
public void test() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
//1获取Class对象
Class<?> class1 = Class.forName("com.itheima.reflect.User");
System.out.println(class1);
//2根据Class对象获取Field对象
//public Field getField(String name)
Field age = class1.getField("age");
System.out.println(age);
// java.lang.NoSuchFieldException: username
// Field username = class1.getField("username");
Field file_username = class1.getDeclaredField("username");
System.out.println(file_username);
//3调用Field对象的方法 获取变量值
Object user = class1.newInstance();
System.out.println(user);
// public void set(Object obj,Object value)
//
file_username.setAccessible(true);
file_username.set(user, "sz");
System.out.println(user);
// public Object get(Object obj)
Object username = file_username.get(user);
System.out.println(username);
}
}
获得成员方法
/**
获得成员方法
Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Object invoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。
如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。
如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
参数:
obj - 从中调用底层方法的对象
args - 用于方法调用的参数
返回:
使用参数 args 在 obj 上指派该对象所表示方法的结果
public T newInstance()throws InstantiationException, IllegalAccessException
创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。
注意,此方法传播 null 构造方法所抛出的任何异常,包括已检查的异常。使用此方法可以有效地绕过编译时的异常检查,而在其他情况下编译器都会执行该检查。
Constructor.newInstance 方法将该构造方法所抛出的任何异常包装在一个(已检查的)InvocationTargetException 中,从而避免了这一问题。
返回:
此对象所表示的类的一个新分配的实例。
抛出:
IllegalAccessException - 如果该类或其 null 构造方法是不可访问的。
InstantiationException - 如果此 Class 表示一个抽象类、接口、数组类、基本类型或 void; 或者该类没有 null 构造方法; 或者由于其他某种原因导致实例化失败。
ExceptionInInitializerError - 如果该方法引发的初始化失败。
SecurityException - 如果存在安全管理器 s,并满足下列任一条件:
调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝创建该类的新实例
调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包
*/
public class MethodTest {
@Test
public void test1() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//获得Class对象
Class<?> class1 = Class.forName("com.itheima.reflect.User");
//获得Method对象
Method method_sayHello = class1.getMethod("sayHello",String.class);
//执行方法
Object user = class1.newInstance();
Object invoke = method_sayHello.invoke(user,"sz!");
System.out.println(invoke);
}
@Test
//执行私有方法
public void test2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//获得Class对象
Class<?> class1 = Class.forName("com.itheima.reflect.User");
//获得Method对象
Method method_show = class1.getDeclaredMethod("show",String.class);
//执行方法
//Object user = class1.newInstance();
User user = (User)class1.newInstance();
System.out.println("----------user.sayHello()-----------");
System.out.println(user.sayHello("asd"));
method_show.setAccessible(true);
System.out.println("----------执行私有方法-----------");
Object invoke = method_show.invoke(user,"show");
System.out.println(invoke);
}
// 调用static方法
@Test
public void test3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//获取Class对象
Class<?> class1 = Class.forName("com.itheima.reflect.User");
//Object user = class1.newInstance();
//获取方法
Method method = class1.getMethod("fun", String.class);
// method.invoke(user, "fun");
method.invoke(null, "fun");
}
//调用参数是数组类型的方法
@Test
public void test4() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//获取Class对象
Class<?> class1 = Class.forName("com.itheima.reflect.User");
// Object user = class1.newInstance();
//获取方法
Method method1 = class1.getMethod("sum1", int[].class);
int [] sum1 = {1,2,3,4};
method1.invoke(null, sum1);
Method method2 = class1.getMethod("sum2", int[].class);
int [] sum2 = {1,2,3,4,5};
method2.invoke(null, sum2);
//获取方法
Method method3 = class1.getMethod("sum", Integer[].class);
Integer [] sum = {1,2};
//java.lang.IllegalArgumentException: wrong number of arguments
/*
* invoke(Object obj, Object... args)
* Integer是引用类型
* invoke 底层会将其作为两个Object对象处理
* 原本想传递一个数组类型的数据,却解析成两个Object类型
* 所以出现参数数量错误
*/
//method3.invoke(null, sum);
//方式一
//解决方案一:将sum直接强制转换成Object在传递
method3.invoke(null, (Object)sum);
//方式二
//解决方案二:在sum这个数组外层在包装一层数组
Object[] args = {sum};
method3.invoke(null, args);
}
}
反射案例
/**
需求:
使用java中的反射技术将类中的属性与map中的key相同名称的
使用反射技术将key对应的value值赋值给属性
分析:
1.创建Map集合
2.添加元素
3.遍历集合
4.使用反射给属性赋值
4.1 获取Class对象
4.2 获取方法
4.3执行方法赋值
*/
public class ReflectDemo {
@Test
//通过方法实现
public void test() throws Exception{
// 1.创建Map集合
HashMap<String, Object> map = new HashMap<String,Object>();
// 2.添加元素
map.put("username", "sz");
map.put("sex", "man");
map.put("age",18);
Set<String> keySet = map.keySet();
// 3.遍历集合
// 4.使用反射给属性赋值
// 4.1 获取Class对象
Class<?> class1 = Class.forName("com.sz.reflect_demo.Person");
Object person = class1.newInstance();
// 4.2 获取方法
Method[] methods = class1.getDeclaredMethods();
for(String s : keySet){
String methodName = "set"+s;
for (Method method : methods) {
if(method.getName().equalsIgnoreCase(methodName)){
// 4.3执行方法赋值
method.invoke(person,map.get(s));
}
}
}
System.out.println(person);
}
@Test
//通过属性实现
public void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//创建集合
HashMap<String,Object> map = new HashMap<String,Object>();
//添加元素
map.put("username", "zhangsan");
map.put("sex", "man");
map.put("age", 25);
//得到Class对象
Class<?> class1 = Class.forName("com.sz.reflect_demo.Person");
//创建实例对象
Object object = class1.newInstance();
//获得Field对象
Field[] declaredFields = class1.getDeclaredFields();
//遍历集合
Set<String> keySet = map.keySet();
for (String key : keySet) {
for(Field field : declaredFields){
field.setAccessible(true);
if (field.getName().equalsIgnoreCase(key)) {
field.set(object, map.get(key));
}
}
System.out.println(key+" "+map.get(key));
}
System.out.println(object);
}
}