反射
1.什么是反射
java反射就是程序在运行状态中,对于任何一个类或者对象,都可以通过反射获取其任意权限的属性和方法,并且还可以对其进行修改;这也就导致java被认为是动态语言的原因(但java并不是动态语言,动态语言是程序在运行时允许对程序中结构或者变量类型进行修改的语言,比如python,Ruby)
2.反射与java封装性是否存在冲突
java具有三大特性:封装、继承、多态,我们知道java中所有属性方法都具有权限,四种权限级别从高到低分别为:public、protected、缺省、private。对于private权限的属性和方法我们一般只能在当前类中获得,在其它类中我们是无法获得私有属性和方法的,反射却可以获得。但这并不存在矛盾,因为有时候程序在运行前我们并不知道该加载的是哪个类,而在程序运行起来后才能知道,这时候我们就可以通过反射进行获取(例如我们在需要登录某个网页,因此需要通过Login类来获取其属性和方法,但此时服务器已经运行起来了,因此我们就可以通过反射来获取其属性和方法)
3.关于Class实例的理解
我们java代码在经过javac.exe后会生成多个.class文件,然后再通过java.exe命令之后会将这些.class文件进行加载到内存,这些加载到内存中的类我们称为运行时类,而每一个运行时类其实就是Class的一个实例,而且每一个运行时类在JVM中只有一个Class实例。
4.如何获取Class实例
基本类Person
public class Person {
public String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String show(String nation){
System.out.println("我的国籍是"+nation);
return nation;
}
//私有方法
private void show(){
System.out.println("我的年龄是:"+age);
}
private static void show(int age){
System.out.println("我的年龄是" + age);
}
}
4.1第一种方法:通过Class的静态方法Class.forName(“路径+类名"),通常这也是最常用的方法。
Class class1=Class.forName("路径+类名");
4.2第二种方法:通过类对象中的getClass()方法来获取
Person person1 = new Person("张三", 12);
Class class2 = person1.getClass();
4.3第三种方法:通过类的静态属性.Class来获取
//这里有可能会抛一个异常 ClassNotFoundException
Class class3=Person.class;
注意:这三个实例其实是同一个Class的实例
5.通过反射获取类的属性和方法。
5.1获取属性
@Test
public void test3() throws Exception {
//1.获取运行时类实例
Class clazz2 = Person.class;
//2.获取运行时类的对象,这个操作是访问类中非静态属性时才需要创建,如果访问的是静态属性
//那么不需要创建这个属性
Person p = (Person)clazz2.newInstance();
//3.获取属性
Field name=clazz2.getDeclaredField("name");
//4.使属性可见,如果获取的属性不是private,则可写可不写,但如果获取的是private,则需要写
name.setAccessible(true);
//5.修改属性的值,第一个参数是调用的对象是谁,第二个参数是修改为什么值
name.set(p,"China");
//6.输出属性值
System.out.println(name.get(p));
}
5.2获取方法
@Test
public void testMethod() throws Exception {
//1.获取实例
Class clazz = Person.class;
//2.获取运行时类的对象
Person per = (Person)clazz.newInstance();
//3.获取调用方法,第一个参数是方法名,第二个参数是可变参数列表
Method show = clazz.getDeclaredMethod("show", String.class);
//4.使方法可见
show.setAccessible(true);
//5.调用方法,第一个参数是调用的对象是谁,第二个是传入参数
String china = (String)show.invoke(per, "China");
System.out.println(china);
/*调用静态方法*/
//获取实例
Class personClass = Person.class;
//可以不用写对象S
//2.调用方法
Method show1 = personClass.getDeclaredMethod("show", int.class);
//3.使静态私有方法可见
show1.setAccessible(true);
//调用方法
show1.invoke(personClass, 28);
}
5.3获取构造器
@Test
public void testConsttuctor() throws Exception {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
Person china = declaredConstructor.newInstance("China", 20);
System.out.println(china);
}
6.反射动态性的体现
@Test
public void testDynamic(){
String classPath="";
int num=new Random().nextInt(3);
switch (num){
case 0:
classPath="java.lang.Object";
break;
case 1:
classPath="反射.Person";
break;
case 2:
classPath="java.util.date";
break;
}
try {
testGetInstance(classPath);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testGetInstance(String classPath) throws Exception {
Class<?> aClass = Class.forName(classPath);
System.out.println(aClass);
}