类加载的概述

类加载分为三个步骤:类加载,,连接,,初始化

加载:指的是,将class文件读入到内存中,并为之创建一个Class工具。
任何类被利用系统都会创建一个Class工具

jsp用bootstrap中文乱码java反射基本 u0026u0026 动态署理解决乱码问题 u0026u0026 注解 SQL

连接:验证class文件知否符合哀求。
准备,为静态成员分配内存。
解析class文件

初始化:进行布局方法的初始化

类加载的机遇:

创建类的实例工具

调用类的静态成员,为静态变量赋值

调用类的静态方法。

利用反射天生相应的Class工具

初始化某个类的子类

直接运行主类

类加载器的分类

根类加载器

BootstrapClassLoader

卖力一些核心类的加载,比如String int float System

这些类频繁的与内存进行交互,一样平常是非常快,是伪类,用c c++写

扩展类加载器

Extension ClassLoader 在ext包下的jar都会该加载器

运用类加载器

App ClassLoader 平常我们自定义的类都是用的运用类的加载器

反射概述

反射便是得到某个类在运行状态中的字节码工具,Class工具,并根据该工具中的方法,去解析该类中的属性和方法。
并且去调用该类的属性和方法。

这种动态获取信息,并且动态调用工具的方法便是java措辞的反射机制

获取Class工具

类名.class

new 类名().getClass()

Class,forName(“类的全路径”)

反射的利用

基本用法

通过反射获取无参的布局方法和获取带参的布局方法并利用

public static void main(String[] args) throws Exception{

Class<People> clazz = People.class;

//得到该Class工具所表示的类的无参的布局方法,并为其创建一个实例.

//不是无参的布局,就不能用这种办法

People people = clazz.newInstance();

String b = people.b;

System.out.println(b);

//获取该Class工具所表示的类的有参的布局方法,参数写相对应参数类型的Class工具,不写默认为空,返回无参布局方法

Constructor<People> constructor = clazz.getConstructor(String.class);

People people = constructor.newInstance();

String b = people.b;

System.out.println(b);

}

通过反射获取公共的成员变量和获取私有的成员变量

public static void main(String[] args) throws Exception {

//先通过反射获取实例

Class<People> clazz = People.class;

People people = clazz.newInstance();

//获取该Class工具表示的类的公共的成员变量

Field b = clazz.getField(\"大众b\"大众);

String o = (String)b.get(people);

System.out.println(o);

//获取Class工具表示的类的私有的成员变量

//通过暴力反射

Field a = clazz.getDeclaredField(\"大众a\公众);

//暴力反射要先设置权限

a.setAccessible(true);

int o1 = (int)a.get(people);

System.out.println(o1);

}

通过反射获取公共的成员方法

Class工具中的getMethod() 方法,获取该方法,返回Method工具

Method工具中的invoke() 方法,实行该方法

这是在运行期间,通过反射获取字节码工具,并且运行方法的办法

public static void main(String[] args) throws Exception {

Class<People> clazz = People.class;

Constructor<People> constructor = clazz.getConstructor(String.class);

People people = constructor.newInstance(\"大众dsa\公众);

//获取获取该Class工具表示的类的公共的成员方法

Method m = clazz.getMethod(\公众text\公众);

Object invoke = m.invoke(people);

System.out.println(invoke);

}

通过反射超越泛型检讨

泛型只在编译期间有效,在运行期间无效

通过反射实现动态代理

代理,相称于中介,自己要做的事情没有做,交给了别人

动态代理:程序运行的过程中产生的这个工具。

这个工具便是通过反射来得到的一个实例工具(代理工具),

实现

通过java.lang.reflect 包下的Proxy工具 和 InvocationHandler接口天生代理工具,把稳,只能代理接口。

更强大的代理:利用cglib

创建代理工具:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException

都会调用方法 InvocationHandler 接口中的 invoke() 方法

Object invoke(Object proxy,Method method,Object[] args)throws Throwable

代码解析

public static void main(String[] args) {/ 第一个参数:见告虚拟机通过反射创建出类的字节码文件用哪个字节码加载器(运用类加载器)加载到内存 第二个参数:见告虚拟机通过反射创建出来的字节码文件中该当有多少个方法,也便是被代理工具实现了那些接口 第三个参数:见告虚拟机创建的字节码文件中的方法该当怎么处理/Icar o =(Icar) Proxy.newProxyInstance(Demo1.class.getClassLoader(), GooleCar.class.getInterfaces(), new InvocationHandler() {/ @param proxy 动态代理的实例,不用管 @param method 动态代理工具正在实行的方法 @param args 动态代理工具正在实行的方法中的参数的值,不写默认为null @return @throws Throwable/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String start = method.getName();if(\公众start\公众.contentEquals(start)){/ 实行当前的方法。
第一个参数:是被代理的工具 第二个参数:方法实行的参数的值,不写默认为空/method.invoke(new GooleCar(),args);System.out.println(\"大众hahahahahhah\公众);}return null;}});o.start();}动态代理办理乱码问题

当进行二次开拓的时候,我们只有api,没有源码,也不能继续,要想增加功能,进行二次开拓,利用动态代理模式

办理乱码问题,利用过滤器。
每次要求都进行了中文乱码问题的处理。

实现:增请HttpServletRequest类中的getParameter()方法,使其获取中文数据的时候,不涌现乱码问题

代码实现

final HttpServletRequest request = (HttpServletRequest) servletRequest;

要利用final润色才可以

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {final HttpServletRequest request = (HttpServletRequest) servletRequest;//在不知道源码,不能继续的情形下改变request中的getParameter方法,办理乱码问题HttpServletRequest myRequest = (HttpServletRequest)Proxy.newProxyInstance(MyFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = null;String name = method.getName();if (\公众getParameter\"大众.equalsIgnoreCase(name)) {//增强getParameter()方法String method1 = request.getMethod();if (\"大众get\公众.equalsIgnoreCase(method1)) {//get要求办理乱码问题,转码String invoke = (String) method.invoke(request, args);String a = new String(invoke.getBytes(\"大众ISO-8859-1\"大众), \"大众utf-8\"大众);return a;} else { //post要求办理乱码问题request.setCharacterEncoding(\"大众utf-8\公众);obj = method.invoke(request, args);}}else {obj = method.invoke(request,args);}return obj;}});filterChain.doFilter(myRequest,servletResponse);}表明

表明哀求:

理解

开拓中地位:类似dom4j解析XML文件. XML文件的解析程序员不会去解析,配置XML文件。
后期的开拓中不会自定义表明,反射读取表明信息.

什么是表明

表明就相称于一个数据类型,与类、接口类似

表明的浸染

配置文件

天生帮助文档

编译检讨

表明特点

直接可以在变量、方法、类之上加载

表明可以由属性,也可以没属性

表明的浸染范围

源码期间有效

String类上的 ,注释里面的表明,帮助天生帮助文档,可以识别String类上的干系的表明

@Author, 表示作者

@Since,表示版本

@See ,参照的东西

编译期间有效

见告编译器部分信息

@Override 声明当前方法是重写父类的方法

@Deprecated 声明以下方法是过期的方法,不建议大家利用

@Suppresswarning 抑制编译器发生警告信息

运行期间有效

当我们在当前代码上以Junit办法运行时,Junit会运行方法上包含@Test表明的方法

@Test

我们再当前代码上以Junit办法运行时,Junit会运行方法上包含@Test表明的方法

自定义表明

格式:

public @interface 表明名称{public 属性类型 属性名称1();public 属性类型 属性名称2() default 默认值;}

自定义表明属性支持的类型:

基本数据类型(4类8种),String,Class,Annotation(表明类型),列举类型,

以及以上类型的一维数组类型

表明浸染: 配置浸染

配置:开拓的时候部分信息不肯望写去世在程序中,例如数据库的用户名和密码,可以将用户名和密码存放在.txt , .properties ,

.xml文件中,利用程序来读取文件中的内容

框架:一大堆工具类组合,目的:加速项目开拓

什么时候用表明来做配置?

如果配置信息不会发生的修正,例如servlet路径,建议利用表明的形式

如果配置信息须要发生频繁的修正,例如数据库的用户名和密码信息, 建议采取传统方法 (.txt , .properties , .xml)

仿照Junit

通过反射读取字节码上的表明信息

md.isAnnotationPresent(MyTest.class)

元表明

表明的表明,

声明当前表明浸染域以及目标工具,如果没有声明,在运行期间是无法获取到表明的信息

@Runtention 声明当前表明的浸染域

@target 声明当前表明的目标工具

代码实现

自定义表明@MyTest

//自定义表明,相称于JUnit@Test

//定义表明的时候,须要通过元表明Retention解释当前自定义表明的浸染域(Class,Source,Runtime)

@Retention(RetentionPolicy.RUNTIME)

//定义表明的时候,须要通过元表明Target解释当前的自定义表明的目标工具

@Target(ElementType.METHOD)

public @interface MyTest {

//在MyTest表明中定义成员属性,默认值为-1

public long timeout() default -1;

}

定义UserDao

public class UserDao {

static{

System.out.println(\"大众加载静态代码段的\"大众);

}

@MyTest

public void addUser(){

System.out.println(\"大众增加用户\公众);

}

@MyTest

public void delUser(){

System.out.println(\"大众删除用户\"大众);

}

@MyTest

public void uptUser(){

System.out.println(\"大众更新用户\公众);

}

public void getUser(){

System.out.println(\公众获取用户\"大众);

}

}

定义类MyJunit ,仿照JUnit

public class MyJunit {

public static void main(String[] args) throws Exception {

//加载UserDao.class字节码文件中的方法,判断哪些方法上有自定义的表明@MyTest,如果当前的方法有@MyTest,实行,否则不实行

//1_将UserDao.class字节码文件加载到内存中 ,class工具(代表字节码文件在内存中的工具)

Class clazz=Class.forName(\公众com.itcast.test02.UserDao\公众);

Class claszz01=UserDao.class;

Class claszz02=new UserDao().getClass();

//2_获取字节码工具上所有的方法,返回Method数组工具,数组中的每一个元素都代表Method工具(相称于字节码上的每一个方法)

Method[] mds = clazz.getMethods();

//3_遍历字节码工具上所有的方法

for (Method md : mds) {

//测试方法的名称

//System.out.println(md.getName());

//判断当前方法上是否有@MyTest表明信息

//System.out.println(md.isAnnotationPresent(MyTest.class));

if(md.isAnnotationPresent(MyTest.class)){

//如果当前的方法上有@MyTest表明,实行,否则忽略

md.invoke(new UserDao());

}

}

}

}