类加载器
类加载器是通过某个类的.classLoader()方法,将该类的.class文件从硬盘中加载到java虚拟机中,形成字节码文件。
package com.tongwx.common_code; public class Demo1 { public static void main(String[] args) { /** * 1)系统提供给我们三个类加载器: * BootStrap加载器: 加载的jdk/jre/lib/rt.jar(开发的时候用的核心类) * ExtClassLoad加载器: 加载jdk/jre/lib/ext/*.jar (扩展包) * AppClassLoad加载器: 加载CLASSPATH中的jar包和class文件 * * MyClasLoader1加载器 MyClassLoader2加载器 都是AppClassLoad的子类 * * * 2) 这三个类加载器是树状结构. * 3) 类加载的过程: * 3.1 一个类A是有一个类加载器加载的,如果类A中使用到了类B,类B也是由类A的类加载器加载 * 4)委托机制: * 4.1 发起者类加载器 去加载类的时候,先委托其父类加载, 如果还有父类加载器,则继续委托上去,直接没有父加载器为止。 * 最顶层的类加载就需要真正地去加载指定类,如果在其类目录中找不到这个类,继续往下找,找到发起者类加载器为止!!! * * 委托机制的好处: * 可以让代码加载更加安全和高效! 保证核心类的字节码只有一份在内存中。 * */ //得到某个类被哪个类加载器加载 //System.out.println(Demo1.class.getClassLoader().getClass()); //这个类就由BootStrap加载 //System.out.println(java.util.Date.class.getClassLoader()); //查看某个类加载器树状结构 ClassLoader classLoader = Demo1.class.getClassLoader(); while(classLoader!=null){ System.out.println(classLoader.getClass()); classLoader = classLoader.getParent(); } System.out.println(classLoader); } } |
package com.tongwx.common_code; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestClassLoader extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 一个web的servlet加载顺序: * 1)WebappClassLoader(tomcat自定义的类加载器) : * 加载web/WEB-INF/classes/ 类 * 加载web/WEB-INF/lib/*.jar jar包 * * 1.1 WebappClassLoader设计的目录为了分离服务器中每个web应用,让每个web应用互不干扰的 * ServletContext * 1.2 WebappClassLoader打破了委托机制。 为了保持优先加载当前web应用的所有资源 * * 2)StandardClassLoader(tomcat自定义的类加载器): 加载tomcat/lib/*.jar StandardClassLoader用于加载所有web用到的jar包或类。 A.jar 3)AppClassLoader : jdk的CLASSPATH 4)ExtClassLoader: jre/lib/ext/*.jar 5)BootStrap : jar/lib/rt.jar */ ClassLoader cl = this.getClass().getClassLoader(); while (cl != null) { System.out.println(cl.getClass().getName()); cl = cl.getParent(); } System.out.println(cl); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
反射
什么是反射(Reflection):
在运行时通过目标类的Class对象(字节码文件对象),将目标类的字段,方法,构造器等映射成相应的类,动态获取目标类的信息,动态调用对象的方法。
反射机制:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的方法
动态语言和静态语言
程序运行时允许改变程序结构或变量类型的语言称为动态语言,反之为静态语言。
动态语言有:Perl、Python、Ruby、JavaScript
静态语言有:C++、Java、C#
反射常见API:
java.lang.Class: 代表一个类。
java.lang.reflect.Field: 代表类的成员变量(属性)。
java.lang.reflect.Method: 代表类的方法。
java.lang.reflect.Constructor: 代表类的构造方法。
java.lang.reflect.Array: 提供了动态创建数组,以及访问数组元素的静态方法。
常用方法:
Java中,某个类无论生成多少个对象,这些对象都对应于同一个Class对象。
获取某类或某对象的Class对象的三种方法:
1)使用Class类的静态方法:Class.forName("类名(全称lang包类可不)");
2)使用 类名.class
3)使用Object类的实例方法:对象.getClass();
获取构造方法
getConstru...三个,getDeclaredConstru...三个
构造对象的两种方法:
1)先获取Class对象,再通过Class对象的newInstance()方法生成类的无参对象:
Class<?> classType = Class.forName("java.lang.String");
Object string = classType.newInstance();//空字符串
2)先获取Class对象,然后通过Class对象的getConstructor(可变参数)获取对应的Constructor对象,再通过Constructor对象的newInstance(可变参数)方法生成类的无参或有参对象:
Class<?> classType = Class.forName("java.lang.String");
Constructor<?> constructor1 = classType.getConstructor();
Object string1 = constructor1.newInstance();//空字符串
Constructor<?> constructor2 = classType.getConstructor(new Class[] { String.class });
Object string2 = constructor2.newInstance(new Object[] { ("Hello") });//Hello
获取方法、属性:见示例。
API用法示例
package com.tongwx.reflect; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class DumpMethods { public static void main(String[] args) throws Exception { /** * 获取Class类对象 */ //获取指定类的Class对象第一种方法:使用Class类的静态方法Class.forName() Class<?> classType = Class.forName("java.lang.String");//class java.lang.String //获取Class对象的第二种方法:使用句式 类名.class Class<?> classType2 = String.class;//class java.lang.String //获取Class对象的第三种方法:使用Object类的实例方法getClas() Class<? extends String> classType3 = "对象".getClass();//class java.lang.String //获取父类的Class对象 Class<?> superclassType = String.class.getSuperclass();//class java.lang.Object //Integer.TYPE 和 Integer.class 的区别(其他七个 原生类型/包装类型 类似) Class<?> type = Integer.TYPE;//Integer.TYPE返回的是原生类型int所对应的Class对象:int Class<?> type2 = Integer.class;//Integer.class返回的是Integer类所对应的Class对象:class java.lang.Integer /** * 获取类名、所继承的类、所实现的类 */ String name = classType.getName();//java.lang.String String simpleName = classType.getSimpleName();//String Class<?>[] interfaces = classType.getInterfaces();//实现了Serializable、Comparable、CharSequence(类全名略) Class<?> superclass = classType.getSuperclass();//class java.lang.Object /** * 获取类实例 */ //方法一(只能获取类的无参构造实例):通过Class类的实例方法获取Class对象所代表的类的无参构造实例 Object string = classType.newInstance();//空字符串 //方法二:通过Constructor类的实例方法获取Class对象所代表类的无参或有参构造实例 Constructor<?> constructor = classType.getConstructor();//public java.lang.String() Constructor<?> constructor2 = classType.getConstructor(new Class[] { String.class });//public java.lang.String(java.lang.String) Constructor<?> constructor3 = classType.getConstructor(new Class[] { byte[].class });//public java.lang.String(byte[]) Object newInstance = constructor.newInstance();//空字符串 Object newInstance2 = constructor2.newInstance(new Object[] { ("Hello") });//Hello Object newInstance3 = constructor3.newInstance(new Object[] { new byte[] { 'H', 'i' } });//Hi /** * 获取并调用类方法 */ //获取Class对象所代表类的所有声明的方法(包括所有访问类型方法,不包括继承的方法) Method[] methods = classType.getDeclaredMethods(); //获取Class对象所代表类的所有公共的方法(只包括公共方法,包括继承的公共方法) Method[] methods2 = classType.getMethods(); //获取Class对象所代表类的指定公共方法(参数列表为:(String 方法名, Class<?>... 方法参数对应的Class对象列表)) Method indexOfMethod = classType.getMethod("indexOf", new Class[] { String.class, int.class }); //调用方法,获取方法返回值(参数列表为:(Object 调用方法所需实例(静态不需实例写null), Object... 方法实际参数列表)) Object index = indexOfMethod.invoke("凤凰台上凤凰游", new Object[] { "凤凰", 2 });//4 //获取Class对象所代表类的指定方法包括私有方法(参数列表为:(String 方法名, Class<?>... 方法参数对应的Class对象列表)) Method sayHelloMethod = com.tongwx.reflect.PrivateTestClass.class.getDeclaredMethod("sayHello", String.class); //设置私有方法可访问 sayHelloMethod.setAccessible(true); //调用私有方法,获取方法返回值(参数列表为:(Object 调用方法所需实例(静态不需实例写null), Object... 方法实际参数列表) Object result = sayHelloMethod.invoke(new PrivateTestClass(), "tongwx");//Hello, tongwx! /** * 获取并修改类属性 */ //获取Class对象所代表类的所有声明的属性(包括所有访问类型的属性,不包括继承的属性) Field[] declaredFields = classType.getDeclaredFields(); for (Field field : declaredFields) { String fieldName = field.getName();//获取属性名 Class<?> fieldType = field.getType();//获取属性类型 } //获取Class对象所代表类的所有公共的属性(只包括公共属性,包括继承的公共属性) Field[] fields = classType.getFields(); //获取Class对象所代表类的私有属性并修改其值 Field privateNameField = com.tongwx.reflect.PrivateTestClass.class.getDeclaredField("name");//获取指定(私有)属性 privateNameField.setAccessible(true);//设置私有属性可访问 PrivateTestClass privateTestClass = new PrivateTestClass(); privateNameField.set(privateTestClass, "lisi");//修改指定对象属性值 Object privateNameValue = privateNameField.get(privateTestClass);//获取指定对象属性值 /** * Array类操作数组 */ //创建一维数组。参数含义:(新数组组件类型的Class对象,新数组维度) Object arr = Array.newInstance(Integer.class, 10); //设置某值(要设置的数组,要设置的下标,要设置的值) Array.set(arr, 5, 6); //查看某值(要访问的数组,要访问的下标) Object object2 = Array.get(arr, 5);//6 Integer integer = ((Integer[]) arr)[5];//6 //创建多维数组。参数含义:(新数组组件类型的Class对象,新数组维度)此例三维,长2宽3高5 Object multiArr = Array.newInstance(Integer.TYPE, new int[] { 2, 3, 5 }); //设置某值(要设置的数组,要设置的下标,要设置的值) Array.set(Array.get(Array.get(multiArr, 1), 2), 4, 8); //查看某值(要访问的数组,要访问的下标) Object object = Array.get(Array.get(Array.get(multiArr, 1), 2), 4);//7 int i = ((int[][][]) multiArr)[1][2][4];//7 } } class PrivateTestClass { private String name = "zhangsan"; public String getName() { return name; } private String sayHello(String name) { return "Hello, " + name + "!"; } } |
案例:调用getter和setter方法复制对象
import java.lang.reflect.Field; import java.lang.reflect.Method; public class Demo { private String name; private int age; private long time; 一系列getter和setter方法、toString方法、无参构造方法、全参构造方法 public static void main(String[] args) throws Exception { Demo demo = new Demo("张三", 18, 123); Demo newDemo = (Demo) copyObjectBySetterAndGetter(demo); System.out.println(newDemo); //Demo [name=张三, age=18, time=123] } public static Object copyObjectBySetterAndGetter(Object obj) throws Exception { Class<?> classType = obj.getClass(); Object newObj = classType.newInstance(); Field[] fields = classType.getDeclaredFields(); for (Field field : fields) { //遍历属性名以构建getter和setter方法名 String fieldName = field.getName(); String setterName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); //获取getter方法和setter方法 Method getterMethod = classType.getMethod(getterName, new Class[] {}); Method setterMethod = classType.getMethod(setterName, new Class[] { field.getType() }); //用getter方法和setter方法取旧传新 Object fieldValue = getterMethod.invoke(obj, new Object[] {}); setterMethod.invoke(newObj, new Object[] { fieldValue }); } return newObj; } } |
案例:对JavaBean的null值属性赋默认值
Field[] field = model.getClass().getDeclaredFields(); // 获取实体类的所有属性,返回Field数组 try { for (int j = 0; j < field.length; j++) { // 遍历所有属性 String name = field[j].getName(); // 获取属性的名字 name = name.substring(0, 1).toUpperCase() + name.substring(1); // 将属性的首字符大写,方便构造get,set方法 String type = field[j].getGenericType().toString(); // 获取属性的类型 if (type.equals("class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名 Method m = model.getClass().getMethod("get" + name); String value = (String) m.invoke(model); // 调用getter方法获取属性值 if (value == null) { m = model.getClass().getMethod("set" + name, String.class); m.invoke(model, ""); } } if (type.equals("class java.lang.Integer")) { Method m = model.getClass().getMethod("get" + name); Integer value = (Integer) m.invoke(model); if (value == null) { m = model.getClass().getMethod("set" + name, Integer.class); m.invoke(model, 0); } } if (type.equals("class java.lang.Boolean")) { Method m = model.getClass().getMethod("get" + name); Boolean value = (Boolean) m.invoke(model); if (value == null) { m = model.getClass().getMethod("set" + name, Boolean.class); m.invoke(model, false); } } if (type.equals("class java.util.Date")) { Method m = model.getClass().getMethod("get" + name); Date value = (Date) m.invoke(model); if (value == null) { m = model.getClass().getMethod("set" + name, Date.class); m.invoke(model, new Date()); } } } } 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(); } |