注解
1.什么是注解?
- Annotation 的作用
- 不是程序本身,可以对程序作出解释。
- 可以被其他程序读取
Annotation的格式:
- 注解是以“@注释名”在代码中存在的,还可以添加一些参数值;例如:@SuppressWarnings(value = “unchecked”)
Annotation在哪里使用?
- 可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问
1 | package com.polly.annotation; |
@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。编译器在不被弃用的代码中使用或覆盖不推荐使用的程序元素时发出警告。
@SuppressWarnings表示在注释元素(以及注释元素中包含的所有程序元素)中应该抑制命名的编译器警告。
2. 内置注解
3.元注解
1 | package com.polly.annotation; |
3.自定义注解
1 | package com.polly.annotation; |
反射
1.反射概述
1 | package com.polly.reflection; |
2.得到Class类的几种方式
1 | package com.polly.reflection; |
3.哪些类型可以有Class对象
1 | package com.polly.reflection; |
4.类加载内存分析
1 | package com.polly.reflection; |
1 | package com.polly.reflection; |
5.类加载器
1 | package com.polly.reflection; |
6.获得类的运行时结构
1 | package com.polly.reflection; |
7.动态创建对象执行方法
1 | package com.polly.reflection; |
性能分析:
1 | package com.polly.reflection; |
8.获取泛型信息
1 | package com.polly.reflection; |
9.获取注解信息
1 | package com.polly.reflection; |
反射应用案例
原本的这两个都有问题;
1. 反射与工厂设计模式
工厂类每有一个子类都要写一个工厂类,这样的工厂类不能重复使用。所以我们使用反射中的Class.forName("包.类")
,再用newInstance
方法获得;进一步的可以使用泛型,通过传入想要的类的Class
是的这个工厂类天下通行;
2. 反射与单例设计模式
单例设计模式是饿汉式的;
- 构造方法私有化,只有一个static方法
- 但在多线程下,同时获取这种单例的实例化对象就可能出现多个对象;所以在这里使用
synchronic
关键字同步构造方法的结构,再用volate关键字使得私有的类属性(本类的对象索引属性)直接使用内存中的,而不是副本;
反射与类操作
1. 获取类结果信息
获取类:四种
3. 反射调用普通方法
获取方法:四种
然后再通过反射获取方法的结构;
最重要的方法:invoke
4. 反射调用属性
获取成员
Field类中的方法
- 设置属性内容: set
获取属性内容:get
解除封装:setAccessible;
5. Unsafe工具类
Unsafe
的获取过程需要反射:
因为它构造方法私有化,类属性有一个static unsafe
类型的也是私有化的。但是不是单例设计模式那种。所以就是一个完全封闭的类。要进去就得开上帝视角,也就是解除封装获取那个属性就好了。
他能绕过实例化的管理。
然后利用这个实例化对象里的:allocateInstance
方法给别的单例设计模式弄一个实例化对象;并未这种方式不调用构造方法;
反射与简单Java类
1. 传统属性赋值弊端
属性太多时,类里的方法大部分都是setter和getter;本质上他们都是重复的;可以用反射来解决这个问题
2. 属性自动赋值的实现思路
要给一个类传属性的值。要通过反射的方式。这里就是在主方法获得class对象然后得到很多相应的信息。这里讲的东西把反射的过程集成到一个ClassInstanceFactory
类里。希望它是一个万能的东西:接受反射对象和属性内容并获取指定类的实例化对象;
3. 设置各种数据类型
在这里实现了所有可能出现的类型;包括:Long,int,double,Date
4. 级联对象实例化
也就是各种类相互融合在了一起;比如部门属于一个公司,部门类里就有公司属性,公司类里就有部门属性。然后公司类,部门类里也都有name属性;
外部获取时也就是:getDept().getDname()
,getDept().getCompany().setName("sdsf")
;
而这里级联里可能就写很长,如果其中一个对象的实例化得不到。那么就影响整个代码运行。所以这里他想要自动实现对象实例化
级联对象一般都用“.”来取。以这个为判断;
5. 级联属性赋值
ClassLoader类加载器
1. 类加载器简介
java提供了一个环境变量:CLASSPATH
,这个环境变量的作用主要在JVM进程启动的时候进行类加载路径的定义;
Class类是反射的根源:他里面有一个getClassLoader
方法
获得类加载器,就可以实现类的反射加载处理:
2. 自定义类加载器
自定义加载器是在所有加载器之后;之前他们都得用classPath
,有了自定义加载器就可以在系统内任意位置都可以进行加载;
写了一个简单类,放在D盘路径上不打包:
javac Message.java
,并且不打包(使得classpath无法加载)。自定义一个类加载器,并继承自classLoader类:
1
2
3
4
5
6
7public class<?> loadData(String className) throws Exception{
byte [] data = this.loadClassData; // 读来的二进制数据文件
if (data != null){
return super.dafindClass(className, data, 0, data.length); // 重要的一步
}
return null;
}在这里获取的Class对象就可以用Class里面的方法实例化,实现后续操作
java提供了双亲加载机制:系统类有由系统加载器加载。自定义的加载器不能够加载;自定义类才可以有自定义加载器加载;
反射与代理设计模式
1. 静态代理设计模式
代理设计模式必须要有一个接口,接着实现;
传统设计模式弊端:客户端和接口子类产生了耦合问题,最好再引入工厂设计模式
一个代理类,只为一个接口服务;这里想要一个代理类,满足所有的业务接口
2. 代理设计模式
- 不管是真实代理类还是静态代理类都一定要接收真实业务实现子类对象;
- 由于动态代理类不再与某一个具体的接口进行捆绑应该可以动态获取类的接口;
这里要用到一个invocationHandle
的接口来处理,他有一个invoke
方法
还有
1 | public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) |
3. CGLIB实现代理设计
可以实现基于类的代理设计模式。不再与接口联系