反射注解代理

类的加载:

1. 第一次使用类

当我们的程序第一次使用某个类(创建对象、访问它的静态成员…)(除常量)时,JVM会到硬盘上读取这个类的class文件。

2. 运行时使用过的类

Java对于任何在程序运行过程中使用过的类,都会将它们的类信息存储到"方法区",都会为其创建一个、而且只创建一个Class对象。
例如:Student类、System类、Scanner类、Random类、ArrayList类…
这就是为什么"静态同步方法",它的锁对象是本类的Class对象。public synchronized static void show(){
}

3. 加载器

当JVM加载我们的class文件时,也是用一个"类"去加载,这种类在JVM中被称为:类加载器.
Java中有三种类加载器:
1).启动类加载器(Bootstrap ClassLoader):用于加载系统类库<JAVA_HOME>\bin目录下的class,例如:rt.jar。(例如:System类、Random类、ArrayList类)
2).扩展类加载器(Extension ClassLoader):用于加载扩展类库<JAVA_HOME>\lib\ext目录下的class。
3).应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器(例如:Student类、Phone类…)
JVM加载一个类,使用"双亲委托模型":
当我们要加载一个类:
例如:Student类–>JVM–>应用程序类加载器–>委托给"扩展类加载器"–>委托给"启动类加载器",发现不能加载;然后:应用程序类加载器 <–“扩展类加载器”<–

获取一个类的Class对象的三种方式

1).Object类:getClass()【适合获取类库的类的Class】
2).任何数据类型(包括基本数据类型):数据类型.class【适合获取类库的类的Class】
3).Class的静态方法forName(String 全类名):Class.forName(String 全类名)【常用-适合获取我们自定义类的Class对象】
注意:上述三种方式,都会先判断是否有Class对象,如果没有,会读取class文件,然后在方法区中创建它的Class对象。
//1.getClass();
String s = new String();
Class<? extends String> aClass = s.getClass();
//2.数据类型.class(包括基本数据类型)
Class<String> stringClass = String.class;
//3.Class.forName(String 全类名)
Class<?> clazz = Class.forName("com.itheima.demo02_Class_ClassLoader.Student");

通过Class对象,获取一个类的构造方法,并创建它的对象。

批量获取:

1).public Constructor[] getConstructors():获取所有的"公有构造方法",会将每个公有构造方法封装为一个Constructor对象,多个Constructor对象封装到一个数组中返回。
2).public Constructor[] getDeclaredConstructors():获取所有的构造方法,包括:公有、受保护、默认、私有。

获取单个:[掌握]

3).public Constructor getConstructor(Class … parameterTypes):获取某个"公有构造方法"
例:Constructor constructor = Class.getConstructor(String.class);
4).public Constructor getDeclaredConstructor(Class … parameterTypes):获取任何的构造方法。
例:
DeclaredConstructor declaredConstructor = Class.getDeclaredConstructor(String.class)

调用构造方法

Constructor(代表一个构造方法)–>newInstance(实参)
例:constructor.newINstance(“猫爬”, 23, “男”, “艾欧泽亚”);
如果调用此构造方法,没有"权限(访问权限修饰符的限制)",要先设置:暴力访问
如果有访问权限,也可以设置"暴力访问",Constructor–>setAccessible(true)
例:constructor.setAccessible(true);

//获取私有的、String和int参数的构造方法
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class, String.class, String.class);
System.out.println(declaredConstructor);
//设置暴力访问
declaredConstructor.setAccessible(true);
//使用私有构造方法
Object student = declaredConstructor.newInstance("猫爬", 23, "男", "艾欧泽亚");
System.out.println(student);

通过Class对象获取一个类的"成员属性",并设置、获取成员属性的值

批量获取:

1).public Field[] getFields():获取所有的"公有成员属性"会将每个公有成员属性封装为一个Field对象,多个Field对象封装到一个数组中返回。
2).public Field[] getDeclaredFields():获取所有的成员属性,包括:公有、受保护、默认、私有。

获取单个:

1).public Field getField(String fieldName):通过"属性名",获取某个"公有成员属性"
2).public Field getDeclaredField(String fieldName):通过属性名,获取任何访问权限的成员属性。

赋值,获取值

1).要为属性赋值,必须先创建此类对象;
2).赋值:Field–>set(Object targetObj,Object value):如果没有访问权限,设置暴力访问
Field–>setAccessible(true)
3).获取值:Field–>get(Object targetObj)

Field address = clazz.getField("address");
Field name = clazz.getDeclaredField("name");
Student student = new Student();
address.set(student,"艾欧泽亚");
//暴力访问私有属性
name.setAccessible(true);
name.set(student,"猫爬");
System.out.println(student);

通过Class对象获取一个类的成员方法,并调用

批量获取:

    1).public Method[] getMethods():获取所有的"公有成员方法"
            会将每个公有成员方法封装为一个Method对象,多个Method对象封装到一个数组中返回。
    2).public Method[] getDeclaredMethods():获取所有的成员方法,包括:公有、受保护、默认、私有。

获取单个:[掌握]

 	3).public Method getMethod(String methodName,Class... params):通过"方法名,
 	参数的Class",获取某个"公有成员方法"
 	4).public Method getDeclaredMethod(String methodName,Class ... params):通过
 	方法名、参数Class,获取任何访问权限的成员方法。

调用方法:

Method类的–>invoke(Object targetObj,Object … params)
如果没有访问权限,需要设置暴力访问:Method类的–>setAccessible(true)

//1.获取此类的Class对象
        Class student = Class.forName("com.itheima.demo04_reflect_Constructor.Student");
        //2.获取方法
        Method[] methods = student.getMethods();
        Method[] declaredMethods = student.getDeclaredMethods();
        //3.使用方法
        Method eat = student.getMethod("eat");
        Student s = new Student("杨晨");
        eat.invoke(s);
        //4.暴力访问私有方法
        Method playGame = student.getDeclaredMethod("playGame", String.class, int.class);
        playGame.setAccessible(true);
        playGame.invoke(s,"猫爬",24);

题目:程序中现有一个ArrayList集合,现在需要通过代码向这个集合中添加一个String类型的数据

public static void main(String[] args) throws Exception {
    //创建一个ArrayList集合
    ArrayList<Integer> list = new ArrayList<>();
    //获取ArrayList类的class对象
    Class<ArrayList> arrayListClass = ArrayList.class;
    //获取成员方法
    Method add = arrayListClass.getMethod("add", Object.class);
    //调用方法添加数据
    add.invoke(list,"猫爬");
    System.out.println(list);
}

泛型的意义在于,编译期间可以验证语法,达到代码不出错

注解

注解的作用:写在"源码"中,告诉"注解解析器",下面的代码怎样编译和运行。
注解的应用包含:注解 + 注解解析器(程序)

定义注解

public @interface MyTest {
}

元注解:Java类库中定义好的注解,用在"注解的定义"上,用于对注解进行"约束"的(即用于定义注解的注解):

  1. @Target:约束新定义的注解的"使用位置"
    格式:@Target(ElementType.METHOD)
    ElementType的常用值:
    1).TYPE:类,接口
    2).FIELD:成员变量
    3).METHOD, 成员方法
    4).PARAMETER, 方法参数
    5).CONSTRUCTOR, 构造方法
    6).LOCAL_VARIABLE, 局部变量
  2. @Retention:约束新定义的注解的"生命周期"
    格式:@Retention(RetentionPolicy.SOURCE)可以约束注解的生命周期:源码
    RetentionPolicy的取值:
    1).SOURCE:在源码中。不会编译到class文件中。作用:给编译器中的"注解解析器"看的。例如:@Override
    2).CLASS:在源码中、class文件。但运行时,不会被加载到运行时内存。
    3).RUNTIME:在源码中、class文件中,运行时内存。例如:@Test

使用注解

@MyTest
public class Student {
    @MyTest
    private String name;
    @MyTest
    public void show(){
        System.out.println("呵呵");
    }
}

注解解析器

使用反射方式,创建使用了注解的类的对象
反射后,获取类的组成部分,
调用isAnnotationPresent方法,判断是否使用了注定注解.class

注解的属性

使用元注解,都是带属性: @Target(ElementType.METHOD)其中的ElementType.METHOD就是属性
属性的作用:可以”更加细致"的对新定义的注解进行"约束"
注解中定义属性的格式:

 public @interface MyTest {
            //属性的格式:数据类型名  属性名() [default 值];
            int index() default 0;  //属性定义后,使用时必须赋值,否则报错
        }

属性的获取:
可以反射获取加入了注解的部分,并调用getAnnotation(注解类.class)方法获取注解对象
注解对象.get属性(),即可获得注解属性值
注意:
1).其中的数据类型,只能是:八种数据数据类型、String、Class、注解类型、枚举类型、上述几种类型的"数组"类型。
2).如果一个注解中:有一个属性名叫:value,而且其他属性都有默认值,而且在使用这个注解时,只需要设置value属性,可以省略:"value = ",直接写值。

代理

设计模式:指利用Java的一些语法特征(继承、封装、多态…)针对某些问题,提出的一种固定的设计方式。Java中已定义的设计模式有很多种(20多种,扩展的有40-50多种)

代理模式

解决的问题:在不更改原类代码的前提下,为原类的方法提供"功能增强"
动态代理:指程序可以在运行时"动态的"为某个"被代理类"产生一个"动态代理对象",并可以进行方法增强。
注意:JDK提供的动态代理是基于"接口"的——要求所有"被代理的类"必须实现同一个接口,从而具有相同的功能
动态代理类:Proxy
产生代理方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)

IStar pantom = (IStar) Proxy.newProxyInstance(classLoader, interfaces, handler);

参数:loader 类加载器,代理类的"类加载器",与"被代理类"的相同
参数:interfaces 代理类的"父接口",与"被代理类"相同

ClassLoader classLoader = ramin.getClass().getClassLoader();
Class<?>[] interfaces = ramin.getClass().getInterfaces();

参数:h 执行代理控制对象
InvocationHandler接口内方法:
public Object invoke(Object proxy, Method method, Object[] args)
方法的作用:当代理调用任何方法,都会被该拦截,执行此方法
可以根据逻辑判断是否执行被代理者的原方法,并且可以增强方法,即在原方法执行前后,执行其他逻辑。
参数说明:
proxy;产生的代理对象[不使用]
method:被代理执行的方法对象
args:被代理执行的方法的参数
return 代理对象

InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("sing".equals(method.getName())){
                    System.out.println("饭桶的魅影唱得好");
                }
                Object result = method.invoke(ramin,args);
                if ("dance".equals(method.getName())){
                    System.out.println("饭桶的大悲跳的也不错");
                }
                return result;
            }
        };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值