注解(Annotation)

注解入门

可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信 息,我们可以通过反射机制编程实现对这些元数据的访问

内置注解

@Override
– 此注释只适用于修辞方法,表示一个方 法声明打算重写超类中的另一个方法声明。
@Deprecated
– 此注释可用于修辞方法、属性、类 ,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
@SuppressWarnings
– 用来抑制编译时的警告信息 。
– 与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参 数值都是已经定义好了的,我们选择性的使用就好了,参数如下:

public @interface SuppressWarnings{String[] value();// value 为参数名,String为参数类型,详见上述截图
}

自定义注解、元注解

自定义注解

• 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
• 要点: – @interface用来声明一个注解
• 格式为:
– public @interface 注解名 {定义体} – 其中的每一个方法实际上是声明了一个配置参数。
– 方法的名称就是参数的名称
– 返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)
– 可以通过default来声明参数的默认值。
– 如果只有一个参数成员,一般参数名为value
• 注意:注解元素必须要有值。我们定义注解元素时,经常使用空字符串、0作为默认值。 也经常使用负数(比如:-1)表示不存在的含义


@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface test{String studentName() default "";int age() default 0;int id() default -1;   //String indexOf("abc")  -1String[] schools() default {"清华大学","北京大学"};}

元注解

• 元注解的作用就是负责注解其他注解。 Java定义了4个标准的 meta-annotation类型,它们被用来提供对其它 annotation 类型作说明。
• 这些类型和它们所支持的类在java.lang.annotation包中可以 找到
– @Target

– @Retention
source反射不到

– @Documented
– @Inherited

反射

通过反射获取注解

@SxtTable("tb_student")
public class Student {@SxtField(columnName="id",type="int",length=10)private int id;@SxtField(columnName="sname",type="varchar",length=10)private String studentName;@SxtField(columnName="age",type="int",length=3)private int age;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getStudentName() {return studentName;}public void setStudentName(String studentName) {this.studentName = studentName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}/*** 使用反射读取注解的信息,模拟处理注解信息的流程**/
public class Demo03 {public static void main(String[] args) {try {Class clazz = Class.forName("com.bjsxt.test.annotation.Student");//获得类的所有有效注解Annotation[] annotations=clazz.getAnnotations();for (Annotation a : annotations) {System.out.println(a);}//获得类的指定的注解SxtTable st = (SxtTable) clazz.getAnnotation(SxtTable.class);System.out.println(st.value());//获得类的属性的注解Field f = clazz.getDeclaredField("studentName");SxtField sxtField = f.getAnnotation(SxtField.class);System.out.println(sxtField.columnName()+"--"+sxtField.type()+"--"+sxtField.length());//根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表} catch (Exception e) {e.printStackTrace();}}
}

反射机制

– 指的是可以于运行时加载、探知、使用编译期间完全未知的类。
– 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个 已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对 象,都能够调用它的任意一个方法和属性;
– 加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个 类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过 这个镜子看到类的结构,所以,我们形象的称之为:反射。

Class对象获取

• 对象.getClass()
• Class.forName()(最常被使用)
• 类名.class 语法

反射的常见作用

• 动态加载类、动态获取类的信息(属性、方法、构造器)
• 动态构造对象
• 动态调用类和对象的任意方法、构造器
• 动态调用和处理属性
• 获取泛型信息
• 处理注解

反射获取

/*** 应用反射的API,获取类的信息(类的名字、属性、方法、构造器等)*/
public class Demo02 {public static void main(String[] args) {String path = "com.bjsxt.test.bean.User";try {Class<?> clazz = Class.forName(path);//获取类的名字System.out.println(clazz.getName());//获得包名+类名:com.bjsxt.test.bean.UserSystem.out.println(clazz.getSimpleName());  //获的类名:User//获取属性信息
//          Field[] fields = clazz.getFields(); //只能获得public的fieldField[] fields = clazz.getDeclaredFields();//获得所有的fieldField f = clazz.getDeclaredField("uname");System.out.println(fields.length);for(Field temp:fields){System.out.println("属性:"+temp);}//获取方法信息Method[] methods = clazz.getDeclaredMethods();Method m01 = clazz.getDeclaredMethod("getUname", null);//如果方法有参,则必须传递参数类型对应的class对象Method m02 = clazz.getDeclaredMethod("setUname", String.class); for(Method m:methods){System.out.println("方法:"+m);}//获得构造器信息Constructor[] constructors = clazz.getDeclaredConstructors();Constructor c = clazz.getDeclaredConstructor(int.class,int.class,String.class);System.out.println("获得构造器:"+c);for(Constructor temp:constructors){System.out.println("构造器:"+temp);}   } catch (Exception e) {e.printStackTrace();}}
}

反射使用

public class Demo03 {public static void main(String[] args) {String path = "com.bjsxt.test.bean.User";try {Class<User> clazz = (Class<User>) Class.forName(path);//通过反射API调用构造方法,构造对象User u = clazz.newInstance();   //其实是调用了User的无参构造方法System.out.println(u);Constructor<User> c = clazz.getDeclaredConstructor(int.class,int.class,String.class);User u2 = c.newInstance(1001,18,"高淇二");System.out.println(u2.getUname());//通过反射API调用普通方法User u3 = clazz.newInstance();Method method = clazz.getDeclaredMethod("setUname", String.class);method.invoke(u3, "高淇三");   //u3.setUname("高淇三");System.out.println(u3.getUname());//通过反射API操作属性User u4 = clazz.newInstance();Field f = clazz.getDeclaredField("uname");f.setAccessible(true); //这个属性不需要做安全检查了,可以直接访问,直接访问私有的属性f.set(u4, "高淇四");       //通过反射直接写属性System.out.println(u4.getUname());   //通过反射直接读属性的值System.out.println(f.get(u4));} catch (Exception e) {e.printStackTrace();}}
}

反射调用泛型

/*** 通过反射获取泛型信息*/
public class Demo04 {public void test01(Map<String,User> map,List<User> list){System.out.println("Demo04.test01()");}public Map<Integer,User> test02(){System.out.println("Demo04.test02()");return null;}public static void main(String[] args) {try {//获得指定方法参数泛型信息Method m = Demo04.class.getMethod("test01", Map.class,List.class);Type[] t = m.getGenericParameterTypes();for (Type paramType : t) {System.out.println("#"+paramType);if(paramType instanceof ParameterizedType){Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();for (Type genericType : genericTypes) {System.out.println("泛型类型:"+genericType);}}}//获得指定方法返回值泛型信息Method m2 = Demo04.class.getMethod("test02", null);Type returnType = m2.getGenericReturnType();if(returnType instanceof ParameterizedType){Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();for (Type genericType : genericTypes) {System.out.println("返回值,泛型类型:"+genericType);} }} catch (Exception e) {e.printStackTrace();}}
}

动态编译(JavaCompiler)


/*** 测试java的动态编译**/
public class Demo01 {public static void main(String[] args) throws Exception {//通过IO流操作,将字符串存储成一个临时文件(Hi.java),然后调用动态编译方法!String str = "public class Hi {public static void main(String[] args){System.out.println(\"HaHa,sxt!\");}}";JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();int result = compiler.run(null, null, null, "c:/myjava/HelloWorld.java");System.out.println(result==0?"编译成功":"编译失败");//通过Runtime调用执行类
//      Runtime run = Runtime.getRuntime();
//        Process process = run.exec("java -cp  c:/myjava    HelloWorld");
//
//        InputStream in = process.getInputStream();
//        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
//      String info = "";
//      while((info=reader.readLine())!=null){//          System.out.println(info);
//      }try {URL[] urls = new URL[] {new URL("file:/"+"C:/myjava/")};URLClassLoader loader = new URLClassLoader(urls);Class c = loader.loadClass("HelloWorld");//调用加载类的main方法Method m = c.getMethod("main",String[].class);m.invoke(null, (Object)new String[]{});//由于可变参数是JDK5.0之后才有。//m.invoke(null, (Object)new String[]{});会编译成:m.invoke(null,"aa","bb"),就发生了参数个数不匹配的问题。//因此,必须要加上(Object)转型,避免这个问题。//public static void main(String[] args)} catch (Exception e) {e.printStackTrace();}}
}

脚本引擎执行JS代码(Rhino)

/*** 测试脚本引擎执行javascript代码*/
public class Demo01 {public static void main(String[] args) throws Exception {//获得脚本引擎对象ScriptEngineManager sem = new ScriptEngineManager();ScriptEngine engine = sem.getEngineByName("javascript");//定义变量,存储到引擎上下文中engine.put("msg", "is a good man!");String str = "var user = {name:'gaoqi',age:18,schools:['清华大学','北京尚学堂']};";str += "println(user.name);";//执行脚本engine.eval(str);engine.eval("msg = 'is a good school';");System.out.println(engine.get("msg"));System.out.println("###########################");//定义函数engine.eval("function add(a,b){var sum = a + b; return sum;}");//取得调用接口Invocable jsInvoke = (Invocable) engine;//执行脚本中定义的方法Object result1 = jsInvoke.invokeFunction("add", new Object[]{13,20});System.out.println(result1);//导入其他java包,使用其他包中的java类.若需要深入了解细节,可以详细学习Rhino的语法String jsCode = "importPackage(java.util); var list=Arrays.asList([\"北京尚学堂\",\"清华大学\",\"北京大学\"]);";engine.eval(jsCode);List<String> list2 = (List<String>)engine.get("list");for (String temp : list2) {System.out.println(temp);}//执行一个js文件(我们将a.js至于项目的src下即可)URL url = Demo01.class.getClassLoader().getResource("a.js");FileReader fr = new FileReader(url.getPath());engine.eval(fr);fr.close();   //由于只是测试,就不那么规范了。大家实际用时要使用try catch finally!}
}

JAVA字节码操作

JAVA动态性的两种方式

  • 字节码操作
  • 反射

实现功能

  • 1.动态生成新的类
  • 2.动态改变某个类的结构(添加/删除/修改 新的属性方法)

优势
比反射开销小,性能高

字节码操作类库

  • BCEl
  • ASM
  • CGLIB
  • JAVAssist

JAVAssist

简介

主要由CtClass、CtMethod、CtField几个类组成组成,用以执行JDK反射中java.lang.Class、java.lang.reflect.Method、java.lang.reflect.Method.Fleld相同的操作

简单使用

1.创建全新的类,使用XJAD反编译工具,将生成的class文件反编译成Jaca文件

public class Demo01 {public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.makeClass("com.bjsxt.bean.Emp");//创建属性CtField f1 = CtField.make("private int empno;", cc);CtField f2 = CtField.make("private String ename;", cc);cc.addField(f1);cc.addField(f2);//创建方法CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno=empno;}", cc);cc.addMethod(m1);cc.addMethod(m2);//添加构造器CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")}, cc);constructor.setBody("{this.empno=empno; this.ename=ename;}");cc.addConstructor(constructor);cc.writeFile("c:/myjava"); //将上面构造好的类写入到c:/myjava中System.out.println("生成类,成功!");}
}
/*** 测试javassist的API*/
public class Demo02 {/*** 处理类的基本用法* @throws Exception */public static void test01() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.bjsxt.test.Emp");byte[] bytes = cc.toBytecode();System.out.println(Arrays.toString(bytes));System.out.println(cc.getName()); //获取类名System.out.println(cc.getSimpleName()); //获取简要类名System.out.println(cc.getSuperclass()); //获得父类System.out.println(cc.getInterfaces()); //获得接口}/*** 测试产生新的方法* @throws Exception */public static void test02() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.bjsxt.test.Emp");//       CtMethod m = CtNewMethod.make("public int add(int a,int b){return a+b;}", cc);CtMethod m = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc);m.setModifiers(Modifier.PUBLIC);m.setBody("{System.out.println(\"www.sxt.cn\");return $1+$2;}");cc.addMethod(m);//通过反射调用新生成的方法Class clazz = cc.toClass();Object obj = clazz.newInstance();  //通过调用Emp无参构造器,创建新的Emp对象Method method = clazz.getDeclaredMethod("add", int.class,int.class);Object result = method.invoke(obj, 200,300);System.out.println(result);}/*** 修改已有的方法的信息,修改方法体的内容* @throws Exception*/public static void test03() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.bjsxt.test.Emp");CtMethod cm = cc.getDeclaredMethod("sayHello",new CtClass[]{CtClass.intType});cm.insertBefore("System.out.println($1);System.out.println(\"start!!!\");");//方法之前cm.insertAt(9, "int b=3;System.out.println(\"b=\"+b);");//第几行加代码cm.insertAfter("System.out.println(\"end!!!\");");// 方法之后//通过反射调用新生成的方法Class clazz = cc.toClass();Object obj = clazz.newInstance();  //通过调用Emp无参构造器,创建新的Emp对象Method method = clazz.getDeclaredMethod("sayHello", int.class);method.invoke(obj, 300);}/*** 属性的操作* @throws Exception*/public static void test04() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.bjsxt.test.Emp");//      CtField f1 = CtField.make("private int empno;", cc);CtField f1 = new CtField(CtClass.intType,"salary",cc);f1.setModifiers(Modifier.PRIVATE);cc.addField(f1);//        cc.getDeclaredField("ename");   //获取指定的属性//增加相应的set和get方法cc.addMethod(CtNewMethod.getter("getSalary", f1));;cc.addMethod(CtNewMethod.getter("setSalary", f1));;}/*** 构造方法的操作* @throws Exception*/public static void test05() throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.bjsxt.test.Emp");CtConstructor[] cs = cc.getConstructors();for (CtConstructor c : cs) {System.out.println(c.getLongName());}}public static void test06() throws Exception{CtClass cc = ClassPool.getDefault().get("com.bjsxt.test.Emp"); Object[] all = cc.getAnnotations();Author a = (Author)all[0]; String name = a.name();int year = a.year();System.out.println("name: " + name + ", year: " + year);}public static void main(String[] args) throws Exception {test06();}
}

JVM核心之JVM运行和类加载全过程

反射、注解、字节码、类加载机制相关推荐

  1. Java_注解 反射 字节码 类加载机制

    一.注解  1. 二.反射  1.动态语言:python.js    程序运行时,可以改变程序结构或变量类型. java的动态性:利用反射机制.字节码操作获得类似动态语言的特性. 2.反射机制 ref ...

  2. 什么是反射和字节码对象。

    1.什么是"反射": 它是Java中提供的一种"操作对象"的方式.在运行状态下,通过class文件对象,去使用构造方法,成员变量,成员方法. 之前我们创建对象: ...

  3. java的反射和它的类加载机制

    2019独角兽企业重金招聘Python工程师标准>>> 1. java 的类装载系统: 在java虚拟机中有两种类装载器: 启动类装载器 和 自定义类装载器. 前者是jvm的一部分, ...

  4. object转class_从零并发框架(三)异步转同步注解+字节码增强代理实现

    序言 上一节我们学习了异步查询转同步的 7 种实现方式,今天我们就来学习一下,如何对其进行封装,使其成为一个更加便于使用的工具. 思维导图如下: 异步转同步字节码增强 拓展阅读 java 手写并发框架 ...

  5. 注解、反射、动态编译、字节码操作

    注解.反射.动态编译.字节码操作 前言:本篇博客将介绍Java中注解的定义.使用以及反射对Java动态性的支持和Java字节码操作,通过本篇内容,读者将对Java知识有更加深刻的理解,同时为后面And ...

  6. 菜鸟学习笔记:Java提升篇12(Java动态性2——动态编译、javassist字节码操作)

    菜鸟学习笔记:Java提升篇12(Java动态性2--动态编译.javassist字节码操作) Java的动态编译 通过脚本引擎执行代码 Java字节码操作 JAVAssist的简单使用 常用API ...

  7. v-html解析的相对地址img 显示不出来_还不懂java类加载机制的,建议看下这份阿里技术官总结的笔记!...

    作者:HandKnock 原文:https://blog.csdn.net/weixin_42547039 类加载机制 把class文件加载到内存,并对数据进行校验,准备,解析,初始化,形成可以被虚拟 ...

  8. 字节码插桩之Java Agent

    字节码插桩之Java Agent 本篇文章将详细讲解有关Java Agent的知识,揭开它神秘的面纱,帮助开发人员了解它的黑魔法,帮助我们完成更多业务需求 What is Java Agent Jav ...

  9. 《深入理解Java虚拟机》笔记5——类加载机制与字节码执行引擎

    第七章 虚拟机类加载机制 7.1 概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 在J ...

  10. Class类文件结构、类加载机制以及字节码执行

    一.Class类文件结构 Class类文件严格按照顺序紧凑的排列,由无符号数和表构成,表是由多个无符号数或其他数据项构成的符合数据结构. Class类文件格式按如下顺序排列: 类型 名称 数量 u4 ...

最新文章

  1. Java设计模式之适配器模式
  2. 牛客 - 养花(最大流)
  3. 一个小码农对嵌入式的理解
  4. TensorFlow2.0(一)--简介与环境搭建
  5. ADF12C viewScope,pageFlowScope,requestScope,backingBeanScope
  6. 冈萨雷斯--数字图像处理(MATLAB版)----书籍相关网站
  7. HDU2044 一只小蜜蜂...【递推】
  8. Python pandas学习总结
  9. JS导出页面为PDF,分页导出
  10. 《高效的秘密》第五,六章读后感
  11. MQTT连接阿里云物联网平台步骤
  12. Robocup新手指南
  13. 如何用纯前端去写购物车_索尼商城购物车
  14. 客制化 GH60 XD60 像 Poker 一样的 60% 机械键盘 (2) 采购以及组装
  15. <<多模态预训练>>2022:CoCa: Contrastive Captioners are Image-Text Foundation Models
  16. Flutter: 把本地相册图片转换成Base64的方法
  17. 典雅大方实用中国风PPT模板
  18. python金融分析小知识(22)——时间序列之Timestamp对象的处理
  19. AdSense AdMob 游戏变现在线免费课堂
  20. keil查看rtx rtos堆栈溢出

热门文章

  1. IEC 61131 标准系列
  2. gn: toolchain
  3. 计算机网络实验教程金伟祖,基于PDCA循环的计算机网络实验教学改革
  4. 配置ouster雷达过程
  5. 如何安装红旗linux6.0声卡驱动
  6. 『信息安全技术』 标准系列合集(467个)
  7. ubuntu kylin 简单更新内置 firefox 记录(可使用安装包离线更新)
  8. 固定资产管理有关的计算机知识,固定资产管理相关知识问答梳理(无形资产篇)...
  9. PXE网刻教程 教如何制作自己的DOS网卡驱动
  10. apk逆向出来只有几百k的java_Android逆向之路---改apk包名、达到多开效果