类加载器和反射

类加载器

类加载器是通过某个类的.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();

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值