初解
java.lang.Class
对象,通过该Class
对象就可以访问到JVM中的这个类.Class类的使用
在面向对象的世界里,所有看到的事物都是对象,包括class也是对象(java.lang.Class的对象)
任何一个类都是Class类的实例对象,那么,他们是如何表示的呢?
Foo foo=new Foo();
第一种 Class c1=Foo.Class;
任何一个类都有一个隐含的静态成员变量;
第二种 Class c2=foo.getClass();
通过该对象的getClass()方法,获取类;
此时c1/c2表示的是Foo类的类类型 (class type)
c1==c2,因为他们表示的是同一个类的类类型,一个类只有一种类类型
第三种 Class c3=null;
c3=Class.forName(“reflect.Foo”);
此时,需要的参数是类的全限定名;这种方法不仅表示了类的类类型,还表示了动态加载类;
c2==c3;
last:
Foo foo=(Foo)c1.newInstance;
需要通过无参的构造函数;
静态加载类:编译时刻加载类; new一个对象,编译时候需要加载所有需要的类;很多执行的功能同时执行,但是只要有一个有问题,那么,所有的都会停滞,全部无用;
动态加载类:运行时刻加载类; 通过类类型创建类对象;
Class.forName(“类的全称”)
Class c=Class.forName(arg[0]);
//加载类型未知,不要强制类型转换,但是不知道怎么转换
OfficeAble oa=( OfficeAble) c.newInstance();
//用一种规则(接口)来强制转换,因为此时不知道转换到哪一种类;
oa.start();
此时,可编译上述代码;
编写OfficeAble接口下面的各种类;
编译哪个类,就可以动态加载哪个类;
用途:利用动态加载,尽量提高功能型的类的可扩展性,尽量使用动态加载,更加方便;
常见的现象,某个运行的界面,运行到某个地方的时候提示出错,此时是个别的类出错,使用动态加载类,避免了整个界面不能启动、功能全部瘫痪。
void关键字、基本数据类型等都有自己的类类型;
获取类的信息,类成员变量,类方法,类构造函数等
package hdu.terence.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ClassUtil {
@SuppressWarnings("unchecked")
public static void printClassMessage(Object obj) {
//获取类的信息:类类型;
Class c = obj.getClass();
System.out.println("类名称:" + c.getName());
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* * getMethods()方法,获取所有public函数,包括继承过来的
* * getDeclaredMethods()获取该类自己声明的方法(一般在自定义类中)
* */
Method[] ms = c.getMethods();
for (inti = 0; i < ms.length; i++) {
ClassreturnType = ms[i].getReturnType();
System.out.print(" " + returnType.getName() + " ");
System.out.print(ms[i].getName() + "(");
Class[] paramTypes = ms[i].getParameterTypes();
for (intj = 0; j < paramTypes.length; j++) {
System.out.print(paramTypes[j].getName());
if (j != paramTypes.length - 1) {
System.out.print(",");
}
}
System.out.println(")");
}
}
/**
* 获取成员变量的信息
*/
@SuppressWarnings("unchecked")
public static void printFieldMessage(Object obj) {
Classc = obj.getClass();
/**成员变量也是对象
* java.lang.reflect.Field
* Field类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
* */
//Field[]fs = c.getFields();
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
//得到成员变量的类型的类类型
ClassfieldType = field.getType();
tringtypeName = fieldType.getName();
//得到成员变量的名称
StringfieldName = field.getName();
System.out.println(" " + typeName + " " + fieldName);
}
}
/**
* 打印对象的构造函数的信息
*/
@SuppressWarnings("unchecked")
public static void printConMessage(Object obj) {
Classc = obj.getClass();
/**构造函数也是对象
* * java.lang. Constructor中封装了构造函数的信息
* * getConstructors获取所有的public的构造函数
* getDeclaredConstructors得到所有的构造函数
* */
//Constructor[]cs = c.getConstructors();
Constructor[] cs = c.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.print(" " + constructor.getName() + "(");
//获取构造函数的参数列表--->得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
public static void main(String[] args) {
Strings = "Hello,Terence!";
System.out.println("获取类信息");
ClassUtil.printClassMessage(s);
System.out.println("获取类成员变量信息");
ClassUtil.printFieldMessage(s);
System.out.println("获取类构造函数信息");
ClassUtil.printConMessage(s);
//Integeri=1;
// ClassUtil.printClassMessage(i);
}
}
方法反射
如何获取某个方法
方法的名称和方法的参数列表可以唯一决定某个方法
方法的反射操作
Method.invoke(对象,参数列表)
package hdu.terence.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodDemo1 {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
/**
*要获取方法
*1.首先要获取该方法所在的类,即获取类的信息
*要获取类的信息,首先要获取类的类类型;
*/
A a1 = new A();
Class c = a1.getClass();
/**
*2.获取方法名称和参数列表来表决
*getMethod获取的是public方法
*getDeclaredMethod自己声明的方法
* /
/* Methodm=c.getDeclaredMethod("print",new Class[]{int.class,int.class}); */
try {
Method m = c.getDeclaredMethod("print", int.class, int.class);
/**方法的反射;正常调用:a1.print(10,20);
*方法的反射操作时通过m对象来进行方法调用,效果和正常调用是一样的;
*反射操作有返回值,返回值类型是Object类型,如果返回值类型是void则obj=null;
*/
Object obj1 = m.invoke(a1, new Object[]{10, 20}); /* 反射传参1 */
Objectobj2 = m.invoke(a1, 10, 20); /* 反射传参2 */
System.out.println(obj1 + "\t" + obj2);
Methodm1 = c.getDeclaredMethod("print", String.class, String.class);
Object obj3 = m1.invoke(a1, "Hello", "Terence");
Object obj4 = m1.invoke(a1, new Object[]{"Hello", "Terence"});
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
class A {
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());
}
}
通过反射来理解泛型的本质
package hdu.terence.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class MethodDemo2 {
public static void main(String[] args) {
ArrayListlist = new ArrayList();
ArrayList list1 = new ArrayList();
list.add("hello");
list.add(10);
list1.add("tttttt");
/* list1.add(10);提示错误; */
Classc1 = list.getClass();
Classc2 = list1.getClass();
System.out.println("listand list1 是否类型相同:" + (c1 == c2));
/*
*上述结果提示:true;表明编译之后的集合ArrayList是去除泛型化的
*只是泛型的限制不同,所以,泛型是用来提示输入错误的,只有在编译阶段才有效,绕过编译就无效了;
*反射的操作都是在编译之后的操作,此处可以用方法反射来证明上述观点;
*/
try {
Methodm = c2.getMethod("add", Object.class);
m.invoke(list1, 20); /* 此时转化为对象传参,绕过了编译,避免了泛型的判断;不提示错误 */
System.out.println("list1的长度:" + list1.size());
System.out.println("list1:" + list1);
System.out.println("使用泛型 遍历集合(出错)");
/* 此时不能用泛型再遍历了,应该使用对象Object遍历 */
/*for(Stringstr:list1) {
System.out.println(str+" ");
*此时遍历到整形的时候会出错
}
*/
System.out.println("使用Object类型 遍历集合:");
for (Object obj : list1) {
System.out.print(obj + "\t");
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
(2016-10-17)
(注:如果看到的人发现了里面有错误,请帮忙指正一下,我修改一下自己的理解,共同学习,只求让我这只菜鸟快快成长。提到反射我就晕晕乎不知其所以然)