当前位置: 首页>編程日記>正文

反射、注解、字节码、类加载机制

反射、注解、字节码、类加载机制

注解(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运行和类加载全过程


https://www.fengoutiyan.com/post/16301.html

相关文章:

  • 反射加入注解
  • 反射获取注解属性值
  • 注解与反射
  • java反射有什么用
  • Java反射原理
  • 腱反射的产生机制
  • 反射机制原理
  • java反射和注解原理
  • 鏡像模式如何設置在哪,圖片鏡像操作
  • 什么軟件可以把圖片鏡像翻轉,C#圖片處理 解決左右鏡像相反(旋轉圖片)
  • 手機照片鏡像翻轉,C#圖像鏡像
  • 視頻鏡像翻轉軟件,python圖片鏡像翻轉_python中鏡像實現方法
  • 什么軟件可以把圖片鏡像翻轉,利用PS實現圖片的鏡像處理
  • 照片鏡像翻轉app,java實現圖片鏡像翻轉
  • 什么軟件可以把圖片鏡像翻轉,python圖片鏡像翻轉_python圖像處理之鏡像實現方法
  • matlab下載,matlab如何鏡像處理圖片,matlab實現圖像鏡像
  • 圖片鏡像翻轉,MATLAB:鏡像圖片
  • 鏡像翻轉圖片的軟件,圖像處理:實現圖片鏡像(基于python)
  • canvas可畫,JavaScript - canvas - 鏡像圖片
  • 圖片鏡像翻轉,UGUI優化:使用鏡像圖片
  • Codeforces,CodeForces 1253C
  • MySQL下載安裝,Mysql ERROR: 1253 解決方法
  • 勝利大逃亡英雄逃亡方案,HDU - 1253 勝利大逃亡 BFS
  • 大一c語言期末考試試題及答案匯總,電大計算機C語言1253,1253《C語言程序設計》電大期末精彩試題及其問題詳解
  • lu求解線性方程組,P1253 [yLOI2018] 扶蘇的問題 (線段樹)
  • c語言程序設計基礎題庫,1253號C語言程序設計試題,2016年1月試卷號1253C語言程序設計A.pdf
  • 信奧賽一本通官網,【信奧賽一本通】1253:抓住那頭牛(詳細代碼)
  • c語言程序設計1253,1253c語言程序設計a(2010年1月)
  • 勝利大逃亡英雄逃亡方案,BFS——1253 勝利大逃亡
  • 直流電壓測量模塊,IM1253B交直流電能計量模塊(艾銳達光電)
  • c語言程序設計第三版課后答案,【渝粵題庫】國家開放大學2021春1253C語言程序設計答案
  • 18轉換為二進制,1253. 將數字轉換為16進制
  • light-emitting diode,LightOJ-1253 Misere Nim
  • masterroyale魔改版,1253 Dungeon Master
  • codeformer官網中文版,codeforces.1253 B
  • c語言程序設計考研真題及答案,2020C語言程序設計1253,1253計算機科學與技術專業C語言程序設計A科目2020年09月國家開 放大學(中央廣播電視大學)
  • c語言程序設計基礎題庫,1253本科2016c語言程序設計試題,1253電大《C語言程序設計A》試題和答案200901
  • 肇事逃逸車輛無法聯系到車主怎么辦,1253尋找肇事司機