Java反射

加载类概述

类加载分为三个阶段:类加载、连接和初始化

加载:是指将class文件读取到内存中,以便为该文件创建Class对象。

任何类被使用系统都会创建一个Class对象

连接:验证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 = Peo;

//获得该Class对象所表示的类的无参的构造方法,并为其创建一个实例.

//不是无参的构造,就不能用这种方式

People people = clazz.newInstance();

String b = ;

Sy(b);

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

constructor<People> constructor = clazz.getConstructor);

People people = con();

String b = ;

Sy(b);

}

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

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

//先通过反射获取实例

Class<People> clazz = Peo;

People people = clazz.newInstance();

//获取该Class对象表示的类的公共的成员变量

Field b = clazz.getField("b");

String o = (String(people);

Sy(o);

//获取Class对象表示的类的私有的成员变量

//通过暴力反射

Field a = clazz.getDeclaredField("a");

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

a.setAccessible(true);

int o1 = (in(people);

Sy(o1);

}

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

Class对象中的getMethod() 方法,获取该方法,返回Method对象

Method对象中的invoke() 方法,执行该方法

这是在运行期间,通过反射获取字节码对象,并且运行方法的方式

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

Class<People> clazz = Peo;

Constructor<People> constructor = clazz.getConstructor);

People people = con("dsa");

//获取获取该Class对象表示的类的公共的成员方法

Method m = clazz.getMethod("text");

Object invoke = m.invoke(people);

Sy(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(), GooleCar.cla(), 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 = me();if("start".contentEquals(start)){/*** 执行当前的方法。* 第一个参数:是被代理的对象* 第二个参数:方法执行的参数的值,不写默认为空*(new GooleCar(),args);Sy("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 = (HttpServletReque(), reque().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = null;String name = me();if ("getParameter".equalsIgnoreCase(name)) {//增强getParameter()方法String method1 = reque();if ("get".equalsIgnoreCase(method1)) {//get请求解决乱码问题,转码String invoke = (String) me(request, args);String a = new String("ISO-8859-1"), "utf-8");return a;} else { //post请求解决乱码问题reque("utf-8");obj = me(request, args);}}else {obj = me(request,args);}return obj;}});(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.isAnnotationPresen)

元注解

注解的注解,

声明当前注解作用域以及目标对象,如果没有声明,在运行期间是无法获取到注解的信息

@Runtention 声明当前注解的作用域

@target 声明当前注解的目标对象

代码实现

自定义注解@MyTest

//自定义注解,相当于JUnit@Test

//定义注解的时候,需要通过元注解Retention说明当前自定义注解的作用域(Class,Source,Runtime)

@Retention)

//定义注解的时候,需要通过元注解Target说明当前的自定义注解的目标对象

@Targe)

public @interface MyTest {

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

public long timeout() default -1;

}

定义UserDao

public class UserDao {

static{

Sy("加载静态代码段的消息");

}

@MyTest

public void addUser(){

Sy("增加用户");

}

@MyTest

public void delUser(){

Sy("删除用户");

}

@MyTest

public void uptUser(){

Sy("更新用户");

}

public void getUser(){

Sy("获取用户");

}

}

定义类MyJunit ,模拟JUnit

public class MyJunit {

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

//加载U字节码文件中的方法,判断哪些方法上有自定义的注解@MyTest,如果当前的方法有@MyTest,执行,否则不执行

//1_将U字节码文件加载到内存中 ,class对象(代表字节码文件在内存中的对象)

Class clazz=Cla("com.i;);

Class claszz01=U;

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

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

Method[] mds = clazz.getMethods();

//3_遍历字节码对象上所有的方法

for (Method md : mds) {

//测试方法的名称

//Sy());

//判断当前方法上是否有@MyTest注解信息

//Sy(md.isAnnotationPresen));

if(md.isAnnotationPresen)){

//如果当前的方法上有@MyTest注解,执行,否则忽略

md.invoke(new UserDao());

}

}

}

}

1.《程序中出现乱码怎么办看这里!java反射基础 &amp;&amp; 动态代理解决乱码问题 &amp;&amp; 注解》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《程序中出现乱码怎么办看这里!java反射基础 &amp;&amp; 动态代理解决乱码问题 &amp;&amp; 注解》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/gl/3039292.html