带有私有字段的类
你们都非常了解字段访问修饰符。如果一个字段有private修饰符,那么我们就不能从外部访问它。
public class Person {
private int age;
public String nickname;
public Person(int age, String nickname) {
this.age = age;
this.nickname = nickname;
}
}
让我们检查Main类中的可访问性:
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.nickname);
// System.out.println(person.age); No access to the field
}
}
我们无权访问年龄领域,但我们确实有反思。:) 在它的帮助下,我们可以访问和使用私有字段。
使用反射从对象中获取私有字段
让我们使用getDeclaredFields()方法获取我们类中所有字段的数组。它返回一个我们可以使用和修改的Field对象:
public static void main(String[] args) {
Field[] fields = Person.class.getDeclaredFields();
List<String> actualFieldNames = getFieldNames(fields);
actualFieldNames.forEach(System.out::println);
}
static List<String> getFieldNames(Field[] fields) {
List<String> fieldNames = new ArrayList<>();
for (Field field : fields)
fieldNames.add(Modifier.toString(field.getModifiers()) + " " + field.getName());
return fieldNames;
}
公开昵称
在getFieldNames方法中,我们从类中获取两个字段。getModifiers 方法返回我们字段的修饰符,getName返回它的名称。现在让我们尝试修改和访问这个字段。首先,让我们尝试从公共字段获取数据:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("nickname");
String nickname = (String) field.get(person);
System.out.println(nickname);
System.out.println(person.nickname);
}
代码健身房
我们可以借助反射和使用我们对对象的引用来访问该字段。一切都很好!让我们进入一个私人领域。
我们会将请求字段的名称更改为我们的私有字段年龄场地:
public static void main(String[]args)throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
int age =(int)field.get(person);
System.out.println(age);
// System.out.println(person.age);
}
我们无法通过创建的对象进行访问,因此请尝试使用反射。我们得到一个错误:
非法访问异常
我们得到一个IllegalAccessException。让我们来看看里面有什么:
让我们试着弄明白。
IllegalAccessException当应用程序试图反射性地创建实例(数组除外)、设置或获取字段或调用方法时抛出,而当前正在执行的方法无权访问指定类、字段的定义,方法或构造函数。
这里的方法也会抛出这个异常。为了避免这种异常,我们将使用一种特殊的方法来访问私有字段。
setAccessible(布尔标志)
此方法可以避免对字段或类进行安全访问检查。我们可以将true或false传递给该方法,以确定是否对该字段执行安全访问检查。让我们尝试修复我们的代码:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
field.setAccessible(true);
int age = (int) field.get(person);
System.out.println("The current value is " + age);
}
让我们看看结果:
伟大的!我们得到了关于我们班级的信息。让我们也尝试通过为它分配一个新值来更改我们的字段:
public static void main(String[]args)throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
field.setAccessible(true);
field.set(person, 19);
int age =(int)field.get(person);
System.out.println("The current value is " + age);
}
改变我们的领域后,我们得到:
让我们尝试调用setAccessible(false)。
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
field.setAccessible(true);
field.set(person, 19);
field.setAccessible(false);
System.out.println("The current value is " + field.get(person));
}
将可访问性恢复为false后,当我们尝试调用get方法时再次遇到异常:
所以在处理私有字段时要小心,不要忘记反射是一个非常强大的工具!
GO TO FULL VERSION