1、访问字段
对任意的一个Object实例,获取了它的Class,就可以获取一切信息,通过反射读写字段会破坏对象的封装性。
Java提供了一下方法来通过Class实例获取字段信息:
- Field getField(name): 根据字段名获取某个public的field(包括父类)
- Field getDeclaredField(name): 根据字段名获取当前类的某个field(不包括父类)
- Field[] getFields(): 获取所有public的field(包括父类)
- Field[] getDeclaredFields(): 获取当前类的所有字段(不包括父类)
public class FieldTest {
public static void main(String[] args) throws NoSuchFieldException {
Class clazz = Student.class;
System.out.println(clazz.getField("age"));
System.out.println(clazz.getField("name"));
System.out.println(clazz.getDeclaredField("address"));
}
class Student extends Person{
public int age;
private String address;
}
class Person{
public String name;
}
}
运行结果:
public int Reflect.FieldTest$Student.age
public java.lang.String Reflect.FieldTest$Person.name
private java.lang.String Reflect.FieldTest$Student.address
获取到一个Field对象,可以通过Field对象获取到该对象的名称、类型、修饰符、值等信息。
- getName(): 返回字段名称
- getType(): 返回字段类型,是一个Class实例
- getModifiers(): 返回字段的修饰符,是一个int,不同bit表示不同含义
Field s = String.class.getDeclaredField("value");
int j = s.getModifiers();
System.out.println(s.getName());
System.out.println(s.getType());
System.out.println(Modifier.isPublic(j));
System.out.println(Modifier.isAbstract(j));
System.out.println(Modifier.isPrivate(j));
System.out.println(Modifier.isStatic(j));
执行结果:
value
class [C
false
false
true
false
使用get(Object)方法获取Field的值
Object person = new Person("Mark");
Class claz = person.getClass();
Field fie = claz.getDeclaredField("name");
fie.setAccessible(true);//无论是public或者private,一律允许访问
Object value = fie.get(person);
System.out.println(value);
static class Person{
public String name;
public Person(String name){
this.name = name;
}
}
执行结果:
Mark
使用Field.set(Object,Object)实现设置字段值,第一个参数是指定的实例,第二个参数是待修改的值。
Person person = new Person("Mark");
System.out.println(person.getName());
Class claz = person.getClass();
Field fie = claz.getDeclaredField("name");
fie.setAccessible(true);//无论是public或者private,一律允许访问
//设置字段值
fie.set(person, "John");
System.out.println(person.getName());
运行结果:
Mark
John
2、 调用方法
通过Class实例可以获取所有Method的信息,Java提供了一下几个方法来获取Method。
- Method getMothod(name, Class…): 获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class…): 获取当前类的某个Method(不包括父类)
- Method[] getMethods(): 获取所有public的Method(包括父类)
- Method[] getDeclareMethods(): 获取当前类的所有Method(不包括父类)
//反射获取方法
public class MethodTest {
public static void main(String[] args) throws NoSuchMethodException {
Class clazz = Student.class;
//有参public方法
System.out.println(clazz.getMethod("getScore", String.class));
//有参private方法
System.out.println(clazz.getDeclaredMethod("getPhone", int.class));
//无参public父类方法
System.out.println(clazz.getMethod("getName"));
}
class Student extends Person{
public int getScore(String score){
return 100;
}
private int getPhone(int phone){
return 12345;
}
}
class Person{
public String getName(){
return "Mark";
}
}
}
执行结果:
public int Reflect.MethodTest$Student.getScore(java.lang.String)
private int Reflect.MethodTest$Student.getPhone(int)
public java.lang.String Reflect.MethodTest$Person.getName()
获取到Method对象,就可以获取该方法的所有信息,java提供了以下方法对方法进行操作:
- getName(): 返回方法名称
- getReturnType(): 返回方法返回值类型,是一个Class实例
- getParameterTypes(): 返回方法的参数类型,是一个Class数据
- getModifiers():返回方法的修饰符,是一个int类型,不同数字代表不同含义
//获取方法的详细信息
Method method = clazz.getMethod("getScore", String.class);
System.out.println(method.getName());//方法名
System.out.println(method.getReturnType());//返回类型
System.out.println(method.getParameterTypes());//方法参数类型
System.out.println(method.getModifiers());//方法的修饰符
执行结果:
getScore
int
[Ljava.lang.Class;@6ff3c5b5
1
2.1 调用方法
获取到一个Method方法时,不仅可以获取该方法对象的所有信息,还可以对方法进行操作。调用方法。
利用反射调用String的length()方法,使用Method的invoke方法就相当于调用该方法,invoke的第一个参数是对象实例,后面的可变参数与方法参数一致。
String str = "Hello World";
Method m1 = String.class.getMethod("length");
int length = (int) m1.invoke(str);
System.out.println(length);
调用非public方法,使用Method.setAccessible(true)方法
//调用private方法
User user = new User();
Method m2 = user.getClass().getDeclaredMethod("setName", String.class);
m2.setAccessible(true);
String band = (String) m2.invoke(user,"Oasis");
System.out.println(band);
static class User{
String name;
private String setName(String name){
return name;
}
}
执行结果:
Oasis
处理多态:子类覆写了父类的方法,从父类获取到的方法,作用于子类时,调用的是子类的方法。
结论:使用反射调用方法时,仍然遵守多态规则。
//处理多态
Method m3 = Animals.class.getMethod("run");
m3.invoke(new Cat());
class Animals{
public void run(){
System.out.println("Animals:I can run");
}
}
class Cat extends Animals{
public void run(){
System.out.println("Cat:I can run");
}
}
执行结果:
Cat:I can run
2.2 调用构造方法
使用Class调用newInstance()方法来创建新的实例,但通过此种方法只能调用该类的public无参数构造方法。
要解决上面的问题,Java的反射API提供了Constructor对象,包含一个构造方法的所有信息,可以创建一个实例,调用结果总是返回实例。
Constructor类提供了一下方法:
- getConstructor(Class…): 获取某个public的Constructor
- getDeclaredconstructor(Class…): 获取某个Constructor
- getConstructors(): 获取所有public的Constructor
- getDeclaredConstructors(): 获取所有Constructor
//获取构造方法Integer(int)
Constructor cons = Integer.class.getConstructor(int.class);
Integer n = (Integer) cons.newInstance(132);
System.out.println(n);
//获取构造方法String(String)
Constructor cons1 = String.class.getConstructor(String.class);
String str = (String) cons1.newInstance("hello world");
System.out.println(str);
2.3 获取继承关系
2.3.1 获取普通类的Class
获取Class对象的三种方法:
使用.class获取某个Class对象
Class cls = String.class;
使用getClass()方法获取
String str = "";
Class cls = str.getClass();
使用Class.forName(“”)方法获取,需要传入类的完整名称
Class cls = Class.forName("java.lang.String");
2.3.2 获取父类的Class
使用getSuperclass()方法
@Test
public void test(){
Class clazz = Integer.class;
Class supCls = clazz.getSuperclass();
System.out.println(supCls);
Class sup2Cls = supCls.getSuperclass();
System.out.println(sup2Cls);
System.out.println(sup2Cls.getSuperclass());
}
执行结果:
class java.lang.Number
class java.lang.Object
null
2.3.3 获取interface
通过getInterfaces()方法,返回一个数组。
/**
* 获取接口
* */
@Test
public void test1(){
Class cls = Integer.class;
Class[] clazz = cls.getInterfaces();
for (Class inface : clazz){
System.out.println(inface);
}
}
执行结果:
interface java.lang.Comparable
2.3.4 继承关系
判断一个实例是否是某个类型时,使用instanceof操作符。
@Test
public void instanceofTest(){
Object obj = Integer.valueOf(123);
System.out.println(obj instanceof Double);//false
System.out.println(obj instanceof String);//false
System.out.println(obj instanceof Integer);//true
System.out.println(obj instanceof Number);//true
}
判断一个实例向上转型是否成立,使用isAssignableFrom()方法
@Test
public void assignableFrom(){
//Number<--------可以转为-----Integer
System.out.println(Integer.class.isAssignableFrom(Integer.class));//true
System.out.println(Integer.class.isAssignableFrom(String.class));//false
System.out.println(Integer.class.isAssignableFrom(Number.class));//false
System.out.println(Number.class.isAssignableFrom(Integer.class));//true
}