Java的Class类,注解与反射
Class对象:
- 我们每创建一个类,经过build都会生成对应的.class文件
- 该类无法只能由虚拟机创建对象,其构造函数为private
- 当我们创建某个类的对象,ClassLoader(一个类)就会装载对应.class文件到虚拟机(仅一次)
- 该Class对象存有函数对应的Constructors(搭配反射使用),Fields(访问私有变量,getFields()只能访问公有,getDeclaredFields()可以访问所有属性),Methods(可以用于动态代理)(以指针的形式)等信息,通常用于反射
- 可以通过
ClassName.class
,className.getClass()
,Class.forName("limitName")
获取
为了保存class中的字段,构造器和方法,Java有定义了三种不同的类Constructor,Field,Method,同时在类对应的class文件中包含了它们的数组引用
classLoader
作用:加载.Class对象
分类
- BootstrapClassLoader:核心库加载,如
%JRE_HOME%\lib
- ExtClassLoader:扩展库加载,如
%JRE_HOME%\lib\ext
- AppClassLoader:程序库加载,如当前应用的classpath下的类
- CustomClassLoader:自定义类加载器
注:对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器(正是这一条规定导致了JavaSPI机制需要破坏双亲委派机制)
- BootstrapClassLoader:核心库加载,如
双亲委派机制:上面四个加载器构成上下级关系,双亲委派机制优先询问上级是否加载过相应的类。如果父类加载器无法完成加载,子类才去加载
/**
* Loads the class with the specified <a href="#name">binary name</a>. The
* default implementation of this method searches for classes in the
* following order:
*
* <ol>
*
* <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
* has already been loaded. </p></li>
*
* <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
* on the parent class loader. If the parent is <tt>null</tt> the class
* loader built-in to the virtual machine is used, instead. </p></li>
*
* <li><p> Invoke the {@link #findClass(String)} method to find the
* class. </p></li>
*
* </ol>
*
* <p> If the class was found using the above steps, and the
* <tt>resolve</tt> flag is true, this method will then invoke the {@link
* #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
*
* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
* #findClass(String)}, rather than this method. </p>
*
* <p> Unless overridden, this method synchronizes on the result of
* {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
* during the entire class loading process.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @param resolve
* If <tt>true</tt> then resolve the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class could not be found
*/
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
} if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name); // this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
具体流程:
通过
findLoadedClass
查找是否该类是否已经被加载过(其底层是native的)如果没加载过,有父类则先尝试调用父类进行加载
如果没加载过,没有父类则直接尝试用BootstrapClassLoader加载
/**
* Returns a class loaded by the bootstrap class loader;
* or return null if not found.
*/
private Class<?> findBootstrapClassOrNull(String name)
{
if (!checkName(name)) return null; return findBootstrapClass(name);
}
好处:
- 避免重复加载
- 安全
为什么要使用反射:因为在代码运行过程中,我们可能需要知道运行的类的相关信息并对其进行操作
以动态反射为例,假如我们要给某个类添加日志操作,显然我们可以直接在对应的类中添加相关的打印日志信息的操作,显然这个方法不仅繁琐而且不符合设计模式对于解耦的追求。通过反射,即可将日志动作与运行的类分离。
package org.example; import org.omg.CORBA.portable.InvokeHandler;
import redis.clients.jedis.Jedis; import java.lang.reflect.*; /**
* Hello world!
*
*/ interface DemoInf{
public void doWork();
} class Demo implements DemoInf{
public void doWork(){
System.out.println("Do something~");
}
} public class App
{
public static void main( String[] args ) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Demo demo = new Demo(); //这里是唯一创建的实例,而不是接口
Class<?> proxyClass = Proxy.getProxyClass(DemoInf.class.getClassLoader(), DemoInf.class);
Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
DemoInf DemoInf = (DemoInf)constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before methods");
method.invoke(demo, args); //通过Method类的invoke方法调用,实际的Demo对象
System.out.println("after methods");
return null;
}
});
DemoInf.doWork();
}
}
四个元注解
@Target
:指定注解的使用范围,相应的参数可以通过ElementType配置@Retention
:指定注解的保留策略,源码,.Class文件中或是运行时,通过RetentionPolicy类配置@Documented
:是否将注解包含在javadoc中@Inherited
:可以被子类继承@Repeatable
:注解是否可以重复使用,比如某个类上重复添加某个注解
为什么要使用注解
注解可以看做是对类或者他的方法和字段的额外信息,通过注解我们可以在不改变原代码和逻辑的情况下在源代码中嵌入补充信息。如,通过@Test注解实现对测试类的运行(类似Junit)
定义
package com.example.readfile.annotation; import java.lang.annotation.*; @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Test {
String value();
}
使用
package com.example.readfile.service.impl; import com.example.readfile.annotation.Test;
import com.example.readfile.service.List; public class UnorderList implements List { @Test("addContent")
@Override
public String addContent(String content) {
System.out.println("have a test:"+content);
return null;
}
}
读取
@Test
void annotationTest() throws InvocationTargetException, IllegalAccessException, InstantiationException {
Method[] methods = UnorderList.class.getMethods();
for (Method method : methods) {
com.example.readfile.annotation.Test annotation = method.getAnnotation(com.example.readfile.annotation.Test.class);
if (annotation!=null){
System.out.println(annotation.value());
method.invoke(UnorderList.class.newInstance(),"annotationTest"); //Java中执行方法,隐式地规定了需要指明是哪个对象执行方法
}
}
}
注:函数上面那个@Test是模拟的Junit中的@Test
Java的Class类,注解与反射的更多相关文章
- Java注解和反射
1.注解(Annotation) 1.1.什么是注解(Annotation) 注解不是程序本身,可以在程序编译.类加载和运行时被读取,并执行相应的处理.注解的格式为"@注释名(参数值)&qu ...
- Java枚举类、注解和反射
本文主要介绍的是枚举类,注解和反射.还有一些基础知识:static,基本数据类型,运算符优先级放在文中,以便查阅复习. 其中牵扯到泛型的部分,可参考本人的另一篇博客:(Collection, List ...
- Java利用自定义注解、反射实现简单BaseDao
在常见的ORM框架中,大都提供了使用注解方式来实现entity与数据库的映射,这里简单地使用自定义注解与反射来生成可执行的sql语句. 这是整体的目录结构,本来是为复习注解建立的项目^.^ 好的,首先 ...
- 【Java】利用注解和反射实现一个"低配版"的依赖注入
在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何用Java的注解和反射实现一个“低配版”的依赖注入. 下面是我们 ...
- java自定义注解与反射
java注解与反射一.Java中提供了四种元注解,专门负责注解其他的注解,分别如下 1.@Retention元注解,表示需要在什么级别保存该注释信息(生命周期).可选的RetentionPoicy参数 ...
- Java基于注解和反射导入导出Excel
代码地址如下:http://www.demodashi.com/demo/11995.html 1. 构建项目 使用Spring Boot快速构建一个Web工程,并导入与操作Excel相关的POI包以 ...
- 使用Java元注解和反射实现简单MVC框架
Springmvc的核心是DispatcherServlet来进行各种请求的拦截,进而进行后续的各种转发处理.流程图如下: 说明:客户端发出一个http请求给web服务器,web服务器对http请求进 ...
- Java基础--注解、反射
一.注解(Annotation) 1.什么是注解? 从JDK5开始,Java增加了Annotation(注解),Annotation是代码里的特殊标记,这些标记可以在编译.类加载.运行时被读取,并执行 ...
- Java Scala获取所有注解的类信息
要想获取使用指定注解的类信息,可借助工具: org.reflections.Reflections 此工具将Java反射进行了高级封装,Reflections 通过扫描 classpath,索引元数据 ...
- Java笔记---枚举类和注解
Java笔记---枚举类和注解 一.枚举类 自定义枚举类 方式一:JDK5.0之前自定义枚举类 class Seasons { //1. 声明Seasons对象的属性 private final St ...
随机推荐
- 【栈和队列】纯C实现栈和队列以及其基本操作-宝藏级别数据结构教程【保姆级别详细教学】
[栈和队列]栈和队列的C语言实现-宝藏级别数据结构教程-超详细的注释和解释 先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记 ...
- 3.4 CSP-J 补赛游寄
3.4 CSP-J 补赛游寄 Day -? 听说要去打比赛. Day -7 今天家长会,老师公布成绩 /fn/fn/fn.政治考废了,然后其他都挺好. 语文 $ 95 $,数学 $ 118 $,英语 ...
- Go语言的100个错误使用场景(40-47)|字符串&函数&方法
目录 前言 5. 字符串 5.5 无用的字符串转换(#40) 5.6 获取子字符串操作和内存泄漏(#41) 6. 函数和方法 6.1 不知道选择哪种类型的方法接受者(#42) 6.2 从来不使用命名的 ...
- C语言,函数形参与实参个数不一致问题
最近阅读工程代码的时候,同一个函数,不同场景调用时,输入的实参个数不一样,但是编译却没有问题.查看函数的定义,相关的C文件里并没有给形参指定默认值,这就很奇怪了. 最终,发现在函数相关的头文件 ...
- 云原生服务网格Istio:原理、实践、架构与源码解析
华为云原生团队600多页的Istio实战精华总结,云原生服务网格Istio:原理.实践.架构与源码解析的电子书. 图书介绍 <云原生服务网格Istio:原理.实践.架构与源码解析>分为原理 ...
- java 如何计算两个汉字的相似度?如何获得一个汉字的相似汉字?
计算汉字相似度 情景 有时候我们希望计算两个汉字的相似度,比如文本的 OCR 等场景.用于识别纠正. 实现 引入 maven <dependency> <groupId>com ...
- 贝壳云P1刷机记录(5.10内核Armbian)
说明 贝壳云基于瑞芯微的RK3328芯片, 芯片介绍, Cortex-A53架构, 4核, 1G内存, 8G eMMC. 板载1个千兆网口, 4个USB3.0. 这个盒子比较赞的地方就是不到百元的价格 ...
- CoreDNS笔记
因为项目的原因需要在客户端启动DNS服务,拦截本机DNS请求,考察了一下开源的DNS Server项目,适合在Windows下使用的只有CoreDNS. 说明 CoreDNS的项目地址 https:/ ...
- java.lang.System快速指南
1.介绍 在本教程中,我们将快速了解java.lang.System类及其特性和核心功能. 2.IO 系统类是java.lang的一部分,它的一个主要特性是让我们能够访问标准的I/O流. 简单地说,它 ...
- nodejs+express4实现文件上传下载删除和列表展示功能
0.效果展示 1.创建项目 创建文件夹:express_file_upload npm init # 入口文件选择server.js 安装插件 npm install express npm inst ...