反射在java中是非常重要的。反射是学习java框架的灵魂。
什么是反射,来看张图:
简单来说,我们在之前,一般都是在用new来开辟空间,调用对象。也就是说我们通过包名,寻找类方法来进行操作。这样的方法我们可以称之为“正”操作,而反方法我们需要的是逆向思维,去反推。
反射就是根据已有类的对象反推类的组成:
在反射的世界里,看重的不在是一个对象,而是对象身后的组成。
Class类:描述具体类的信息。Class类对象用JVM产生,当类装载的时候,JVM产生改类的唯一class对象。
class类对象的三种实例化模式:
Class类是描述整个类的概念,也是整个反射的操作源头,在使用Class类的时候需要关注的依然是这个类的对象。而这个类的对象的产生模式一共有三种:
Class cls1 = data.getClass();
Class cls2 = Data.class
Class cls3 = Class.forName("java.util.Data")
我们用的最多的一般是第三种,在导入数据库的时候第三种方法比较简单。
Construct类:描述类中的构造方法类
两个方法:
1、取得指定参数类型的构造:
public Constructor<T> getConstructor(Class>... parameterTypes)
throws NoSuchMethodException, SecurityException
2、取得类中的所有构造:
public Constructor>[] getConstructors() throws SecurityException
代码实现
package TestClass;
import java.lang.reflect.Constructor;
class Person {
public Person() {
}
public Person(String name) {
}
public Person(String name, int age) {
}
}
public class Class1 {
public static void main(String[] args) {
Class> class1 = Person.class;
Constructor>[] constructors = class1.getConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor> constructor = constructors[i];
System.out.println(constructor);
}
}
}
我们可以看出是直接利用了Constructor类中的toString()方法取得了构造方法的完整信息(包含方法权限,参数列表),而如果只使用了getName()方法,只会返回构造方法的包名.类名。
在定义简单JAVA类的时候一定要保留一个无参构造:
Class类通过反射实例化类对象的时候,只能够调用类中的无参构造。如果现在类中没有无参构造则无法使用Class类调用,只能够通过明确的构造调用实例化处理。
Method类:取得类中的普通方法
1、
a.
取得类中的全部方法:
getMethods() :取得本类以及父类中所有权限为public方法的普通方法
getDeclaredMethods():取得本类中的普通方法,无关权限
代码实现:
import java.lang.reflect.Method;
class Person{
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
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;
}
}
public class Test6 {
public static void main(String[] args) {
Class> class1 = Person.class;
Method[] methods = class1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
b.
取得类中指定参数方法
//根据方法以及参数取得指定普通方法,权限为public
//如果指定名称的方法在本类中没有,会继续在父类中查找
getMethod(String name,Class>...parameterTypes)
//只在本类找指定名称,以及参数类型的普通方法,无关权限
getDeclaredMethod(String name,Class>...parameterTypes)
c.调用拿到的普通方法
//通过反射调用拿到的Method方法
invoke(Object obj,Object...args)
代码实现:
public class Test6 {
public static void main(String[] args)
throws Exception {
// Class> class1 = Person.class;
// Method[] methods = class1.getMethods();
// for (Method method : methods) {
// System.out.println(method);
// }
Class> cls = Class.forName("TestClass.Person");
// 任何时候调用类中的普通方法都必须有实例化对象
Object obj = cls.newInstance();
// 取得setName这个方法的实例化对象,设置方法名称与参数类型
Method setMethod = cls.getMethod("setName", String.class);
// 随后需要通过Method类对象调用指定的方法,调用方法需要有实例化对象
// 同时传入参数
setMethod.invoke(obj, "y"); // 相当于Person对象.setName("y") ;
Method getMethod = cls.getMethod("getName");
Object result = getMethod.invoke(obj); // 相当于Person对象.getName() ;
System.out.println(result);
}
}
Filed类:反射类中的属性
a.取得所有的属性
getFile():取得本类以及父类中所有public权限属性。静态和全局都能看到
getDeclaredMethods():取得本类中的所有属性,只找本类的与权限无关
b.取得指定名称属性
getFile(String name):取得本类以及父类中所有public权限属性。
getDeclared file(String):取得本类中的所有属性
c.取得属性类型
gettype()
d.动态破坏封装性(!!!!需谨慎使用)
//动态破坏封装性,只此一次。在当前的JVM进程中
filed.setAccessible()
代码实现:
import java.text.DateFormat.Field;
class Person {
public String name;
public int age;
}
class Student extends Person {
private String school;
}
public class Test7 {
public static void main(String[] args) throws Exception {
Class> cls = Class.forName("TestClass.Student");
{ // 普通代码块
// 第一组-取得类中全部属性
Field[] fields = cls.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
System.out.println("------------------------");
{
// 第二组-取得类中全部属性
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
}