重点!java反射技术,动态代理AOP理念
文章目录
1.反射之前对于创建一个类的对象的操作
我们以一个Person类举例,我把Person粘贴在下面
public class Person {
private String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
System.out.println("p");
}
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 +
'}';
}
public void show(){
System.out.println("你好,我是一个人");
}
private String showNation(String nation){
System.out.println("我的国籍是"+nation);
return nation;
}
}
反射之前对于Person类的操作
//反射之前对于Person类的操作
@Test
public void test1(){
Person person = new Person("Tom",12);
person.age=10;
System.out.println(person);
person.show();
//在person类的外部,不可以通过其person类对象调用其内部的私有结构
//比如:私有属性,私有方法,私有构造器
}
2.Class类的理解,以及获取Class实例的方式
Class类的理解
1.类的加载过程:
程序经过javac.exe 生成一个或者多个字节码文件(.class结尾),java.exe 对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,此过程称为类的加载。加载到内存中的类,我们称为运行时类,就充当了一个Class类的实例。
类也是对象,万事万物皆对象 哈哈哈
2.换句话说,Class的实例就对应着一个运行时类
3.我们加载到内存中的运行时类会缓存一定的时间,在此时间之内我们可以通过不同的方式,来获取运行时类
获取Class实例的方式(前三种方式需要掌握)
@Test
public void test3() throws ClassNotFoundException {
//方式一:调用运行时类的属性
Class clazz1=Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象进行获取,调用getClass方法
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用Class静态方法,类的全路径
Class clazz3 = Class.forName("reflectionTest.test.Person");
System.out.println(clazz3);
System.out.println(clazz1==clazz2);
System.out.println(clazz1==clazz3);
//方式四:使用类的加载器ClassLoder
ClassLoader classLoader = Reflection.class.getClassLoader();
Class clazz4 = classLoader.loadClass("reflectionTest.test.Person");
System.out.println(clazz4);
System.out.println(clazz1==clazz4);
}
3.使用反射做1同样的操作创建对象并操作
//使用反射,做上方同样的操作
@Test
public void test2() throws Exception, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.通过反射,创建Person类的对象
/*
这个方法是通过使用指定的构造器来创建对象
如果使用clazz.newInstance()来创建对象,那么默认使用的就是空参的构造器
所以这个时候就体现出了为什么JavaBean要求一定要有空参构造器,以及我们在造
类的时候造空参构造器的必要性。
*/
Class clazz = Person.class;
Constructor cons=clazz.getConstructor(String.class,int.class);
Person person=(Person) cons.newInstance("Tom",12);
System.out.println(person);
//2.通过反射,调用指定的属性
Field age = clazz.getDeclaredField("age");
age.set(person, 10);
System.out.println(person);
//3.通过反射,调用指定的方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(person);
System.out.println("*************************************");
//4.通过反射,可以调用Person类的私有结构的
Constructor cons1 = clazz.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1 = (Person) cons1.newInstance("Jerry");
System.out.println(p1);
//调用私有的属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p1, "HanMeimei");
System.out.println(p1);
//调用私有的方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String nation = (String) showNation.invoke(p1, "中国");
System.out.println(nation);
//问题1:反射机制与面向对象中的封装性是不是矛盾的,如何看待两个技术?
//不矛盾。
//问题2:开发中用哪种方式建对象?
//建议:直接new的方式
//什么时候会用:动态代理等,AOP理念会着重使用
}
4.总结反射中Class类对象常用的方法
以下返回的都是数组类型
getFields():获取当前运行时类及其父类声明为public访问权限的属性
getDeclaredFields():获取当前运行时类当中声明的所有属性(不包含父类中声明的属性,和权限无关,所有的都有)
getMethods():获取当前运行时类中所有声明为public的方法 包括父类中的
getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中声明的)
getConstructors():获取当前运行时类中声明为public的构造器,包含父类
getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
getSuperclass():获取运行时类的父类
getGenericSuperclass():获取运行时类的带泛型的父类
getInterfaces():获取运行时类实现的接口
clzz.getPackage():获取运行时类所在的包
getAnnotations():获取运行时类的注解
5.获取运行时类带泛型的父类的泛型代码
/*
获取运行时类带泛型的父类的泛型
*/
@Test
public void test4(){
Class clzz=Person.class;
Type genericSuperclass = clzz.getGenericSuperclass();
ParameterizedType parameterizedType= (ParameterizedType) genericSuperclass;
//获取泛型类型的参数数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
}
6.调用运行时类的属性,方法,构造器
举例说明了
调用属性
@Test
public void testFiled1() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class clazz= Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1.getDeclaredField(String Filedname):获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可以访问的
name.setAccessible(true);
//3.获取设置指定对象的此属性值
name.set(p, "TOM");
System.out.println(p);
}
调用方法
/*
如何操作运行时类中的指定的犯法--需要掌握
*/
@Test
public void testMethod() throws Exception, InstantiationException {
Class clazz= Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1.获取指定的某个方法
/*
getDeclaredMethod():参数1 :指明获取的方法的名称 参数2 指明获取的方法的形参列表
*/
Method show = clazz.getDeclaredMethod("show", String.class);
//2.保证当前的方法是可以用的
show.setAccessible(true);
//3.调用invoke方法执行
/*
invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参
invoke()的返回值即为对应调用的方法的返回值
*/
Object chn = show.invoke(p, "chn");
System.out.println(chn);
System.out.println("*********************************************************");
/*
调用静态方法
*/
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
//如果调用运行时类中的方法没有返回值,则此invoke()返回null
Object invoke = showDesc.invoke(Person.class);
System.out.println(invoke);
}
调用构造器
/*
如何调用运行时类中指定的构造器
*/
@Test
public void test8() throws Exception {
Class clazz= Person.class;
//1.获取指定的构造器
//getDeclaredConstructor()参数 指明构造器的参数列表
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
//2.保证此构造器是可以访问的
declaredConstructor.setAccessible(true);
//3.调用此构造器创建运行时类的对象
Object tom = declaredConstructor.newInstance("Tom");
System.out.println(tom);
}
7.静态代理与动态代理
什么是代理类:通常来讲我们的代理类和被代理类实现同一个接口,所以代理类里也有和被代理一样的同名方法。代理类在调用方法a的时候同时调用被代理类的同名方法a。这样就可以在调用被代理类方法a之前做一些事情,之后也可以做一些事情了。
就是图片中这样
静态代理:就是代理类和被代理类在编译期间就定了
静态代理举例
/**
* 静态代理举例
*
* 特点:代理类和被代理类在编译期间就确定下来了
* @Author FanYuping
* @Date 2021/3/8 17:26
*
*/
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;
public ProxyClothFactory(ClothFactory factory){
this.factory=factory;
}
@Override
public void produceCloth() {
System.out.println("--------------执行之前做一些准备工作!---------------");
factory.produceCloth();
System.out.println("--------------执行之后做一些后续的收尾工作!---------------");
}
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("被代理类中的方法被执行");
}
}
public class StaitcProxy {
public static void main(String[] args) {
NikeClothFactory nike=new NikeClothFactory();
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
动态代理:给一个被代理类,动态的生成一个代理类对象。反射的主要体现,动态性。
动态代理举例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* 动态代理举例
*
* @Author FanYuping
* @Date 2021/3/9 11:00
*/
interface Human{
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "i believe i can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃"+food);
}
}
class HumanUtil{
public void method1(){
System.out.println("----------TON1------------------");
}
public void method2(){
System.out.println("----------TON2------------------");
}
}
//代理类书写--动态代理
//根据加载到内存中的被代理类动态的创建一个代理类及其对象
//通过代理类的对象调用方法时,动态的调用被代理类中的同名方法
class ProxyFactory{
//通过调用此方法,返回一个代理类对象
public static Object getProxyInstance(Object obj) throws IllegalAccessException, InstantiationException {
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;//被代理类对象
//赋值方法
public void bind(Object obj){
this.obj=obj;
}
//当我们通过代理类的对象,调a方法时,就会自动的调用如下的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method :即为代理类对象调用的方法,被代理类也调用同名方法
//obj本身就是被代理对象
HumanUtil util=new HumanUtil();
util.method1();
Object returnValue = method.invoke(obj, args);
util.method2();
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
SuperMan superMan=new SuperMan();
//代理类对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
proxyInstance.eat("四川麻辣烫");
System.out.println("*******************************************************");
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
proxyInstance1.produceCloth();
}
}