类加载:
1.在编译后的类会成为字节码文件.class,.class文件里有类的所有信息(包括成员变量,构造函数,成员方法)
2.当运行到创建类的实例时jvm就会加载该类的.class文件称为类的加载。
3.将成员方法,成员变量,构造方法都存储在Class对象里,Class对象存储在方法区中。
类加载时机:
1.创建实例
2.调用静态方法。
3.使用类的静态变量。
4.通过反射创建类的对象。
5.初始化类的子类。
反射:
作用:通过反射机制获得类的构造方法,成员变量,成员方法。
在字节码的情况下加载类再Class对象获得类相关的信息。
获取Class对象:
有一个Person类:
public class Person {
public String name;
public int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(int age) {
this.age = age;
}
public void show1() {
System.out.println("show1 方法...");
}
public void show2(int num) {
System.out.println("show2 方法...num: " + num);
}
public int show3(int num) {
System.out.println("show3 方法...num: " + num);
return 1000;
}
private void show4(String str) {
System.out.println("show4 方法...str: " + str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
获取Class对象:
1.Class <Person> c1=Person.class;//类名直接得到
2.Class<?extends Person> c2=new Person().getClass;//对象得到
3.Class<?> c3=Class.forName(Person);//Class的静态方法
Class类常用方法:
首先先得到一个Class对象:Class <Person> c = Person.class;
1.获得类名: c.getSimpleName;//person
2.获得全类名: c.getName();//包名.类名
3.创建该类的对象 : Person p=c.newInstance();//创建了Person对象,该方法过时。
反射获取构造方法:
首先获取Person类的Class对象:Class <Person> c = Person.class; //c就有了Person类的一切成员。
获取指定构造方法:
Constructor <Person> Con1=c.getDeclaredConstructor();//无参构造
Constructor <Person> Con2=c.getDeclaredConstructor(String.class, int.class);//有参构造
获取所有构造方法:
Constructor<?>[] arr =c.getDeclaredConstructors();
Consturcotr对象的常用方法:
反射执行构造方法创建对象
Person p1 = con1.newInstance();
反射获取成员方法:
反射获取指定成员方法://指定方法名和参数的Class对象
Method m1=c.getDeclaredMethod("show1");
Method m2=c.getDeclaredMethod("show2",int.class);
Method m3=c.getDeclaredMethod("show3",int.class);
Method m4=c.getDeclaredMethod("show4",String.class);
反射获取所有成员方法:
Method<?> [] arr=c.getDeclaredMethods();
Method对象的常用方法:
执行方法:invock(Object o,Object...args);//参数1表示执行方法的对象,参数2是方法的参数列表。
首先通过反射创建对象 Person p= c.newInstance();
m1.invock(p);//援引
m2.invock(p,1);
m3.invock(p,100);
m4.invock(p,"hello");
反射获得成员变量:
获取指定成员变量
Field f1=c.getDeclaredField("name");//获得声明字段
Field f2=c.getDeclaredField("age");
获取所有成员变量
Field[] f=c.getDeclaredFields();
Field对象的常用方法:
set(Object obj ,Object value);//给变量赋值
get(Objcet obj);//获取变量的值
首先反射创建对象 Person p =c.newInstance();//新实例
f1.set(p,"疾风剑豪");
f2.set(p,10);
Object name=f1.get(p);//获取疾风剑豪
反射获取注解
首先自定义一个注解类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
String name();
int age();
}
public class Test {
@MyAnnotation1
String name ;
int age;
@MyAnnotation1(name="张三",age=18)
public void show1(){
System.out.println("show1方法执行了....");
}
public void show2(){
System.out.println("show2方法执行了....");
}
}
首先得到person的Class对象:
Class <Test> c=Class.forName("包名+Test");
1.获得类上的注解:
//Target Retention 都是注解名
Target t=c.getAnnotation(Target.class);
Retention r=c.getAnnotation(Retention.class);
判断方法上是否有该名字的注解:
boolean res = c.isAnnotationPresent(Target.class);
2.获得方法上的注解:
Method m1=c.getDeclaredMethod("show1");
调用方法获得注解://MyAnnotation1是注解名
MyAnnotation1 a1=m1.getAnnotation(MyAnnotation1.class);
获得注解的属性值:
a1.Name(); a1.age();
判断方法上是否有该名字的注解:
boolean res1 = m1.isAnnotationPresent(MyAnnotation1.class);
3.获得变量上的注解:
Field f1=c.getDeclaredField("name");
f1.getAnnotation(MyAnnotation1.class);
总结:
1.反射将类里的所有变量,方法都视为对象。
2.是对象就会有api
3.如果main方法操作对象是正向,那么反射机制操作就是反向。
4.编译,类加载,类入方法区,对象调用方法。正向)
反射机制更像是用代码操作虚拟机,主动去获得类的成员,将类的构造解剖成一个个对象。单独执行。
代理模式定义:
被代理对象没有做某个方法的能力,要代理对象帮忙做,增强方法。所以代理模式包含了三个角色:被代理对象,代理对象,还有一个标准协议(接口)。
接口,被代理类和代理类:(类似装饰者模式)
1.接口定义了规范,代理类与被代理类都实现相同的接口。
2.被代理类实现接口中的方法。
3.代理类成员变量有被代理类的引用,实现接口中的方法。方法里调用被代理的方法再增强方法。
静态代理:
public interface FindHappy {
void happy();
}
public class JinLian implements Happy {
public void happy(){
System.out.println("金莲在happy...");
}
}
public class WangPo implements Happy{
// 成员变量
JinLian jl;
// 构造方法
public WangPo(JinLian jl) {
this.jl = jl;
}
// 成员方法
@Override
public void happy() {
System.out.println("王婆以做衣服的名义开好房间,并把2人约到房间里...");
// 金莲happy
jl.happy();
System.out.println("王婆打扫战场...");
}
}
public class XiMen {
public static void main(String[] args) {
/*
案例: 金莲要找西门happy
代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者,
所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)
*/
// 不请代理: 金莲直接找西门happy
// 创建金莲对象
JinLian jl = new JinLian();
// happy
// jl.happy();
// 请代理: 静态代理,代理类真实存在
Happy wp = new WangPo(jl);// wp:代理对象 WangPo类: 代理类 Happy接口: 协议 JinLian: 被代理类
wp.happy();
}
}
动态代理:
概述:动态代理通过反射生成的代理对象,代理对象所属的类是不存在的。
Proxy对象调用api直接生成一个代理对象。
Proxy类api:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
1.第一个参数:被代理类加载器。加载代理类。
2.第二个参数:被代理类接口的Class对象。
3.第三个参数:接口,执行处理类。
前2个参数是为了帮助在jvm内部生成被代理对象的代理对象,第3个参数,用来监听代理对象调用方法,帮助我们调用方法。
此时代理对象就生成了,有
InvocationHandler(接口)中的invoke()方法,回调函数,监听代理对象执行方法。**调用代理类的任何方法,此方法都会执行**
Object invoke(Object proxy, Method method, Object[] args)方法(抽象方法,用匿名内部类方式实现方法):
- 参数1:代理对象
- 参数2:当前执行的方法
- 参数3:当前执行的方法运行时传递过来的参数
- 返回值:当前方法执行的返回值
public interface Happy {// 协议,被代理者需要代理的方法,就定义在这里,然后让代理者和被代理者去实现
// 被代理者实现: 为了确保和代理者实现的方法一致
// 代理者实现: 为了增强被代理者的这些方法
public abstract void happy();
}
public class JinLian implements Happy {
public void happy(){
System.out.println("金莲在happy...");
}
}
public class Test {
public static void main(String[] args) {
/*
Proxy类可以直接生成一个代理对象
- static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
- 参数1:ClassLoader loader 被代理对象的类加载器
- 参数2:Class<?>[] interfaces 被代理对象的要实现的接口
- 参数3:InvocationHandler h (接口)执行处理类
- 返回值: 代理对象
- 前2个参数是为了帮助在jvm内部生成被代理对象的代理对象,第3个参数,用来监听代理对象调用方法,帮助我们调用方法
- InvocationHandler中的Object invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行
- 参数1:代理对象(慎用)
- 参数2:当前执行的方法
- 参数3:当前执行的方法运行时传递过来的参数
- 返回值:当前方法执行的返回值
*/
// 创建金莲对象
JinLian jl = new JinLian();
// 看不到代理类,直接就动态生成一个代理对象
// 得到被代理对象的类加载器
ClassLoader cLoader = JinLian.class.getClassLoader();
// 被代理对象的要实现的接口
Class<?>[] arr = JinLian.class.getInterfaces();
// 确定:返回的代理对象一定实现了接口
FindHappy proxy = (FindHappy)Proxy.newProxyInstance(cLoader, arr, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 当代理对象调用方法,就会来到这里执行代码
// 参数1:返回的代理对象,一般不用
// 参数2:代理对象调用的方法
// 参数3:代理对象调用的方法传入的实际参数
// 返回值:代理对象调用的方法需要的返回值
System.out.println("王婆以做衣服的名义把房间开好...");
// 金莲调用happy方法
method.invoke(jl);//jl是被代理类在代理类的//因为代理类实现被代理类的所有接口,所以不管是谁都可以调用。
System.out.println("王婆打扫战场...");
return null;
}
});
System.out.println(1);
// 代理对象调用方法。
proxy.happy();
System.out.println(2);
}
}
对Collection接口进行代理,以前的remove(Object obj)方法是删除集合中第一次出现的元素(比如集合中有多个“abc”,调用remove(“abc”)后只会删除一个元素)。代理后,要求在调用remove(Object obj)方法后,能够删除集合中所有匹配的元素。【动态代理】
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* @Author:ZZZ
* @Date: 2020/11/30 14:50
* @Version 1.0
*/
//对Collection接口进行代理,以前的remove(Object obj)方法是删除集合中第一次出现的元素
// (比如集合中有多个“abc”,调用remove(“abc”)后只会删除一个元素)。代理后,要求在调用remove(Object obj)方法后,能够删除集合中所有匹配的元素。
// 【动态代理】
public class 动态代理 {
public static void main(String[] args) {
//被代理
List<String > list=new ArrayList<>();
list.add("aba");
list.add("nba");
list.add("nba");
list.add("nab");
list.add("nba");
list.add("cba");
System.out.println("之前");
System.out.println(list);
ClassLoader listclassLoader = list.getClass().getClassLoader();
Class<?>[] interfaces = list.getClass().getInterfaces();
Collection o = (Collection) Proxy.newProxyInstance(listclassLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equalsIgnoreCase("remove")){
// for (String s : list) {
// if(s.equals(args[0])){
// list.remove(args[0]);//错误1:for语句不能remove,迭代器可以remove
// }
// }
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if(next.equals(args[0])){
// list.remove(args[0]);//错误2:不是list.remove,是iterator.remove();
iterator.remove();
}
}
}
// return null;//错误3:这个是代理对象调用的方法的返回值。调用的是remove方法,返回值是true或false
return true;
}
});
o.remove("nba");
System.out.println("之后");
System.out.println(list);
}
}