【Java】(2)Java反射

来源:互联网 发布:淘宝运营考核指标 编辑:程序博客网 时间:2024/05/17 17:59

1. 概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。


2. 获取Class对象

public class ClassDemo1 {public static void main(String[] args) {try {Entity foo1 = new Entity();// 获得Class对象的两种方式:Class c1 = Entity.class;Class c2 = foo1.getClass();Class c3 = Class.forName("com.thr.reflect.Entity");// 不管c1还是c2,都代表了Entity的class的对象System.out.println(c1 == c2);// c3也是Entity的class对象System.out.println(c1 == c3);} catch (ClassNotFoundException e) {e.printStackTrace();}}}class Entity {}
三种方式获取的Class对象是一致的。

通过Class对象我们还可以创建类:

Entity en = (Entity) c1.newInstance();

通过获取的这个对象就可以像用new创建出来的对象一样使用Entity内部的方法等。


3. 动态加载类

首先创建一个接口:

public interface Singable {void sing();}
然后写两个实现类:
public class Bird implements Singable {@Overridepublic void sing() {System.out.println("Bird sing...");}}
public class Cat implements Singable {@Overridepublic void sing() {System.out.println("Cat sing...");}}

最后再主程序中动态加载类:

public class World {public static void main(String[] args) {try {Class c = Class.forName(args[0]);Singable singable = (Singable) c.newInstance();singable.sing();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}

运行时要传入类的全名参数。


4. 获取方法信息

首先来看基本数据类型的Class对象:

public class ClassDemo2 {public static void main(String[] args) {Class[] cs = new Class[] { int.class, String.class, double.class,Double.class, void.class, Class.class };for (Class c : cs) {System.out.println(c.getName());System.out.println(c.getSimpleName());}}}
我们编写一个获取类的方法的工具方法:
public static void printClassMethods(Object obj) {// 首先获取Class对象Class c = obj.getClass();// 获取类的名称System.out.println("类的名称是:" + c.getName());// 获取类的方法,一个Method的对象就是一个成员方法,通过getMethods()获取的是所有public的方法,包括从父类继承而来的// getDeclaredMethods()获取的是所有该类自己生命的方法,不问访问权限Method[] ms = c.getMethods();for (Method m : ms) {// 获取返回值类型Class returnType = m.getReturnType();System.out.print(returnType.getName() + " ");// 获取方法名System.out.print(m.getName() + "(");// 获取参数类型Class[] paramTypes = m.getParameterTypes();for (Class type : paramTypes) {System.out.print(type.getName() + ",");}System.out.println(")");}}
使用它:
public static void main(String[] args) {String s = new String();ClassUtil.printClassMethods(s);Integer i = 1;ClassUtil.printClassMethods(i);}

5. 获取成员变量和构造函数信息

获取成员变量信息:

public static void printClassFields(Object obj) {// 首先获取Class对象Class c = obj.getClass();// 使用getFields()获取的是所有public的成员变量信息,使用getDeclaredFields获取的是该类自己声明的成员变量信息,不问访问权限Field[] fs = c.getDeclaredFields();for (Field f : fs) {// 获取成员变量的类型Class fieldType = f.getType();String typeName = fieldType.getName();// 获取成员变量的名字String filedName = f.getName();System.out.println(typeName + " " + filedName);}}
获取构造方法信息:
public static void printClassConstructor(Object obj) {// 首先获取Class对象Class c = obj.getClass();Constructor[] cons = c.getDeclaredConstructors();for (Constructor con : cons) {// 获取方法名System.out.print(con.getName() + "(");// 获取参数类型Class[] paramTypes = con.getParameterTypes();for (Class type : paramTypes) {System.out.print(type.getName() + ",");}System.out.println(")");}}

6. 方法反射的基本操作

所有的方法对象都有一个invoke方法我们调用method.invoke(对象, 参数列表)就可以执行方法:

public class MethodDemo1 {public static void main(String[] args) {try {// 获取print(int, int)方法A a = new A();Class c = a.getClass();Method m1 = c.getMethod("print", int.class, int.class);// 执行方法,使用o来接受返回值// 如果有返回值,那么Object就是返回值的类型;没有返回值就返回nullObject o1 = m1.invoke(a, 10, 10);// 获取print(String, String)方法Method m2 = c.getMethod("print", new Class[] { String.class,String.class });Object o2 = m2.invoke(a, "s1", "s2");// 获取print()方法Method m3 = c.getMethod("print");Object o3 = m3.invoke(a);System.out.println(o1);System.out.println(o2);System.out.println(o3);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}class A {public void print() {System.out.println("hello");}public int print(int a, int b) {System.out.println(a + b);return a + b;}public String print(String a, String b) {System.out.println(a.toUpperCase() + "," + b.toLowerCase());return a + b;}}

7. 泛型的本质

public static void main(String[] args) {List list1 = new ArrayList();List<String> list2 = new ArrayList<String>();Class c1 = list1.getClass();Class c2 = list2.getClass();System.out.println(c1 == c2);// 反射的操作都是编译之后的操作// c1==c2是true说明编译之后集合的泛型是去泛型化的// Java中集合的泛型是防止错误输入的,只在编译阶段有效,绕过编译就无效了// 我们可以通过方法的反射来绕过编译Method m;try {m = c1.getMethod("add", Object.class);m.invoke(list1, 100);System.out.println(list1.size());System.out.println(list1);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}
通过这个例子可以看到通过Java的反射机制可以绕过编译,是在运行时刻执行的,自然就可以绕过集合的泛型。


0 0
原创粉丝点击