注解与反射笔记(狂神说)

注解和反射

注解(java.Annotation)

内置注解

@Override:重写注解

@Deprecated:废弃注解

@SuppressWarnings():镇压警告

元注解

元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明。

@Target:描述注解可以用在什么地方
@Retention:表示在什么级别保存该注解信息(描述注解的生命周期 SOURCE<CLASS<RUNTIME)
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解

自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//自定义注解
public class TestAnno {

    //如果没有默认值 必须给注解赋值
    @MyAnnotation(name = "1122")
    public void test(){

    }
    @MyAnnotation1("222")
    public void test2(){

    }
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    //注解的参数(不是方法):参数类型+参数名()
    String name();
    int age() default 0;
    int id() default -1;
    String[] school() default {"清华大学"};
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation1{
    //如果只有一个参数 建议使用value 这样就可以在使用注解时不用指定参数名
    String value();
}

反射(java.Reflection)

静态语言与动态语言

动态语言

一类在运行时可以改变其结构的语言,例如新的函数、对象、已有的函数被删除或是其他结构上的变化。主要动态语言:Object-C、C#、JavaScript、PHP、Python等

静态语言

运行时结构不可变,如Java、C、C++。Java不是动态语言,但Java可以成为“准动态语言”。即Java有一定的动态性,我们可以利用反射来获得类似动态语言的特性。Java的动态性让编程更加灵活。

反射概述

  • 反射被认为是Java动态语言的关键,反射机制允许程序在执行期借助于Reflection API获取任何类的内部信息,并能直接操作任意对象的内部属性或方法(包括private修饰的字段)

    Class c = Class.forName("java.lang.String")
    
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息。我们可以通过对象看到类的结构。这个对象就像一面镜子,通过这个镜子看到类的结构。所以称之为反射。

在这里插入图片描述

反射机制提供的功能

  • 运行时判断任意一个对象所属的类
  • 运行时构造任意一个类的对象
  • 运行时判断任意一个类所具有的成员变量和方法
  • 运行时获取泛型信息
  • 运行时调用任意一个对象的成员变量或方法
  • 运行时处理注解
  • 生成动态代理

优缺点

优点:动态创建对象和编译,灵活性高

缺点:对性能有影响。反射是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

反射相关API

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Construtor:代表类的构造器

在这里插入图片描述

Class

概述

反射可以得到的信息:类的属性、方法、构造器、类实现了哪些接口。对于每个类而言,JRE都会为其保留一个不变的Class类型的对象。

  • Class本身也是一个类
  • Class对象只能有系统创建(文明只能通过反射去获得)
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成的
  • 通过Class可以完整的得到一个勒种的所有被加载的结构
  • Class类是Reflection的根源,任何想要动态加载、运行的类,唯有先获得相应的Class对象

获取Class类的三种方式

  • 前提:知道具体的类 该方法最安全可靠、程序性能高

    Class clazz = Person.class

  • 前提:已知类的实例

    Class clazz = person.getClass() 这是Object类中定义的方法

  • 前提:已知类的全类名,且该类在类路径下

    Class c = Class.forName(“java.lang.String”)

    在这里插入图片描述

  • 内置对象的包装类都有一个Type属性

    Class c4 = Integer.TYPE;
    

Class类的常用方法

static ClassforName(String name)	返回指定类名的Class对象
Object newInstance()				通过反射 创建一个实例
getName()							返回此Class对象所表示的实体(类、接口、数组类或void)的名称	Class getSuperClass()				返回当前Class对象父类的Class对象
Class[] getinterfaces()				获取当前Class对象的接口
ClassLoader getClassLoader()		返回该类的类加载器
Constructor[] getConstructors()		返回一个包含某些Constructor对象的数组
Method getMethod(String name, Class .. T)	返回一个Method的对象
Field[] getDeclaredFields()			返回Field对象的一个数组

哪些类型可以有Class对象?

class(外部类、局部内部类、匿名内部类等)、interface、数组、enum(枚举)、注解、基本数据类型、void

Java内存分析

在这里插入图片描述

获取类的运行时结构

        Class cl1 = Class.forName("com.ys.reflect.User");

        System.out.println(cl1.getName()); //获得包名+类名
        System.out.println(cl1.getSimpleName()); //获得类名

        Field[] fields = cl1.getFields();   //只能找到public属性
        fields = cl1.getDeclaredFields();   //找到全部属性

        Field field = cl1.getDeclaredField("name"); //获得指定属性的值

        Method[] methods = cl1.getMethods();    //获得本类及父类的所有public方法
        methods = cl1.getDeclaredMethods();     //获得本类的所有方法

        //获得指定的方法
        Method method = cl1.getMethod("setName", String.class);
        method = cl1.getMethod("getName", null);

        Constructor[] constructors = cl1.getConstructors();     //获得public的构造器
        constructors = cl1.getDeclaredConstructors();       //获得所有的构造器

        Constructor constructor = cl1.getConstructor(String.class, int.class, int.class);       //获取指定的构造器

通过反射创建对象

        Class c1 = Class.forName("com.ys.reflect.User");

        //通过反射创建实例
        User user = (User)c1.newInstance();//本质是调用类的无参构造

        //没有无参构造的情况下 通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        user = (User)constructor.newInstance("zs", 16,1);

        //通过反射调用普通方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user, "ls");     //将user的name改为ls invoke是激活的意思

        //通过反射操作属性
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);//不能直接操作私有属性 需要通过这个方法关闭安全检测
        name.set(user, "zs");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值