一、背景引入
tomcat是由Java编写的,所以可以和servlet合成一个程序。用tomcat启动网站,实际就是将网站与tomcat合成一个项目。
servlet没有主方法,借助tomcat的主方法来启动,tomcat作为进程存在,servlet作为线程存在。
tomcat作为一个早就编写好的程序,是如何调用到刚创建的servlet?
用到的就是反射机制。
二、反射的定义及作用
能够分析类能力的程序称为反射( reflective )。反射机制的功能极其强大,在下面可以看
到, 反射机制可以用来:
- 在运行时分析类的能力。
- 在运行时查看对象, 例如, 编写一个toString 方法供所有类使用。
- 实现通用的数组操作代码。
- 利用Method 对象, 这个对象很像中的函数指针。(from 《Java核心技术》)
三、反射相关的各种类
Java官方文档java.lang.reflect中:
其中AccessibleObject类是Field,Method和Constructor对象的基类。
在Java核心技术(5.7反射)主要涉及的类是Class类、Constructor类、Field类、Method类、Modifier类这五个类。
- Class类:是对类的抽象和集合。
- Constructor类:英文Constructor构造器,所以这个类是和类的构造器信息有关的类。
- Field类:英文Field领域,所以这个类是和类的域信息有关的类。
- Method类:英文Method方法,所以这个类是和类的方法信息有关的类。
- Modifier类:英文Modifier修饰语,所以这个类是和类中的修饰信息有关的类。
1、Class类
一些解释:
- 如果说类是对象抽象和集合的话,那么Class类就是对类的抽象和集合;如同用一个Employee 对象表示一个特定的雇员属性一样, 一个Class 对象将表示一个特定类的属性。
- 它的构造函数是私有的,只有虚拟机才能够创建它的对象
- Object 类中的getClass( ) 方法将会返回一个Class 类型的实例。(Object类是所有类的超类)
常用方法:
返回类型 | 方法名 | 作用 |
---|---|---|
static Class | forName(String className) | 返回描述类名为className 的Class 对象。 |
Object | newlnstance() | 返回这个类的一个新实例。 |
Field[ ] | getFields() | 返回一个包含Field 对象的数组, 这些对象记录这个类或其超类的公有域。 |
Filed[ ] | getDeclaredFields() | 获得这个类(不含超类)所有的域,包括私有变量 |
Constructor[ ] | getConstructors() | 获得这个类所有所有公有构造方法 |
Constructor[ ] | getDeclaredConstructors() | 获得这个类所有的构造方法,包括私有 |
Method[ ] | getdMethods() | 获得所有公有方法,包括从超类继承的 |
Method[ ] | getDeclaredFields() | 获得这个类所有的方法,但不含超类继承的 |
int | getModifiers() | 获取类的修饰 |
- 反射通过以下三种种方式获取类信息(创建Class的对象的方法):
- Class c1 = 对象.getClass()
- Class c1 = 类名.Class
- Class c1 = Class.forName("包名.类名")
- c1.newInstance();根据类信息获取类的实例
代码:
Class c1 = Class.forName("com.工商.Son1")//Class类的静态方法,获得类名"com.工商.Son1"对应的Class对象
Class superc1 = c1.getSuperclass()//获取c1的父类对应的Class对象
Object m = c1.newInstance();//返回一个类的对象
Constructor[] constructors = c1.getDeclaredConstructors() ;//获得这个类所有的构造方法,包括私有
Constructor[] constructors = c1.getConstructors() ;//获得这个类所有所有公有构造方法
Method[] methods = c1.getDeclaredMethods() ;//获得这个类所有的方法,但不含超类继承的
Method[] methods = c1.getdMethods() ;//获得所有公有方法,包括从超类继承的
Field[] fields = c1.getDeclaredFields() ;//获得这个类(不含超类)所有的域,包括私有变量
Field[] fields = c1.getFields() ;//获得类或其超类的公有域
//获取class信息的一段代码实例
Class c1 = Class.forName("com.工商.Son1");
Class superc1 = c1.getSuperclass();
String modifiers = Modifier.toString(c1.getModifiers());
if(modifiers.length()>0) System.out.print(modifiers + " ");
System.out.print("class " + path);
if(superc1 !=null && superc1 != Object.class) System.out.print(" extends " + superc1.getName());
//运行结果:
//public class com.工商.Son1 extends com.工商.PersonA
2、Constructor类
常用方法:
返回类型 | 方法名 | 作用 |
Object | newlnstance(Object[] args) | 构造一个这个构造器所属类的新实例。args 是提供给构造器的参数。 |
String | getName() | 获取构造方法名字,返回字符串 |
int | getModifiers() | 返回一个整型数值,用于描述修饰符 |
Class | getDeclaringClass() | 返冋一个用于描述类中定义构造函数的Class 对象 |
Class[ ] | getParameterTypes() | 返回一个Class[]数组,获取方法的所有参数类型(入参) |
Class[ ] | getExceptionTypes() | 返回一个用于描述方法抛出的异常类型的Class 对象数组 |
代码:
public static void printConstructors(Class c1) {
Constructor[] constructors = c1.getDeclaredConstructors();
for(Constructor c : constructors) {
String name = c.getName();
System.out.println(" ");
String modifiers = Modifier.toString(c.getModifiers());
if(modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(name + "(");
Class[] paramTypes = c.getParameterTypes();
for(int j = 0; j < paramTypes.length; j++) {
if(j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
//运行结果:
//public com.工商.Son1();
//public com.工商.Son1(java.lang.String, int);
3、Method类
常用方法:
返回类型 | 方法名 | 作用 |
String | getName() | 获取方法名字 |
Class | getReturnType() | 获取返回值类型 |
int | getModifiers() | 返回一个整型数值,用于描述修饰符 |
Class | getDeclaringClass() | 返冋一个用于描述类中定义方法的Class 对象 |
Class[ ] | getParameterTypes() | 返回一个Class[]数组,获取方法的所有参数类型(入参) |
Class[ ] | getExceptionTypes() | 返回一个用于描述方法抛出的异常类型的Class 对象数组 |
代码:
public static void printlnMethods(Class c1) {
Method[] methods = c1.getDeclaredMethods();
for(Method method : methods) {
Class retType = method.getReturnType();
String name = method.getName();
System.out.println(" ");
String modifiers = Modifier.toString(method.getModifiers());
if(modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(retType.getName() + " " + name + "(");
Class[] paramTypes = method.getParameterTypes();
for(int j = 0; j< paramTypes.length; j++) {
if(j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
//运行结果:
//public void m1();
//public void m2(java.lang.String, java.lang.String);
4、Field类
常用方法:
返回类型 | 方法名 | 作用 |
String | getName() | 获取域名字 |
Class | getType() | 获取域类型 |
int | getModifiers() | 返回一个整型数值,用于描述修饰符 |
Class | getDeclaringClass() | 返冋一个用于描述类中定义域的Class 对象 |
代码:
public static void printFields(Class c1) {
Field[] fields = c1.getDeclaredFields();
for(Field f : fields) {
Class type = f.getType();
String name = f.getName();
//System.out.print(" ");
String modifiers = Modifier.toString(f.getModifiers());
if(modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.println(type.getName() + " " + name + ";");
}
}
//运行结果:
//public int height;
//public java.lang.String name;
5、Modifier类
常用方法:
代码:
String modifiers = Modifier.toString(c.getModifiers());
- 反射能否获取类的私有属性?
- 可以,setAccessible(true) ,设置为true
6、利用反射分析对象//Java核心技术的完整代码
package objectAnalyzer;
import java.util.ArrayList;
public class ObjectAnalyzerTest {
public static void main(String[] args){
ArrayList<Integer> squares = new ArrayList<>();
for(int i = 1;i <= 5;i ++)
squares.add(i*i);
System.out.println(new ObjectAnalyzer().toString(squares));
}
}
package objectAnalyzer;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
public class ObjectAnalyzer {
private ArrayList<Object> visited = new ArrayList<>();
public String toString(Object obj)
{
if(obj == null) return "null";
if(visited.contains(obj)) return "...";
visited.add(obj);
Class c1 = obj.getClass();
if(c1 == String.class) return (String) obj;
if(c1.isArray()) {
String r = c1.getComponentType() + "[]{";
for(int i = 0; i<Array.getLength(obj); i++) {
if(i > 0) r += ",";
Object val = Array.get(obj, i);
if(c1.getComponentType().isPrimitive()) r += val;
else r += toString(val);
}
return r + "}";
}
String r = c1.getName();
do {
r += "[";
Field[] fields = c1.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for(Field f : fields) {
if(!Modifier.isStatic(f.getModifiers())) {
if(!r.endsWith("[")) r +=",";
r += f.getName() + "=";
try {
Class t = f.getType();
Object val;
val = f.get(obj);
if(t.isPrimitive()) r += val;
else r += toString(val);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
r +="]";
c1 = c1.getSuperclass();
}
while(c1 != null);
return r;
}
}
全文整理自Java核心技术5.7反射。