一、反射的引出
通常的正向处理:先有类,再根据类创建对象(根据包名.类名找到类)
范例:
import java.util.Date;
public class ReflectTest {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);//输出系统当前时间
}
}
而反射是根据现有对象倒推类的组成
反射的最核心:Class类(专门描述其他类的组成)
任何一个类在JVM中只有唯一的一个class对象,此对象记录该类的组成结构。当类加载时由JVM产生,用户只能取得此对象无法创建。
二、应用反射
- 要想在java中应用反射,首先取得该类的class对象
1.取得任意类class对象方法:
1)调用Object提供的getClass方法
即调用对象.getClass()取得Class对象
2).类名称.class取得Class对象
3).调用Class类提供的静态方法Class.forName(类的全名称)取得Class对象;
范例:
public class reflectStartTest {
public static void main(String[] args) throws Exception{
Date date=new Date();
System.out.println(date);//----->Sun Mar 31 10:03:24 CST 2019
//1.调用对象.getClass()
System.out.println(date.getClass());
//2.类名称.class
System.out.println(Date.class);
//3.调用Class.forName()
System.out.println(Class.forName("java.util.Date"));
//---->class java.util.Date
System.out.println(int.class);//----> int
System.out.println(Integer.class);//---->class java.lang.Integer
}
}
2.拿到一个类的class对象后,就可以对该类进行以下操作
1).创建该类的新对象
public T newInstance():通过反射实例化对象,使用类中的无参构造进行对象的创建
Class<Date> cls = Date.class;
//用过反射产生Date类的对象
//等同于 Date date = new Date();正向产生对象
Date date = cls.newInstance();
System.out.println(date);
2).取得包名、父类、父接口
a. Package:描述一个类的包信息
Class类提供的getPackage()方法
Class<Test> cls = Test.class;
System.out.println(cls.getPackage().getName());
b. 取得一个类的父类信息:Class
Class类提供的getSuperclass()方法
Class<Test> cls = Test.class;
System.out.println(cls.getSuperclass().getName());
c. 取得一个类的所有父接口
Class类提供的getInterface()方法,返回值是一个Class数组
interface IMessage{}
interface INews{}
class MyClass implements IMessage,INews{}
public class Test {
public static void main(String[] args) throws Exception {
Class<Test> cls = Test.class;
Class[] classes = MyClass.class.getInterfaces();
for(Class cls1:classes){
System.out.println(cls1);
}
}
}
3.取得构造方法、普通方法、普通属性
constructor.setAccessible(true);//动态破坏封装,仅在一次JVM进程中
3.1 Constructor:描述一个类的构造方法
1)取得本类中指定参数的构造方法
Class类中提供的getConstructor(参数):只能取得权限为public的构造方法
Class类中提供的getDeclaredConstructor(参数):可以取得类中所有的构造方法,与权限无关
Class<Person> cls = Person.class;
Constructor constructor = cls.getDeclaredConstructor(Integer.class,String.class);
System.out.println(constructor);
2)取得本类中所有构造方法
Class类中提供的getConstructors():只能取得权限为public的构造方法
Class类中提供的getDeclaredConstructors():可以取得类中所有的构造方法,与权限无关
Class<Person> cls = Person.class;
Constructor[] constructors = cls.getDeclaredConstructors();
for(Constructor constructor:constructors){
System.out.println(constructor);
}
3)作用:创建对象:
Class类的newInstance()实际上调用的是类中的无参构造,如果类中没有无参构造或者权限不是public,此方法无法使用!建议:以后在定义简单java类时,一定要保留一个无参构造.
当类中没有无参构造时,就调用Constructor类提供的newInstance方法使用有参构造来实例化对象 。public T newInstance(Object… initargs)
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ReflectConstructorTest {
public static void main(String[] args) throws Exception {
Class<?> cls=Person.class;//取得class对象
Constructor<?> constructors=cls.getConstructor(String.class,int.class);
//调用Constructor类提供的newInstance方法使用有参构造来实例化对象
System.out.println(constructors.newInstance("zhangsan",18));
}
3.2 Method:描述一个类的普通方法
1)取得类中所有方法
a.取得本类以及父类中的所有权限为public的普通方法(包含静态方法)
public Method[] getMethods() throws SecurityException
b. 只能取得本类中所有方法(包含private方法)
public Method[] getDeclaredMethods() throws SecurityException
2)取得类中指定名称与参数的普通方法
public Method getMethod(String name,Class<?>...parameterTypes)
public Method getDeclaredMethod(String name,Class<?>...parameterTypes)
3)作用:Method类提供的反射调用普通方法
/**
*反射调用普通方法
*obj类的实例化对象
*args 普通方法的参数
*/
public Object invoke(Object obj,Object...args)
class Person {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class Test {
public static void main(String[] args) throws Exception {
//正向处理,调用getter和setter
// Person per = new Person();
// per.setName("张三");
// System.out.println(per.getName());
//-------------利用反射调用方法-----------------------------
//1.先取得class对象
Class<Person> cls = Person.class;
//2.组装方法名称
String setMethodName = "set"+initCap(args[0]);
String getMethodName = "get"+initCap(args[0]);
//3.取得Method对象
Method setMethod = cls.getMethod(setMethodName,String.class);
Method getMethod = cls.getMethod(getMethodName);
//4.取得Person类实例化对象而后调用方法
Person per = cls.newInstance();
setMethod.invoke(per,"张三");
System.out.println(getMethod.invoke(per));
}
//首字母大写方法
private static String initCap(String str){
return str.substring(0,1).toUpperCase()+str.substring(1);
}
}
3.3 Field:描述一个类的普通属性
1)取得类中指定名称属性
public Field getField(String name)
public Field getDeclaredField(String name)
2)取得类中所有属性(同Method)
public Field[] getFields() throws SecurityException ---->取得本类以及父类中的所有权限为public的普通方法(包含静态方法)
public Field[] getDeclaredFields() throws SecurityException ----->只能取得本类中所有方法(包含private方法)
3)Field类提供的设置与取得属性值
a.设置值
/**
* 设置属性值
* @param obj 类的实例化对象
* @param value 要设置的值
*/
public void set(Object obj,Object value)
b.取得值
/**
* 取得属性值
* @param obj 类的实例化对象
*/
public Object get(Object obj)
c.取得属性类型
/**
* 取得属性类型
* @return
*/
public Class<?> getType()
eg:
class Person {
public int age ;
}
public class Test {
public static void main(String[] args) throws Exception {
Class<Person> cls = Person.class;
Field field = cls.getField("age");
Person per = cls.newInstance();
field.set(per,20);
System.out.println(field.get(per));
System.out.println(field.getType());
}
} ----->20 int
3.4动态破坏封装(反射的特性)-只在一次JVM进程中,不是永久破坏,只能通过反射调用
Constuctor、Method、Field类都继承AccessibleObject类
此类中有一个破坏封装的方法:
public void setAccessible(boolean flag) throws SecurityException
nameField.setAccessible(true);//取消封装