反射Reflect
参考http://www.sczyh30.com/posts/Java/java-reflection-1/
知识点:
- Class类的使用
- 方法的反射
- 成员变量的反射
- 构造函数的反射
- Java类加载机制
知识整理:
- Class类的使用
- Java中有两样东西不是面向对象,一是普通的数据类型(例:int a=5不是面向对象,但是有封装类来弥补),二是java静态的东西(静态的东西不属于对象,而是属于类)
- 在面向对象的世界里,万事万物皆对象,因此:类是对象,类是java.lang.Class类的实例对象,这个对象成为该类的类类型
举例:
public class Test { public static void main(String[] args) { //Foo这个类的实例对象f怎么表示? Foo f = new Foo(); /*Foo这个类也是Class类的一个实例对象,Class类构造方法为私有,类外部不能访问, 只有java虚拟机能创建Class实例对象。既然不能像创建对象一样new一个实例对象, 那么怎么Class这个类的实例对象Foo?*/ //三种表示方法,下面c1,c2表示了Foo的类类型(class type) //第一种:任何一个类都有一个隐含的静态成员变量class Class c1 = Foo.class; System.out.println(c1); //class Foo //第二种,已经知道该类的对象,通过getClass()方法 Class c2 = f.getClass(); System.out.println(c2);//class Foo System.out.println(c1 == c2); //true //第三种表达方式 Class c3 = null; try { //c3 = Class.forName("java.lang.Thread");//java.lang.Thread代表Thread这个类,乱写会抛异常 c3 = Class.forName("Foo");//若字符串写"com.reflect.Foo",文件需打包package com.reflect;关于包知识忘记了,后续研究 } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("***" + c3); //我们完全可以通过类的类类型创建该类的对象,通过c1,c2,或c3创建Foo的实例 try{ Foo fo = (Foo)c1.newInstance();//需要有无参数的构造方法 fo.showFo(); } catch (Exception e) { e.printStackTrace(); } } } class Foo { public void showFo() { System.out.println("this is fo"); } }
运行结果:
Class类动态加载类:
Class.forName("类的全称")
- 不仅表示了类的类类型,还表示了动态加载类
- 编译时刻加载类是静态加载类、运行时刻加载类是动态加载类
静态加载类:(编译时就需要加载所有的类,即使用不到也必须加载上,否则不能通过编译)
public class TestReflect { public static void main(String[] args) { if("World".equals(args[0])) { World w = new World(); w.start(); } if("Excel".equals(args[0])) { Excel e = new Excel(); e.start(); } } } //类的静态加载,在编译时刻必须加载所有可能使用到的类,例如类Excel不存在,那么程序就不能编译 class World{ public void start() { System.out.println("World....starts!"); } } // class Excel{ // public void start() { // System.out.println("Excel....starts!"); // } // }
动态加载类:(用哪个类加载哪个类,不用不加载)
public class TestReflect { public static void main(String[] args) { try{ //动态加载类,运行时刻加载类,即使没有World、Excel类,编译(javac TestReflect.java)也能通过, //但是执行时(java TestReflect World)会报错,因为没有这个类 Class c = Class.forName(args[0]); //World w = (World)c.newInstance();//这样实例化类对象也可以,但是假如是Excel类型怎么办? Office o = (Office)c.newInstance(); o.start(); } catch(Exception e) { e.printStackTrace(); } } } interface Office { public void start(); } class World implements Office { public void start(){ System.out.println("World....starts!!"); } } // class Excel{ // public void start() { // System.out.println("Excel....starts!"); // } // }
基本的数据类型对应的类类型
public class TestReflect { public static void main(String[] args) { Class c1 = int.class; //int的类类型 Class c2 = String.class; //String的类类型 Class c3 = double.class; //double数据类型的类类型 Class c4 = Double.class; //Double类的类类型 Class c5 = void.class; System.out.println(c1); System.out.println(c2.getName()); System.out.println(c3.getSimpleName());//不包含包名的类的名称 System.out.println(c4.getName()); System.out.println(c5.getName()); } }
- 方法的反射
import java.lang.reflect.Method; class ReflectUtil { /* *打印类的信息 *包括成员函数、成员变量 */ public static void printClassMessage(Object obj){ //1、要获取类的信息,首先要获取类的类类型 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型 //2、获取类的名称 System.out.println("类的名称是" + c.getName()); /* *Java里面方法是Method的对象 *getMethods()方法获取的是所有的public的函数,包括父类继承而来的 *getDeclaredMethods方法获取的是所有该类自己声明的方法,不问访问权限,不访问父类方法 *得到的是数组 */ Method[] ms = c.getMethods();//c.getDeclaredMethods(); for(int i = 0; i < ms.length; i++) { //得到方法的返回值类型的类类型 Class returnType = ms[i].getReturnType(); System.out.println(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 class TestReflect { public static void main(String[] args) { String s = "hello"; ReflectUtil.printClassMessage(s); } }
- 成员变量的反射
成员变量也是对象
Java.lang.reflect.Field
Field类封装了关于成员变量的操作
getFields()方法获取的是所有的public的成员变量的信息
getDeclaredFields获取的是自己声明的成员变量的信息,可以是共有的也可是私有的
import java.lang.reflect.Method; import java.lang.reflect.Field; class ReflectUtil { /* *打印类的信息 *包括成员函数、成员变量 */ public static void printClassMessage(Object obj){ //1、要获取类的信息,首先要获取类的类类型 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型 //2、获取类的名称 System.out.println("类的名称是" + c.getName()); /* *Java里面方法是Method的对象 *getMethods()方法获取的是所有的public的函数,包括父类继承而来的 *getDeclaredMethods方法获取的是所有该类自己声明的方法,不问访问权限,不访问父类方法 *得到的是数组 */ Method[] ms = c.getMethods();//c.getDeclaredMethods(); for(int i = 0; i < ms.length; i++) { // //得到方法的返回值类型的类类型 // Class returnType = ms[i].getReturnType(); // System.out.println(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(")"); Field[] fs = c.getDeclaredFields(); for(Field field:fs) { //得到成员变量的类型的类类型 Class fieldType = field.getType(); String typeName = field.getName(); //得到成员变量的名称 String fieldName = field.getName(); System.out.println(typeName + " " + fieldName); } } } } public class TestReflect { public static void main(String[] args) { String s = "hello"; ReflectUtil.printClassMessage(s); } }
- 构造函数的反射
- Java类加载机制