1 反射
反射的应用:
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException{
//String类的实例
String str = new String();
//String其实也是一个实例对象 它是Class类的实例
//任何类的Class的实例对象有三种获取方式
//第一种 每个类都有一个隐含的静态成员变量class
Class c1 = String.class;
//第二种 通过该类的getClass方法获取
Class c2 = str.getClass();
//第三种 Class.forName()
Class c3 = Class.forName("java.lang.String");
System.out.println(c1 == c2 & c2 == c3);
//c1 c2 c3叫做class type 可以通过类类型创建类的实例
String st = (String) c1.newInstance();
}
1.1 java.lang.Class
所有的类都是java.lang.Class类的实例
2 类的加载
2.1静态加载
new的对象都是在编译时对类进行加载
String str = new String();
2.2 动态加载
在运行时对类进行加载
String st = (String) c1.newInstance();
2.3 使用场景
在静态加载类的时候如果代码中某一个类不存在,就会报错,如果运用动态加载就会解决这个问题,
1 问题场景 当Word存在Excel不存在的时候 就会报错
public class Office {
public static void main(String[] args) {
if("Word".equals(args[0]))
{
Word w = new Word();
w.start();
}
if("Excel".equals(args[0]))
{
Excel e = new Excel();
e.start();
}
}
}
2 用动态加载解决该问题
public class OfficeBetter {
public static void main(String[] args) throws Exception {
Class c = Class.forName(args[0]);
OfficeAble of = (OfficeAble)c.newInstance();
of.start();
}
}
//通用接口
public interface OfficeAble {
public void start();
}
//Word 类
public class Word implements OfficeAble {
public void start()
{
System.out.println("World is started!");
}
}
3 获取方法信息
/**
* 打印类的信息,包括类的成员变量、成员函数
*
* @param args
*/
public static void printClassInfo(Object obj) {
// 获取类信息 要先获取类类型
Class c = obj.getClass();
// 获取类名称
System.out.println("c类名称:" + c.getName());
/*
* 获取类方法 Method类是方法类 getMethods()获取的是所有public的方法 包括父类继承而来的
* getDeclaredMethods()获取的是该类自己声明的所有方法 不问访问权
*/
Method[] m1 = c.getMethods();
Method[] m2 = c.getDeclaredMethods();
for (Method m : m1) {
// 方法的名称
System.out.println("方法的名称:" + m.getName());
// 方法的返回类型的类类型
Class returnType = m.getReturnType();
System.out.println("返回类型的类类型:" + returnType);
System.out.println("返回类型的类类型的名字:" + returnType.getName());
// 获取参数类型的类类型
Class[] paramTypes = m.getParameterTypes();
for (Class p : paramTypes) {
// 参数的名称
System.out.println("参数名:" + p.getName());
}
}
}
4 获取成员变量&构造函数
/**
* 打印类的信息,包括类的成员变量、成员函数
*
* @param args
*/
static void printFieldInfo(Object obj) {
Class c = obj.getClass();
/*
* 成员变量也是对象
* java.lang.reflect.Field
* Field封装了了关于成员变量的操作
* getFields() 获取所有public的成员变量
* getDeclaredFields() 获取所有该类声明的成员变量
*/
Field[] fList = c.getDeclaredFields();
for(Field f : fList)
{
//得到成员变量的类型的类类型
Class fType = f.getType();
System.out.println("成员变量类型的类类型:" + fType.getName());
//得到成员变量的名称
String fName =f.getName();
System.out.println("成员变量名:" + fName);
}
}
/**
* 打印类的信息,包括类的构造函数
*
* @param args
*/
static void printConInfo(Object obj) {
Class c = obj.getClass();
/*
* 构造函数也是对象
* java.lang.Constructor 封装了了关于构造函数的操作
* getFields() 获取所有public的成员变量
* getDeclaredFields() 获取所有该类声明的成员变量
*/
Constructor[] conList = c.getConstructors();
for(Constructor con : conList)
{
//得到构造函数的类型的类类型
Class conType = con.getClass();
System.out.println("成员变量类型的类类型:" + con.getName());
//得到构造函数的入参
Class[] pType=con.getParameterTypes();
for(Class p :pType)
{
//入参的类类型
System.out.println("入参的类类型:" + p.getName());
}
}
}
5 方法的反射
public class MethodDemo {
public static void main(String[] args) {
// 要获取print(int ,int )方法 1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型
A a1 = new A();
Class c = a1.getClass();
/*
* 2.获取方法 名称和参数列表来决定 getMethod获取的是public的方法 getDelcaredMethod自己声明的方法
*/
try {
Method m = c.getDeclaredMethod("print", int.class, int.class);
Method m1 = c.getDeclaredMethod("print", new Class[] { int.class, int.class });
// 方法的反射操作
// a1.print(10, 20);方法的反射操作是用m对象来进行方法调用 和a1.print调用的效果完全相同
a1.print(10, 9);
Object o1 = m.invoke(a1, new Object[] { 10, 9 });
Object o2 = m1.invoke(a1, 10, 9);
// 方法如果没有返回值返回null,有返回值返回具体的返回值
// 获取方法print(String,String)
// 用方法进行反射操作
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class A {
public void print() {
System.out.println("helloworld");
}
public void print(int a, int b) {
System.out.println(a + b);
}
public void print(String a, String b) {
System.out.println(a.toUpperCase() + "," + b.toLowerCase());
}
}
6 通过反射了解集合泛型的本质
public class ClassFanXing {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
ArrayList list = new ArrayList();
ArrayList<String> list1 = new ArrayList<String>();
Class c = list.getClass();
Class c1 = list1.getClass();
list1.add("hello");
// list1.add(1);
System.out.println(c == c1);
// 反射的操作都是编译后的操作
// c==c1返回结果是true 是为了防止输错 只在编译阶段有效
// 验证 我们可以通过方法的反射来绕过编译
Method m = c1.getMethod("add", Object.class);
m.invoke(list1, 100);
System.out.println(list1.size());
System.out.println(list1);
}
}
结果
true
2
[hello, 100]
参考文献:
慕课网–反射