JAVA反射机制详解

    科技2022-07-11  98

    反射机制有什么用

    可以操作字节码文件

    反射机制的相关类再哪个包下?

    java.lang.reflect.*;

    反射机制相关的类

    java.lang.Class   代表字节码文件

    java.lang.reflect.Method   代表字节码中的方法的字节码

    java.lang.reflect.Constructor   代表字节码中的构造器的字节码

    java.lang.reflect.Field   代表字节码中的属性的字节码

    利用反射机制操作字节码文件

    获取类的字节码

    第一种方式:使用静态方法Class.forName(完整类名加包名)

    Class c1 = Class.forName("java.lang.String");

    Class.forName("java.lang.String");会导致类加载,即执行一次,String方法中的静态代码块也会执行一次,如果想一个类的静态方法执行一次,那么可以使用Class.forName()

    第二种方式:使用Object类中的引用.getClass()方法

    String s = "abc"; Class c = s.getClass();

    第三种方式:java中的任意数据类型(包括基本数据类型)都有class属性

    Class c = String.class; Class c = int.class;

    通过字节码文件来实例化对象

    public class Test { public static void main(String[] args) { Class c = null; try { //通过反射机制获取字节码文件 c = Class.forName("User"); //newInstacnce()方法会调用User的无参构造方法来new一个User对象 //必须保证User的无参构造方法存在! Object o = c.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } } class User{ }

    注意:使用这种方法来初始化对象,更灵活!

    举个例子

    配置文件

    //classinfo.Properties className=com.sdut.wwg.User

    User类

    package com.sdut.wwg; public class User { @Override public String toString() { return "User{}"; } }

    Test类

    import java.io.FileReader; import java.util.Properties; public class Test { public static void main(String[] args) throws Exception{ //还可以这样获取绝对路径 /* String path = Thread.currentThread().getContextClassLoader() .getResource("classinfo.Properities").getPath(); 还可以直接返回一个流 InputStream r =Thread.currentThread().getContextClassLoader() .getResourceAsStream("classinfo.Properities"); */ FileReader r = new FileReader("Demo/src/classinfo.Properities"); Properties p = new Properties(); p.load(r); r.close(); String className = p.getProperty("className"); //通过反射机制获取字节码文件 Class c= Class.forName(className); //newInstacnce()方法会调用User的无参构造方法来new一个User对象 //必须保证User的无参构造方法存在! Object o = c.newInstance(); System.out.println(o); } }

    这样的优点在于当服务器运行的时候,可以直接修改配置文件,而不需要改代码情况下可以做到不同对象的实例化

    反射属性

    import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class Test { public static void main(String[] args) throws Exception{ Class c = Class.forName("com.sdut.wwg.User"); //获取完整类名 System.out.println("完整类名为"+c.getName()); System.out.println("简类名为"+c.getSimpleName()); //获取User所有的公共属性 Field[] fs = c.getFields(); System.out.println("所有声明公有属性数量总计"+fs.length); //获取User所有的属性 Field[] allFs = c.getDeclaredFields(); System.out.println("所有声明属性数量总计"+allFs.length); System.out.println("属性名为:"); for (int i = 0; i <allFs.length ; i++) { System.out.println(allFs[i].getName()); } System.out.println("各属性类型为:"); for (int i = 0; i <allFs.length ; i++) { //获取属性修饰符 int s = allFs[i].getModifiers(); System.out.println(s); //可以将这个代号数字转换为字符串 String modifierString = Modifier.toString(s); System.out.println(modifierString); //获取属性的类型 Class fieldType = allFs[i].getType(); System.out.println(fieldType.getSimpleName()); } } }

    通过反射机制来反编译一个类的属性(了解)

    import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class Test { public static void main(String[] args) throws Exception{ Class c = Class.forName("User"); StringBuffer s= new StringBuffer(); //获取类的修饰符列表和类名 s.append(Modifier.toString(c.getModifiers())+" class "+c.getSimpleName()+"{\n"); Field[] fields = c.getDeclaredFields(); for(Field f:fields){ s.append("\t"); s.append(Modifier.toString(f.getModifiers())+" "); s.append(f.getType().getSimpleName()+" "); s.append(f.getName()+";\n"); } s.append("}"); System.out.println(s); } }

    输出结果为

    通过访问机制来访问一个java对象的属性

    import java.lang.reflect.Field; public class Test { public static void main(String[] args) throws Exception{ Class c = Class.forName("User"); Object o = c.newInstance(); //获取no属性 Field noField = c.getDeclaredField("no"); //给o对象的no属性赋值 noField.set(o,1111); //读取属性的值 System.out.println(noField.get(o)); //可以访问私有属性吗?? Field nameField = c.getDeclaredField("name"); //需要打破封装.这样设置完之后,在外部也是可以访问私有属性的 nameField.setAccessible(true); nameField.set(o,"jack"); System.out.println(nameField.get(o)); } }

    反射方法

    public class Test { public static void main(String[] args) throws Exception{ Class c = Class.forName("User"); //获取所有的方法 Method[] methods = c.getDeclaredMethods(); //获取获取到的方法数量 System.out.println(methods.length); for(Method m:methods){ //输出方法的修饰符列表 System.out.print(Modifier.toString(m.getModifiers())+" "); //输出方法的返回值类型 System.out.print(m.getReturnType().getSimpleName()+" "); //输出方法的名字 System.out.println(m.getName()); //获取参数 Class [] ctypes = m.getParameterTypes(); for(Class clas: ctypes){ //输出参数的类型 System.out.println(clas.getSimpleName()); } } } }

    反编译方法名和参数列表

    import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class Test { public static void main(String[] args) throws Exception{ StringBuffer s = new StringBuffer(); Class c = Class.forName("java.lang.String"); Method [] methods = c.getDeclaredMethods(); for(Method m: methods){ s.append('\t'); s.append(Modifier.toString(m.getModifiers())+" "+m.getReturnType().getSimpleName()+" "+m.getName()); s.append(" ("); Class []classes = m.getParameterTypes(); for(Class cls : classes){ s.append(cls.getSimpleName()+','); } if(classes.length>0) s.deleteCharAt(s.length()-1); s.append(") { }\n"); } System.out.println(s); } }

    输出结果为

     

    通过反射机制调用方法

     

    import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception{ Class userClass = Class.forName("User"); //创建一个User类对象 Object o = userClass.newInstance(); //获取sum方法 Method sum = userClass.getDeclaredMethod("sum", int.class, int.class); //调用sum方法 int result =(int)sum.invoke(o,1,2); System.out.println(result); } }

    通过反射机制调用有参构造方法

    import java.lang.reflect.Constructor; public class Test { public static void main(String[] args) throws Exception{ Class userClass = Class.forName("User"); //调用无参构造方法创建对象 Object o = userClass.newInstance(); //调用有参构造方法创建对象 Constructor constructor = userClass.getConstructor(int.class,String.class); Object o1 = constructor.newInstance(1111,"jack"); System.out.println(o); System.out.println(o1); } }

    输出结果为

    通过反射机制获取父类以及实现了什么接口

    public class Test { public static void main(String[] args) throws Exception{ Class stringClass = Class.forName("java.lang.String"); //获取父类名 Class superClass = stringClass.getSuperclass(); System.out.println(superClass.getSimpleName()); //获取实现了什么接口 Class[] interfaces = stringClass.getInterfaces(); for(Class i:interfaces){ System.out.println(i.getSimpleName()); } } }

    输出结果

    Processed: 0.020, SQL: 8