Java’s One…

0x01

何为反射

正向

  • 导入类包(import)
  • 实例化对象(new)
  • 调用属性(object.field_name)
  • 调用方法(object.method_name)

反向
与正向相对应调用

  • java.lang.Class
  • java.lang.reflect.Constructor
  • java.lang.reflect.Field
  • java.lang.reflect.Method

反射不需要有明确的类型对象,使用Object表示即可。

java.lang.Class

内部可以记录类的成员、接口等信息,其为一个表示类的类。

类定义:

1
2
3
public final class Class<T>
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement

获取Class类。

  1. public final Class<?> getClass()
  2. 使用类名.class
  3. 1. public static Class<?> forName(String className) throws ClassNotFoundExceptio

第二种多用于程序开发,第三种多用框架设计,为反射机制使用的方法。

forName后续

  • 实例化对象
1
public T newInstance() throws InstantiationException,IllegalAccessException

这是一个Class类的一个无参构造方法,也就会调用所表示类的无参构造方法,返回一个Class所表示的类的实例。

  • 获取类中构造方法
  1. public Constructor<?>[] getConstructors()throws SecurityException

  2. public Constructor<T> getConstructor(Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException

返回java.lang.reflect.Constructor类

Demo:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");

Constructor<?>[] cons = cls.getConstructors();

for (int i = 0; i < cons.length; i++) {
System.out.println(cons[i]);
}
}

Show:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
public java.lang.String(byte[])
public java.lang.String(int[],int,int)
public java.lang.String()
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String(char[],int,int)
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)

关于Class有参构造函数

函数定义:

1
public T newInstance(Object... initargs)throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException

有参构造函数调用Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Student {
private String name;

private Integer age;

public Student(String name, Integer age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "name:" + this.name + ";age:" + this.age;
}
}

public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.test.Student");

Constructor<?> con = cls.getConstructor(String.class, Integer.class);

Object stu = con.newInstance("idlefire", 21);
System.out.println(stu);
}
}

Show:

1
name:idlefire;age:21

Class类调用无参构造,Constructor类调用有参构造方法

  • 获取类中方法

获取父类以及本类全部方法

  1. Method[] getMethods()throws SecurityException```
    1
    2
    3

    获取父类指定方法
    1. ```public Method getMethod(String name,Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException

获取本类全部方法

  1. public Method[] getDeclaredMethods()throws SecurityException

获取本类指定方法

  1. public Method getDeclaredMethod(String name,Class<?>... parameterTypes)throwsNoSuchMethodException,SecurityException

String name 指定是方法名

  • 反射中的invoke方法

方法定义:

1
public Object invoke(Object obj,Object... args)throws IllegalAccessException,IllegalArgumentException,InvocationTargetException

利用上面获取的Method对象,当该对象调用invoke方法时,相当与从指定对象中调用该Method所代表的方法。

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.test.Student4");

Object obj = cls.newInstance();

Method setnameMethod = cls.getMethod("setName", String.class);

Method getnameMethod = cls.getMethod("getName");

setnameMethod.invoke(obj, "idlefire");

System.out.println(getnameMethod.invoke(obj));

}


class Student4 {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

Show:

  • 利用反射调用类中属性

包含继承类
获取全部属性

  1. Field[] getFields() throws SecurityException```
    1
    2
    3

    获取指定属性
    1. ```public Field getField(String name)throwsNoSuchFieldException,SecurityException

仅限于本类
获取全部属性

  1. Field[] getDeclaredFields()throws SecurityException```
    1
    2
    3

    获取指定属性
    1. ```public Field getDeclaredField(String name)throws NoSuchFieldException,SecurityException

设置和获取属性

1
2
3
4
5
6
7
8
public void set(Object obj,
Object value)
throws IllegalArgumentException,
IllegalAccessException
...
public Object get(Object obj)
throws IllegalArgumentException,
IllegalAccessException

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Student5 {

private String name;

}
...
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.test.Student5");

Object obj = cls.newInstance();

Field namefield = cls.getDeclaredField("name");

namefield.setAccessible(true);

namefield.set(obj, "idlefire");

System.out.println(namefield.get(obj));

}
}

其中setAccessible方法是为了能够访问非公开的属性,在Construction,Method,Field三个类中有一个共同的父类AccessibleObject,定义了取消封装的操作:setAccessible(Boolean flag)。

未使用setAccessible:

(ง •_•)ง