类是对象,类是java.lang.Class类的实例对象
//创建类
class Foo{}
public static void main(String[] args) {
Foo foo1 = new Foo();
//任何一个类都是Class的实例对象,这个实例对象有三种表示方式
//1、任何一个类都有一个隐含的静态成员变量class
Class c1 = Foo.class;
//2、已知该类的对象,通过getClass方法获取
Class c2 = foo1.getClass();
/*官网:c1、c2是表示了FOO类的类类型(class type)
* 类也是对象,是Class类的实例对象
* 该对象被称为该类的类类型
*/
System.out.println(c1==c2);
//3、通过Class.forName("类的全称")方法,参数为类的全称(“包.类名”)
Class c3 = null;
try {
c3 = Class.forName("reflect.Foo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//通过类的类类型创建该类的对象实例。通过c1\c2\c3创建Foo的实例对象
try {
Foo foo = (Foo)c1.newInstance();//需要有无参数的构造方法
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
new创建对象是静态加载类,在编译时刻就需要加载所有可能使用到的类
通过动态加载类可以解决该问题
public class OfficeBetter {
public static void main(String[] args) {
try {
//动态加载类,在运行时加载
Class c = Class.forName(args[0]);
//通过该类类型,创建该类对象
OfficeAble oa = (OfficeAble)c.newInstance();
oa.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//创建接口
interface OfficeAble{
public void start();
}
//创建类Word,实现接口
public class Word implements OfficeAble{
public void start() {
System.out.println("Word。。start...");
}
}
//创建类Excel,实现接口
public class Excel implements OfficeAble{
public void start() {
System.out.println("Excel。。start...");
}
}
javac OfficeBetter Word //动态加载Word类运行
javac OfficeBetter Excel //动态加载Excel类运行
Class c1 = int.class; //int的类类型
Class c2 = String.class;
Class c5 = void.class;
System.out.println(c1.getName());//Console:int
System.out.println(c2.getSimpleName());//Console:String(不包含包名的类的名称)
System.out.println(c5.getName());//Console:void
基本的数据类型、void关键字等都存在类类型
Class类的基本API操作
获取类方法信息
public class ClassUtil {
public static void printClassMessage(Object obj) {
//要获取类的信息,首先要获取类的类类型
Class c = obj.getClass();//获取传递的是哪个子类的对象 c就是该子类对象的类类型
//获取类的名称
System.out.println("类的名称:" + c.getName());
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有public的函数,包括父类继承而来的
* c.getDeclaredAnnotations()获取的是所有该类自己声明的方法,不问访问权限
*/
Method[] ms = c.getMethods();
for(int i = 0; i < ms.length; i++) {
//得到方法的返回值类型的类类型
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName()+ " ");//输出返回值类型
//得到方法的名称
System.out.print(ms[i].getName() + "(");
//获取参数类型。得到的是参数列表的类型的类类型
Class[] paramTypes = ms[i].getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
}
获取类成员变量信息
public static void printFieldMessage(Object obj) {
/*
* 成员变量也是对象
* java.lang.refelct.Field
* Field类封装了关于成员变量的操作
*/
//getField()方法获取的是所有public的成员变量的信息
Class c = obj.getClass();
Field[] fs = c.getFields();
//getDeclaredFields()获取的是该类自己声明的成员变量信息
Field[] fc = c.getDeclaredFields();
for (Field field : fc) {
//得到成员变量的类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
//获取成员变量的名字
String fieldName = field.getName();
System.out.println(typeName+" "+fieldName);
}
}
获取类成员的构造函数
public static void printConMessage(Object obj) {
/*
* 构造函数也是变量
*java.lang.Constructor中封装了构造函数的信息
*/
Class c = obj.getClass();
//getConstructors()获取所有的public的构造函数
Constructor[] cs = c.getConstructors();
//getDeclaredConstructors()获取所有的构造函数
Constructor[] cx = c.getDeclaredConstructors();
for (Constructor constructor : cx) {
System.out.print(constructor.getName()+"(");
//获取构造函数参数列表,得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
方法反射的的操作,通过获取类类型,再获取类方法,用获取的类方法反过来操作对象和参数。
A a1 = new A(); a1.print(1,1); ========= m.invoke(a1, new Object[]{1,1}) //m为反射操作获取的方法
method.invoke(对象,参数列表)
public static void main(String[] args) throws Exception, Exception {
// 1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型
A a1 = new A();
Class c = a1.getClass();
//2.获取方法 , 由名称和参数列表来决定 (参数列表:Class.... 代表Class类的可变参数 )
Method m = c.getMethod("print", new Class[]{int.class,int.class});
Method s = c.getMethod("print", int.class,int.class);//也可以直接用 类型.class 有几个参数写几个
a1.print(1, 1);
/*
* 方法的反射操作
* 方法的反射操作是用m对象来进行方法调用,和a1.print(1,1)方法调用完全相同
*/
//方法没有返回值返回null,有返回值返回具体的返回值
Object o = m.invoke(a1, new Object[]{10,20});
Object b = m.invoke(a1, 10,20);//直接传参数
}
//反射的操作都是编译之后
public static void main(String[] args) throws Exception {
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
Class a1 = list1.getClass();
Class a2 = list2.getClass();
System.out.println(a1==a2);//结果为true , 反射操作都是在编译之后的操作
/*
* a1==a2结果返回true说明在编译后,集合是去泛型化的
* Java中的集合泛型是防止错误输入的,只在编译阶段有效
* 绕过编译就无效了
* 证明:通过方法的反射来操作,绕过编译
*/
Method m = a1.getMethod("add", Object.class);
m.invoke(list2, 20);//绕过编译操作就绕过了泛型限制,像集合中插入20
System.out.println(list2); //Console:[20]
}