在java编程语言中,为了不让外界访问到类中某些属性和方法,通常将该属性或者方法有private修饰符来修饰。此时用正常的方式(对象名.属性名,对象名.方法名)将无法访问此属性与方法。
但是存不存在其他的方法来访问呢?答案肯定是存在的,这就是java反射带来的便利。
利用反射访问类的私有属性及方法如下:
public class Student{
private String name;
private Integer age;
private Student(Integer age){
this.age = age;
}
public Student(String name){
this.name = name;
}
private void speak(String name){
System.out.println("My name is"+name);
}
}
在利用反射访问Student类中的私有属性和方法之前,我们需要先了解一下反射包中的类:
Constructor:代表类的单个构造方法,通过Constructor我们可以执行一个类的某个构造方法(有参或者无参)来创建对象。
Method:代表类中的单个方法,可以用于执行类的某个普通方法,有参或者无参,拼接可以接受返回值。
Field:代表类中的单个属性,用于set或get属性。
AccessibleObject:以上三个类的父类,提供了构造方法,普通方法和属性的访问控制能力。
使用Class类中的方法可以获得该类中所有的Constructor对象,Method对象,和Field对象。但是仍然无法访问私有化的构造方法,普通方法和私有属性,此时我们可以使用他们继承父类(AccessibleObject)中的setAccessible()方法。来设置或者取消访问检查,以达到访问私有对象的目的。
public static void main(String[] args) throw Exception{
Student student = new Student("xiaoming");
Method[] methods = Student.class.getMethods();
Field[] fields = Student.class.getFields();
for(int i = 0; i < fields.length; i++ ){
fields[i].setAccessible(true);
System.out.println(fields[i].getName);
}
for(int j = 0; j < methods.length; j++ ){
methods[j].setAccessible(true);
System.out.println(methods[j].getName);
methods[j].invoke(student);
System.out.println(methods[j].getName);
}
}
这样我们就获得了私有属性的值。
当然凡事有利就有弊,我们再来说一下Java反射的优缺点:
优点:
- 能够运行时动态获取类的实例,大大提高了系统的灵活性和扩展性。
- 与Java动态编译相结合,额可以实现无比强大的功能。
缺点:
- 使用反射的性能较低。
- 使用反射来说相对不安全。
- 破坏了类的封装性,可以通过反射来获取这个类的属性和私有方法。
现在让我们回到最初的问题:private修饰的方法可以通过反射访问,那么private的意义什么?
- Java的private修饰符不是为了绝对的安全设计的,而是对用户常规使用Java的一种约束。就好比饭店厨房门口挂着"闲人免进"的牌子,但是我们还是可以通过其他的方法来进入厨房。
- 从外部对对象进行常规调用时,能够看到清晰的类结构。