浅谈JAVA反射机制

什么是反射?

在java核心卷一给出的概括:

能够分析类能力的程序称为反射,可以在运行时分析类能力,运行时查看对象。

按照我的理解就是:

  1. 探索类的信息
  2. 动态的进行类操作(不知道怎么描述)

在理解反射以前先来过一下java对象的创建过程

  • 首先肯定要编译,即javac,将java程序编译成字节码。
  • 然后由ClassLoader将class信息进行加载加载到方法区,在这个过程中执行static语句,初始化静态成员变量。
  • 然后程序在创建对象的时候,即new的时候,会去检查一下有没有要创建类的信息,如果有的话,分配内存。如果没有,那么加载这个类的信息。
  • 清空储存空间,为属性设置默认值。
  • 执行成员变量的初始化。
  • 执行构造方法。

那么反射主要就是执行第二步的操作,只不过反射是在运行时执行这个操作。

下面通过2个小栗子来看一下反射的作用:



import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

//通过反射获取类的信息
public class Reflection {
	
	
	public static void printConstructor(Class cl){
		Constructor[] constructors = cl.getDeclaredConstructors();
		
		for(Constructor c:constructors){
			String name = c.getName();
			System.out.print("   ");
			String modifiers = Modifier.toString(c.getModifiers());
			if(modifiers.length()>0){
				System.out.print(modifiers+" ");
			}
			System.out.print(name+"(");
			Class[] paramTypes = c.getParameterTypes();
			for (int j = 0; j < paramTypes.length; j++) {
				if (j>0) 
					System.out.print(", ");
				System.out.print(paramTypes[j].getName());
			}
			System.out.println(");");
		}
	}
	
	public static void printMethods(Class cl){
		Method[] methods =cl.getDeclaredMethods();
		for (Method m : methods) {
			Class retType = m.getReturnType();
			String name = m.getName();
			System.out.print("   ");
			//getModifiers  获取权限修饰符 
			String modifiers = Modifier.toString(m.getModifiers());
			if(modifiers.length()>0) System.out.print(modifiers+" ");
			System.out.print(retType.getName()+" "+name+"(");
			Class[] paramTypes = m.getParameterTypes();
			for (int j = 0; j < paramTypes.length; j++) {
				if(j>0)System.out.print(", ");
				System.out.print(paramTypes[j].getName());
			}
			System.out.println(");");
		}
	}
	public static void printFields(Class cl){
		Field[] fields = cl.getDeclaredFields();
		for (Field f : fields) {
			Class type = f.getType();
			String name = f.getName();
			System.out.print("   ");
			String modifiers = Modifier.toString(f.getModifiers());
			if (modifiers.length()>0) {
				System.out.print(modifiers+" ");
			}
			System.out.println(type.getName()+" "+name+";");
		}
		
	}
	
	public static void main(String[] args) {
		String name="com.entity.People";
		
		Class cl;
		try {
			cl = Class.forName(name);
			Class supercl = cl.getSuperclass();
			String modifiers= Modifier.toString(cl.getModifiers());
			if(modifiers.length()>0)System.out.print(modifiers+" ");
			System.out.print("class  "+name);
			if(supercl != null && supercl != Object.class)System.out.print("extends"+supercl.getName());
			System.out.print("\n{\n");
			printConstructor(cl);
			System.out.println("");
			printMethods(cl);
			System.err.println();
			printFields(cl);
			System.out.println("}");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}
//通过反射动态进行类操作
public static  List selectT(String sql,Class c1) {
		List list = new ArrayList<>();
		try {
			Connection conn = getConn();

			Statement statement = conn.createStatement();

			ResultSet resultSet = statement.executeQuery(sql);

			while (resultSet.next()) {
				T user = c1.newInstance();
				Field[] fileds = c1.getDeclaredFields();
				for (Field field : fileds) {
                                //因为私有栈,所以要设置可达
				field.setAccessible(true);
					field.set(user,resultSet.getString(field.getName()) );
				}
				
				list.add(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;

	}

当然例二的前提数据库中字段名与类属性名严格一致。

当然例二的作用我们也可以通过利用反射调用set方法来实现。

说到反射就不得不说Class这个对象了,那这个Class对象是什么呢(个人理解)?

先看一个图:

浅谈JAVA反射机制_第1张图片

类信息是存在与方法区的常量池中的,然后我们给对象分配内存的时候,都会有一个指针指向方法区中类信息,用来区分类型

那么既然是指针引用,那么说明他们的类信息只存在一份。这也就是说为什么在创建对象的时候先要去检查一下类是否被加载。

如果前边已经创建过一个该类对象,那么在创建的时候是不会重新加载的。这也是为什么static语句只执行一次的原因

扯得有点远,扯回来。

Class对象在我看来就是存在常量池中的这个类信息对象。

下面介绍三种常用获取类信息的方法:

Class cl = People.class;

c1 = new People().getClass();

Class.forName("people的全限定名");

通过一个例子验证一下我们的上述说的内容:

public static void main(String[] args) {
		People p = new People();
		Class c1 = p.getClass();
		Class c2 = People.class;
		System.out.println(c1==c2);
}

//结果 true

==比较的是地址,所以确实是指向的同一份类信息。

然后。。然后。。我也不知道说啥了,就这样吧,over!

 

你可能感兴趣的:(JAVA)