文章目录
一、静态代理
静态代理角色分析
- 抽象角色 : 一般使用接口或者抽象类来实现
- 真实角色 : 被代理的角色
- 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
- 客户 : 使用代理角色来进行一些操作 .
在spring-study的第八个模块中有实现代码。模拟租房,房东。中介。客户。
Rent接口
package com.zyl.demo01;
public interface Rent {
public void rent();
}
Host类
package com.zyl.demo01;
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东租房");
}
}
Proxy类
注意:构造函数不带返回值,防止子类的构造函数有返回值。
package com.zyl.demo01;
public class Proxy implements Rent{
private Host host;
//构造函数不能写返回值
public Proxy(){}
public Proxy(Host host){
seeHouse();
this.host=host;
}
@Override
public void rent() {
host.rent();
}
private void seeHouse(){
System.out.println("看房子");
}
}
Client类
package com.zyl.demo01;
public class Client {
public static void main(String[] args) {
// Host host=new Host();
// host.rent();
//房东要租房
Host host=new Host();
//代理,中介帮房东租房子,会有一些别的功能
Proxy proxy=new Proxy(host);
proxy.rent();
}
}
静态代理的好处
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
缺点 :
每一个真实角色需要一个代理类,代码量变高
我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !
静态代理的小练习
现在实现一个增删改查的功能
接口
package com.zyl.demo02;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
实现类
package com.zyl.demo02;
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
@Override
public void query() {
System.out.println("查询一个用户");
}
}
Client类
package com.zyl.demo02;
public class Client {
public static void main(String[] args) {
UserService userService=new UserServiceImpl();
userService.add();
}
}
这样就可以跑了。但是我们现在需要在增删改查的功能增加日志功能。
改动源代码是大忌,所以我们增加一个代理类
Proxy类
package com.zyl.demo02;
public class Proxy implements UserService{
private UserService userService;
public void setUserService(UserService userService){
this.userService=userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
private void log(String str){
System.out.println("执行了"+str+"方法");
}
}
在Client类里面使用代理类
package com.zyl.demo02;
public class Client {
public static void main(String[] args) {
// UserService userService=new UserServiceImpl();
// userService.add();
UserService userService=new UserServiceImpl();
Proxy proxy=new Proxy();
proxy.setUserService(userService);
proxy.add();
}
}
二、动态代理
动态代理的Proxy类是动态生成的。
静态代理的缺点:每一个真实角色对应一个代理角色,代码量翻倍。
Proxy类
invocationHandler
Rent接口
//抽象角色:租房
public interface Rent {
public void rent();
}
真实对象
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
生成代理类的
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client类
//租客
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host); //将真实角色放置进去!
Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
proxy.rent();
}
}
总结
//这个可以当做一个工具类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的真实类
private Object target;
public void setTarget(Object target) {
this.target=target;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//核心:本质利用反射实现!
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
三、注解(Annotation)
3.1 内置注解
3.2 元注解
元注解也是注解,他负责注解其他注解
3.3 自定义注解
四、反射
静态语言&动态语言
4.1 得到Class类的几种方法
package com.zyl.reflection;
import java.nio.channels.ClosedSelectorException;
public class 测试Class类的创建方式有哪些 {
public static void main(String[] args) throws ClassNotFoundException {
Person person=new Student();
System.out.println("这个人是一个"+person.name);
//方式一,通过对象获得
Class c1=person.getClass();
System.out.println(c1.hashCode());
//方式二,forName获得
Class c2=Class.forName("com.zyl.reflection.Student");
System.out.println(c2.hashCode());
//方式三.通过类名.class获得
Class c3=Student.class;
System.out.println(c3.hashCode());
//方式四.基本内置类型的包装类都有一个TYPE属性
Class c4=Integer.TYPE;
System.out.println(c4);
//获取父类对象
Class c5=c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
public String name;
public Person(){}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name="学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name="老师";
}
}
4.2 哪些类型可以有Class对象
public class 所有类型的Class {
public static void main(String[] args) {
Class c1=Object.class;
Class c2=Comparable.class;
Class c3=String[].class;
Class c4=int[][].class;
Class c5=Override.class;
Class c6=void.class;
Class c7=Class.class;
Class c8=Integer.class;
Class c9= ElementType.class;
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
System.out.println("===========");
//只要元素类型和维度一样,就是同一个Class
int[] a=new int[10];
int[] b=new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
4.3 类加载内存分析
Class对象存在堆里面,每个类只有一个。
package com.zyl.reflection;
public class 类加载演示 {
public static void main(String[] args) {
A a=new A();
System.out.println(A.m);
}
}
class A{
static int m=100; //我这里 m=100放在静态代码块前面和后面结果是不一样的
static{
System.out.println("A静态代码块执行");
m=300;
}
public A(){
System.out.println("A的无参构造函数");
}
}
clinit方法是编译器自动收集所有类变量的赋值动作和静态代码块中的语句产生的
我m=100的赋值语句在静态代码块前面的话结果就不同了
4.4 什么时候会发生类的初始化
public class 类加载的时机 {
static {
System.out.println("Main被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//1.主动引用
//Son son=new Son();
//反射调用
//Class.forName("com.zyl.reflection.Son");
//不会导致类初始化的情况
//System.out.println(Son.a);
//通过数组定义类引用
//Son[] arr=new Son[5];
//引用常量池里面的常量
System.out.println(Son.s);
}
}
class Father{
static {
System.out.println("父类加载");
}
static int a=1;
static final int s=10;
}
class Son extends Father{
static {
System.out.println("子类被加载");
m=200;
}
static int m=100;
}
4.5 类加载器
4.6 获取运行时类的结构
属性,方法,构造器
返回在哪个包下
public class 获取类的运行时结构 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1=Class.forName("com.zyl.reflection.User");
//获取类的名字
System.out.println(c1.getName()); //包名+类名
System.out.println(c1.getSimpleName()); //只有类名
System.out.println("=============");
//获取类的属性
Field[] fields=c1.getFields(); //只能获取public的属性
for(Field field:fields){
System.out.println(field);
}
fields=c1.getDeclaredFields(); //获取所有的属性
for(Field field:fields){
System.out.println(field);
}
//获取指定属性的值
System.out.println(c1.getDeclaredField("name"));
System.out.println("==========");
//获取类的方法
Method[] methods=c1.getMethods(); //获取本类以及父类的所有public方法
for(Method method:methods){
System.out.println(method);
}
System.out.println("==========");
methods=c1.getDeclaredMethods(); //获取本类的所有方法
for(Method method:methods){
System.out.println(method);
}
System.out.println("===============");
//获取指定方法
Method method2=c1.getMethod("getName",null);
System.out.println(method2);
Method method3=c1.getMethod("setName", String.class); //因为重载的原因,所有我们也需要传参数类型来确认是哪个方法
System.out.println(method3);
System.out.println("============");
//获取构造器
Constructor[] constructors=c1.getConstructors();
for(Constructor constructor:constructors){
System.out.println(constructor);
}
constructors=c1.getDeclaredConstructors();
for(Constructor constructor:constructors){
System.out.println("#"+constructor);
}
//获得指定的构造器
Constructor constructor2=c1.getConstructor(String.class,int.class,int.class);
System.out.println(constructor2);
}
}
4.7 动态创建对象执行方法
反射调用多的话,可以关闭安全检测
public class 通过反射动态创建对象 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获取Class对象
Class c1=Class.forName("com.zyl.reflection.User");
//创建一个对象
User user=(User) c1.newInstance();//本质是调用了类的无参构造器,并且构造器的权限要够
System.out.println(user);
//通过构造器创建对象
Constructor constructor=c1.getDeclaredConstructor(String.class,int.class,int.class);
User user1=(User) constructor.newInstance("zyl",22,100);
System.out.println(user1);
System.out.println("==============");
//通过反射调用普通方法
User user2=(User) c1.newInstance();
Method method=c1.getDeclaredMethod("setName", String.class);
//invoke 激活
//(对象,方法的参数)
method.invoke(user2,"zyl");
Method method1=c1.getDeclaredMethod("getName",null);
String s=(String) method1.invoke(user2,null);
System.out.println(s);
System.out.println("====================");
//通过反射操作属性
User user3=(User) c1.newInstance();
Field name=c1.getDeclaredField("name");
//不能直接操作私有属性,关闭程序的安全检测,将属性或方法name.setAccessible(true)
name.setAccessible(true);
name.set(user3,"zyl1");
String str=(String) name.get(user3);
System.out.println(str);
}
}
4.8 获取泛型信息
public class 通过反射获取泛型 {
public void test01(Map<String,User> map, List<User> list){
System.out.println("test01");
}
public Map<String,User> test02(){
System.out.println("test02");
return new HashMap<>();
}
public static void main(String[] args) throws NoSuchMethodException {
Method method=通过反射获取泛型.class.getMethod("test01", Map.class, List.class);
Type[] types=method.getGenericParameterTypes();
for (Type type : types) {
System.out.println("#"+type);
if(type instanceof ParameterizedType){
Type[] actualType=((ParameterizedType) type).getActualTypeArguments();
for (Type type1 : actualType) {
System.out.println(type1);
}
}
}
System.out.println("=====================");
Method method1=通过反射获取泛型.class.getDeclaredMethod("test02",null);
Type type=method1.getGenericReturnType();
if(type instanceof ParameterizedType){
Type[] actualType=((ParameterizedType) type).getActualTypeArguments();
for (Type type1 : actualType) {
System.out.println(type1);
}
}
}
}