1、反射
(1)概念:
反射:将类的各个组成部分封装为对象,对于任何一个实体类,都能够知道这个类的属性和方法,对于任意一个对象,都能够调用它的任意方法和属性。
(2)好处:
可以在程序运行的过程中,操作这些对象。
解耦,提高可扩展性。
(3)获取Class对象的三种方法:
Class.forname("包名.类名");此方式用于配置文件方式,通过配置文件加载类名。
类名.class,多用于参数传递。
对象.getClass(),用于对象获取字节码对象的方式。
(4)三种方法获取Class对象:
Person类:
package pers.reflect.person; public class Person { private String name; private int age; public Person(){ } public Person(String name,int age){ this.name=name; this.age=age; } public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
测试类:
import pers.reflect.person.Person; public class ReflectDemo { public static void main(String[] args) throws Exception { Class c1 = Class.forName("pers.reflect.person.Person"); System.out.println("c1 = " + c1); Class c2 = Person.class; System.out.println("c2 = " + c2); Person p1 = new Person(); Class c3 = p1.getClass(); System.out.println("c3 = " + c3); System.out.println(c1==c2); System.out.println(c2==c3); System.out.println(c1==c3); } }
通过程序运行结果可以看出,不管通过哪种方式,获取的字节码文件对象是同一个。也就是说,运行期间,一个类只产生一个Class对象。
2、Class对象获取成员变量
(1)Class类的常用方法(获取Field对象):
创建Person类:
package pers.reflect.person;
public class Person {
private String name;
private int age;
public String hobby;
public String height;
protected String sex;
String address;
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", hobby=" + hobby
+ ", height=" + height + ", sex=" + sex + ", address=" + address
+ "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.lang.reflect.Field;
import pers.reflect.person.Person;
public class ReflectDemo {
public static void main(String[] args) throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Class c = Person.class;
System.out.println("getFields(),获取公共的成员变量:");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("getField(),获取指定的公共的成员变量:");
Field hobbyField = c.getField("hobby");
System.out.println(hobbyField);
System.out.println("getDeclaredFields(),获取所有的成员变量,与修饰符无关。");
Field[] fields1 = c.getDeclaredFields();
for (Field field : fields1) {
System.out.println(field);
}
System.out.println("获取私有的指定的成员变量");
Field nameField = c.getDeclaredField("age");
System.out.println(nameField);
}
}
(2)Field类的常用方法:
返回变量的类型:
返回属性的名字:
import java.lang.reflect.Field; import pers.reflect.person.Person; public class ReflectDemo1 { public static void main(String[] args) { Class c = Person.class; System.out.println("getDeclaredFields(),获取所有的成员变量,与修饰符无关。"); System.out.println(); Field[] fields1 = c.getDeclaredFields(); for (Field field : fields1) { System.out.println("成员变量:"+field); System.out.println("属性的类型:"+field.getType()); System.out.println("属性的名字:"+field.getName()); System.out.println(); } } }
import java.lang.reflect.Field; import pers.reflect.person.Person; public class ReflectDemo2 { public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Class c = Person.class; System.out.println("getField(),获取指定的公共的成员变量:"); Field hobbyField = c.getField("hobby"); System.out.println(hobbyField); Person p=new Person(); Object value=hobbyField.get(p); System.out.println(value); hobbyField.set(p, "张可可"); System.out.println(p); System.out.println(); } }
访问不是被public修饰的成员变量(要用暴力反射,否者无法访问):
import java.lang.reflect.Field; import pers.reflect.person.Person; public class ReflectDemo3 { public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Class c = Person.class; Field nameField = c.getDeclaredField("name"); nameField.setAccessible(true);//暴力反射 System.out.println(nameField); Person p = new Person(); Object value = nameField.get(p); System.out.println(value); nameField.set(p, "赵晓霞"); System.out.println(p); } }
setAccessible(true);忽略权限修饰符的安全检查。
3、获取构造方法
package pers.reflect.Constructor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import pers.reflect.person.Person;
public class ReflectDemo1 {
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException, InvocationTargetException {
Class c = Person.class;
System.out.println("getDeclaredConstructors(),获取所有的构造方法:");
Constructor[] cons = c.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println();
System.out.println("getConstructors(),获取所有的构造方法:");
Constructor[] cons1 = c.getConstructors();
for (Constructor con : cons1) {
System.out.println(con);
}
System.out.println();
Constructor con=c.getConstructor(String.class,int.class);
Object p=con.newInstance("张珊珊",12);
System.out.println(p);
Constructor con1=c.getConstructor();//空参数的构造方法创建Person类对象
Object p1=con1.newInstance();
System.out.println(p1);
}
}
4、获取成员方法
(1)常用方法:
public Method getMethod(String name, Class<?>... parameterTypes) 获取Public修饰的一个方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取所有权限的一个方法
public Method[] getMethods() 本类与父类中所有public 修饰的方法所有方法
public Method[] getDeclaredMethods() 获取本类中所有的方法
(2)应用:
package pers.reflect.person;
public class Person {
private String name;
private int age;
public String hobby;
public String height;
protected String sex;
String address;
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
protected void sports() {
System.out.println("我爱运动");
}
private void sport() {
System.out.println("我不爱运动");
}
public String toString() {
return "Person [name=" + name + ", age=" + age + ", hobby=" + hobby
+ ", height=" + height + ", sex=" + sex + ", address=" + address
+ "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void study(String name){
System.out.println(name+"爱学习");
}
}
获取公共的空参的成员方法:
package pers.reflect.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.StubNotFoundException;
import pers.reflect.person.Person;
public class reflectDemo {
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Class c = Person.class;
Method study_method = c.getMethod("study");
Person p = new Person();
study_method.invoke(p);
}
}
获取公共的带参数的成员方法:
package pers.reflect.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;
public class reflectDemo {
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Class c = Person.class;
Method study_method1 = c.getMethod("study",String.class);
Person p = new Person();
study_method1.invoke(p,"Tom");
}
}
获取所有的公共的方法:
package pers.reflect.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;
public class reflectDemo {
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Class c = Person.class;
Method[] methods = c.getMethods();
for (Method method:methods){
System.out.println(method);
}
}
}
获取方法名字:
package pers.reflect.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;
public class reflectDemo {
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Class c = Person.class;
Method[] methods = c.getMethods();
for(Method method:methods){
System.out.println(method.getName());
}
}
}
获取所有的方法(忽略权限修饰符):
package pers.reflect.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;
public class reflectDemo {
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Class c = Person.class;
Method[] methods = c.getDeclaredMethods();
for(Method method:methods){
method.setAccessible(true);
System.out.println(method);
}
}
}
5、反射的好处(转载自博客园:https://www.cnblogs.com/bihanghang/p/9992237.html)
我们在第一次接触反射的时候,总会有个很大的疑问,反射看起来好麻烦啊,各种get.get,他究竟有什么好处,能用来做什么呢?
我们先来看一下《编程思想》这本书中是怎么说的.
RTTI和反射之间真正的区别只在于,对RTTI来说,编译器在在编译时打开和检查.class文件.(换句话说,我们可以用"普通"方式调用对象的所有方法).对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件。 --《编程思想》
这段话看起来很叼的样子,有点云里雾里的,首先RTTI的意思就是以普通的方式来创建对象,调用方法,就是我们常用的new
关键字。这段话的意思简化版就是:编译器将.java文件编译成.class文件之后,普通方式创建的对象就不能再变了,我只能选择是运行还是不运行这个.class文件。是不是感觉很僵硬,假如现在我有个写好的程序已经放在了服务器上,每天供人家来访问,这时候Mysql数据库宕掉了,改用Oracle,这时候该怎么怎么办呢?假如没有反射的话,我们是不是得修改代码,将Mysql驱动改为Oracle驱动,重新编译运行,再放到服务器上。是不是很麻烦,还影响用户的访问。
假如我们使用反射Class.forName()来加载驱动,只需要修改配置文件(配置文件不参与编译)就可以动态加载这个类,Class.forName()生成的结果在编译时是不可知的,只有在运行的时候才能加载这个类,换句话说,此时我们是不需要将程序停下来,只需要修改配置文件里面的信息就可以了。这样当有用户在浏览器访问这个网站时,都不会感觉到服务器程序程序发生了变化。
所以在《Mybatis技术原理与实战》是这么说反射的好处的。
配置性大大提高,如同Spring IOC容器,给很多配置设置参数,使得java应用程序能够顺利跑起来,大大提高了Java的灵活性和可配置性,降低模块间的耦合。--《Mybatis技术原理与实战》
简单来说就是,没有反射的话如果想要调用其他方法和属性就必须重新修改代码,再编译运行。使用反射修改代码后就不需要再次编译程序了