day27(反射,动态代理,枚举,注解)
来源:互联网 发布:下载资源的软件 编辑:程序博客网 时间:2024/04/30 13:01
1.类的加载概述和加载时机
A:类的加载概述
- 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载
就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
* 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构
- 连接
- 验证 是否有正确的内部结构,并和其他类协调一致()
- 准备 负责为类的静态成员分配内存,并设置默认初始化值
- 解析 将类的二进制数据中的符号引用替换为直接引用
- 初始化 就是我们以前讲过的初始化步骤
B:加载时机
- 创建类的实例
- 访问类的静态变量,或者为静态变量赋值
- 调用类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
2.类加载器的概述和分类
A:类加载器的概述
- 负责将.class文件加载到内存中,并为之生成对应的Class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
- 犹如流机制一样
B:类加载器的分类
- Bootstrap ClassLoader 根类加载器
- Extension ClassLoader 扩展类加载器
- Sysetm ClassLoader 系统类加载器
C:类加载器的作用
- Bootstrap ClassLoader 根类加载器
- 也被称为引导类加载器,负责Java核心类的加载
- 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
- Bootstrap ClassLoader 根类加载器
- Extension ClassLoader 扩展类加载器
- 负责JRE的扩展目录中jar包的加载。
- 在JDK中JRE的lib目录下ext目录
- Sysetm ClassLoader 系统类加载器
- 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
3.反射概述
- JAVA反射机制是在运行状态中,对于任意一个类(不包含抽象类),都能够知道这个类的所有属性和方法;
- 对于任意一个对象,都能够调用它的任意一个方法和属性;
- 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 要想解剖一个类,必须先要获取到该类的字节码文件对象。
- 而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
4. 获取Class对象三种方式
- a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件
- b:静态属性class,锁对象
- c:Class类中静态方法forName(),读取配置文件
public class Temp1_load { public static void main(String[] args) throws ClassNotFoundException { Demo demo = new Demo(); Class class1 = Demo.class; //Object类封装了getClass()方法 Class class2 = demo.getClass(); Class class3 = Class.forName("com.to.note.Demo"); System.out.println(class1==class2); System.out.println(class2 == class3); }}class Demo{ public static int num = 1;}
5.Class.forName()读取配置文件
- 榨汁机(Juicer)榨汁的案例
- 分别有水果(Fruit)苹果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)
public class Temp_Properties { public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { BufferedReader bReader = new BufferedReader(new FileReader("config.properties")); String name = bReader.readLine(); Class<?> class1 = Class.forName(name); Fruit fruit = (Fruit) class1.newInstance(); Juicer juicer = new Juicer(); juicer.run(fruit); }}interface Fruit { public void squeeze();}class Apple implements Fruit { public void squeeze() { System.out.println("榨出一杯苹果汁儿"); }}class Orange implements Fruit { public void squeeze() { System.out.println("榨出一杯桔子汁儿"); }}class Juicer { public void run(Fruit f) { f.squeeze(); }}
6.反射
(1)通过反射获取带参构造方法并使用
- Constructor 类
- Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。
- Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance(“张三”,20)方法创建对象
public class Temp1_Constructor { public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<Person> class1 = Person.class; //获取单个构造方法(私有,公共) Constructor<Person> con1= class1.getDeclaredConstructor(String.class); Constructor<Person> con2 = class1.getConstructor(String.class,int.class); //获取构造函数修饰符 int test = con1.getModifiers(); System.out.println(Modifier.toString(test)); //获取构造方法的数组(公共,所有) Constructor[] cons1 = class1.getConstructors(); Constructor[] cons2 = class1.getDeclaredConstructors(); for (Constructor constructor : cons2) { System.out.println(constructor); } //创建对象 //公共 Person p1 = con2.newInstance("汪宝林",22); /* * 先用: public void setAccessible(boolean flag):flag的值为true则指示反射的对象在使用时应该取消 Java 语言访问检查。 * 再用: public T newInstance(Object... initargs) */ con1.setAccessible(true); Person p2 = con1.newInstance("向仕强"); System.out.println(p1); System.out.println(p2); }}class Person{ private String name; private int age; public Person() { } public Person(String name,int age){ this.name = name; this.age = age; } private Person(String name){ this.name = name; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; }}
(2)通过反射获取成员变量并使用
- Field 类
- Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
- Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField(“name”)方法获取,通过set(obj, “李四”)方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
public class Temp3_Field { public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Class<Student> class1 = Student.class; Field nameField = class1.getDeclaredField("name"); Student stu1 = new Student("汪寶林",24); Student stu2 = new Student("向世強"); //获取属性的修饰符 Field testfield = class1.getDeclaredField("test"); testfield.setAccessible(true); System.out.println(Modifier.toString(testfield.getModifiers())); //获取所有属性 Field[] fields = class1.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); System.out.println(field.get(stu1)); if("name".equals(field.getName())){ field.set(stu1, "小強"); System.out.println(field.get(stu1)); } } }}class Student{ private final static int test = 2; private String name; private int age; public Student() { } public Student(String name,int age){ this.name = name; this.age = age; } public Student(String name){ this.name = name; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; }}
(3)通过反射获取方法并使用
- Method
- Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
- Class.getMethod(String, Class…) 和 Class.getDeclaredMethod(String, Class…)方法可以获取类中的指定方法,调用invoke(Object, Object…)可以调用该方法,Class.getMethod(“eat”) invoke(obj) Class.getMethod(“eat”,int.class) invoke(obj,10)
public class Temp4_method { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<Demomethod> class1 = Demomethod.class; //获取所有公共方法 Method[] methods = class1.getMethods(); //获取单个方法,参数为(对象,方法形参的Class对象) Method method1 = class1.getDeclaredMethod("print"); Method method2 = class1.getMethod("print2",int.class); //执行方法,参数为(对象,方法形参) Demomethod demo = new Demomethod(); method1.invoke(demo); method2.invoke(demo, 10); System.out.println(class1.getName()+" "+class1.getSimpleName()); }}class Demomethod{ public void print(){ System.out.println("方法1"); } public void print2(int count){ for(int i=0;i<count;i++){ System.out.println(i); } }}
7.通过反射越过泛型检查
- A:案例演示
- ArrayList的一个对象,在这个集合中添加一个字符串数据,如何实现呢?
public class Temp5_skip { //ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢? //泛型只在编译检查时有效,运行时无效 public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List<Integer> list = new ArrayList<>(); list.add(4); list.add(45); list.add(7); System.out.println(list); Class<? extends List> cla= list.getClass(); //获取参数有泛型的方法 //第一种 Method m = cla.getMethod("add", Object.class); //第二种 Method[] methods = cla.getMethods(); Method me = null; for (Method method : methods) { if("add".equals(method.getName())){ me = method; } } //执行添加 me.invoke(list, "sd"); System.out.println(list); }}
8.通过反射写一个通用的设置某个对象的某个属性为指定的值
public class Temp6_setter2 { //* public void setProperty(Object obj, String propertyName, Object value){},此方法可将obj对象中名为propertyName的属性的值设置为value。 public static void main(String[] args) throws Exception { Stude stu = new Stude(); Temp6_setter2 set = new Temp6_setter2(); set.setProperty(stu, "name", "wbl"); System.out.println(stu); } public void setProperty(Object obj, String propertyName, Object value) throws Exception{ Class<?> class1 = obj.getClass(); Field field = class1.getDeclaredField(propertyName); field.setAccessible(true); field.set(obj, value); }}class Stude{ private String name; private int age; @Override public String toString() { return "Stude [name=" + name + ", age=" + age + "]"; }}
9.练习
public class Temp7 { /* * * 已知一个类,定义如下: * package com.uplooking.reflect; * public class DemoClass { public void run() { System.out.println("welcome to uplooking!"); } } * (1) 写一个Properties格式的配置文件,配置类的完整名称。 * (2) 写一个程序,读取这个Properties配置文件,获得类的完整名称并加载这个类,用反射的方式运行run方法。 */ public static void main(String[] args) throws Exception { BufferedReader brReader = new BufferedReader(new FileReader("temp7.properties")); String string = brReader.readLine(); brReader.close(); Class class1 = Class.forName(string); Method method = class1.getMethod("run"); method.invoke(class1.newInstance()); }}class DemoClass { public void run() { System.out.println("welcome to uplooking!"); }}
10.动态代理的概述和实现
A:动态代理概述
- 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。
- 举例:春节回家买票让人代买
动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
- public static Object newProxyInstance(ClassLoader loader,Class
public interface RentHouse { //定义总接口 void rent();}public class Fangdong implements RentHouse{ //定义具体实现类 @Override public void rent() { System.out.println("租房子"); }}public class MyInvocationHandler implements InvocationHandler{ //创建实现InvocationHandler接口的代理类 private Object obj; public MyInvocationHandler(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method.invoke(obj, args); return null; }}public class ProxyTest { //创建测试类 public static void main(String[] args) { RentHouse rentHouse = new Fangdong(); InvocationHandler myInvoc = new MyInvocationHandler(rentHouse); RentHouse rentHouse2 = (RentHouse) Proxy.newProxyInstance(rentHouse.getClass().getClassLoader(), rentHouse.getClass().getInterfaces(),myInvoc); System.out.println(rentHouse2); rentHouse2.rent(); }}
11.模版(Template)设计模式概述和使用
- A:模版设计模式概述
- 模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现
- B:优点和缺点
- a:优点
- 使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求
- b:缺点
- 如果算法骨架有修改的话,则需要修改抽象类
- a:优点
public abstract class Temp8_Template { //模板 //求run()方法的执行时间 public long getRuntime(){ long start = System.currentTimeMillis(); run(); long end = System.currentTimeMillis(); return end-start; } public abstract void run();}public class Temp8_Template_Test extends Temp8_Template{ //子类 @Override public void run() { for (int i = 0; i < 1000000; i++) { i = i*5/5*5/5; } } public static void main(String[] args) { Temp8_Template_Test test = new Temp8_Template_Test(); long time = test.getRuntime(); System.out.println(time); }}
12.枚举类
- A:枚举概述
- 是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天,一年只有12个月等。
- B:回想单例设计模式:单例类是一个类只有一个实例
- 那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类。
13.使用场景
- a.常量的使用
//枚举类enum Color { RED, GREEN, BLANK;}public class Temp9_enum { public static void main(String[] args) { //switch 的使用 isColor(Color.RED); } public static void isColor(Color color){ switch (color) { case RED: System.out.println("红色"); break; case GREEN: System.out.println("绿色"); break; case BLANK: System.out.println("黑色"); break; default: break; } }}
- b.自定义函数
enum Color2 { RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); private String name ; private int index ; private Color2( String name , int index){ this.name = name ; this.index = index ; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } }public class Temp10_enum { public static void main(String[] args) { //遍历所有枚举类 for(Color2 color : Color2.values()){ System.out.println(color.getIndex()+" "+color.getName()); } }}
14.枚举的注意事项
* 定义枚举类要用关键字enum* 所有枚举类都是Enum的子类* 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略* 枚举类可以有构造器,但必须是private的,它默认的也是private的。* 枚举类也可以有抽象方法,但是枚举项必须重写该方法* 枚举在switch语句中的使用
15.枚举类的常见方法
16.JDK7的六个新特性回顾和讲解
- A:二进制字面量
- B:数字字面量可以出现下划线
- C:switch 语句可以用字符串
- D:泛型简化,菱形泛型
- E:异常的多个catch合并,每个异常用或|
- F:try-with-resources 语句
17.JDK8的新特性
18.注解
- 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
- 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
- 包含在 java.lang.annotation 包中。
19.元注解
元注解的作用就是负责注解其他注解。
- @Target
- @Retention
- @Documented
- @Inherited
@Target
- 说明了Annotation所修饰的对象范围
ElementType有:
1.CONSTRUCTOR:用于描述构造器(常用)2.FIELD:用于描述域(常用)3.LOCAL_VARIABLE:用于描述局部变量4.METHOD:用于描述方法(常用)5.PACKAGE:用于描述包6.PARAMETER:用于描述参数7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention
- 定义了该Annotation被保留的时间长短
- 表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)2.CLASS:在class文件中有效(即class保留)3.RUNTIME:在运行时有效(即运行时保留)
@Documented
- 用于描述其它类型的annotation应该被作为被标注的程序成员的公共API
- 因此可以被例如javadoc此类的工具文档化
@Inherited
- @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
- 如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
20.自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。
- 其中的每一个方法实际上是声明了一个配置参数,方法的名称就是参数的名称,返回值类型就是参数的类型
阅读全文
0 0
- day27(反射,动态代理,枚举,注解)
- Day27-基础加强(注解Annotation、动态代理)
- 注解、动态代理、反射文章
- Java基础加强_Eclipse、枚举、反射、注解、泛型、类加载器、动态代理
- 注解、动态代理与反射的应用
- JDK1.5之可变参数枚举反射内省动态代理
- 代理,动态代理,反射
- 代理,动态代理,反射
- Android框架常用java基础知识:反射,注解,动态代理
- 【反射+注解+动态代理在事务中的应用service层】
- 黑马程序员-day27反射
- 反射,注解,泛型,代理
- 反射与动态代理
- 反射动态代理
- 反射机制动态代理
- 反射、动态代理原理
- 动态代理反射
- 反射和动态代理
- Web中的无状态含义
- 使用spring-restdocs 自动生成接口文档
- js基础-1
- HDU1811---Rank of Tetris (拓扑排序+并查集(好题))
- 使用node.js快速搭建简易本地HTTP服务
- day27(反射,动态代理,枚举,注解)
- Ubuntu16.04(64位)下面使用Doxygen+Graphviz分析python代码
- Excel VBA数据导出
- 扫描配置文件(二)Java 读写Properties配置文件
- ArrayList的线程不安全问题
- UVA10325(容斥定理)
- 字符流中第一个不重复的字符
- bzoj 1600: [Usaco2008 Oct]建造栅栏(DP)
- Deep Learing 7.1-7.7 笔记