注解和反射

7 篇文章 0 订阅

注解

Annotation是jdk5.0引入的概念
它的作用:

  1. 不是程序本身,可以对程序做出解释(和注释(comment)相似)
  2. 可以被其他程序(如,编译器)读取。

格式:
以“@参数名”在程序中存在,还可以添加一些参数值

适用范围:
可以附加在package,class,method,field等上面,相当于给他们添加了额外的信息,我们可以通过反射编程机制实现对这些元数据的访问。

内置注解

@Override

定义在java.lang.Override中,用于修饰方法,表示一个方法声明重写超类中的另一个方法声明。

@Deprecated

定义在java.lang.Deprecated ,用于修饰方法,属性,类,表示不鼓励程序猿使用这样的元素,该方法废弃或有更好的选择。

@SuppressWarnings

定义在java.lang.SuppressWarnings,用于抑制编译时的警告信息
与前两个不同,次注解需要添加一个参数才能正常使用,这些参数是定义好的:(根据警告类型的不同,参数不同)

@SuppressWarnings(“All”) 忽略全部警告
@SuppressWarnings(“unchecked”)
告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
@SuppressWarnings(“serial”)
如果编译器出现这样的警告信息: The serializable class WmailCalendar does not declare a static final serialVersionUID field of type long
,使用这个注释将警告信息去掉。 · @SuppressWarnings(“deprecation”)
如果使用了使用 @Deprecated注释的方法,编译器将出现警告信息。 使用这个注释将警告信息去掉。 · @SuppressWarnings(“unchecked”, “deprecation”)
告诉编译器同时忽略 unchecked和deprecation的警告信息。 · @SuppressWarnings(value={“unchecked”, “deprecation”})
等同于 @SuppressWarnings(“unchecked”, “deprecation”)

除此之外,其他的类型的警告忽略参考
链接: 参考链接.

元注解

元注解的作用是负责注解其他的注解,Java提供了4个Meta-annotation类型,他们被用来提供对其他annotation类型做说明。存储于 java.lang.annotation包下

@Target

用于描写注解适用范围(即注解可以用于什么地方)

@Retention

用于描述注解的生命周期
(SOURCE<CLASS<RUNTIME)

@Document

说明该注解包含在javadoc中

@Inherited

说明子类可以继承父类中的该注解

import org.junit.Test;

import java.lang.annotation.*;

@MyAnnointion
public class Meta_Annointion {
    //@MyAnnointion----会报错,没定义成员属性上
    String name;
    @Test
    @MyAnnointion
    public void test(){

    }
}
//定义一个注解
//定义他的适用范围------定义在方法和类上
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//定义生命周期(注解在哪一阶段有效)
    @Retention(RetentionPolicy.RUNTIME)
//(SOURCE<CLASS<RUNTIME)
    //定义将我们的注解生成在javadoc中
    @Documented
//子类可以继承父类的注解
    @Inherited
 @interface MyAnnointion{

}

自定义注解

关键字 @Interface ,自动继承了java.lang.annointion.Annotation接口

@interface用来声明一个注解,格式:public@interface注解名{定义内容} 其中的每一个方法实际上是声明了一个配置参数.
方法的名称就是参数的名称 返回值类型就是参数的类型(返回值只能是基本类型,Class, String, enum).
可以通过default来声明参数的默认值 如果只有一个参数成员,一般参数名为value
注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值,

反射Reflection

反射机制允许程序在执行期间借助Reflection API 获取任何类的内部信息,并能直接操作对象的实行和方法。
加载完类后,在堆内存的方法区中 就产生了一个Class对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,我们可通过此对象看见类的完整信息,就想一面镜子,通过它我们可以看到累的结构,我们形象的称其为“反射”

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

反射机制作用:

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

优点:
可以实现动态创建对象和编译,有很大的灵活性。
缺点:
会拖慢性能,反射是解释性的操作,这类操作总慢于直接执行相同的操作
class类的常用方法
在这里插入图片描述
class获得实例的方法

public class ClassDome {
    public static void main(String[] args) {
        //通过对象获得---------注意一个类只有一个Class对象 hashcode相同
        Class c1 = Student.getClass();
        System.out.println(c1.hashCode());
        //通过forName 包名 获得
        Class c2 = Class.forName("java.nuc.src.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.hashCode());//输出的是Integer的Class 和上面不同

        //通过子类获得父类
        class c5 = c1.getSuperclass();
        System.out.println(c5.hashCode());

    }
}
class Person{
    private String Name;
    private int id;

    public Person() {
    }

    public Person(String name, int id) {
        Name = name;
        this.id = id;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
class Student extends Person{
    public Student(){
        this.name="学生";
    }
}

有哪些类型有Class对象

public Test {
    public static void main(String[] args) {
        Class c1 = Objcet.class;//类
        Class c2 = Comparable.class;//接口
        Class c3 = String[].class;//一维数组
        Class c4 = int[][].class;//二维数组
        Class c5 = Override.class;//注解
        Class c6 = ElementType.class;//枚举
        Class c7 = Integer.class;//基本数据类型
        Class c8 =void.class;//void
        Class c1 = Class.class;//Class
    }
}

类加载器

作用:将Class文件字节码内容加载到内存中。并将这些静态数据转化成方法取得运行时那数据结构,然后在堆中生成一个代表这个累的java.lang.Class对象,作为方法区中类数据的访问入库
类缓存:标准的javaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,他将维持加载(缓存一段时间),不过jvm的垃圾回收机制可以回收这些Class对象。
分类:
在这里插入图片描述
在这里插入图片描述
类加载过程

  1. 加载
  2. 链接
    2.1 验证
    2.2 准备
    2.3 解析
  3. 初始化
public class Text {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader =  ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
       //获得系统类加载器的父类-----扩展类加载器
        ClassLoader  parent = systemClassLoader.getParent();
        System.out.println(parent);
        //获取扩展类加载器的父类------根加载器(c/c++)直接加载核心类库无法直接获取
        ClassLoader grandpa = parent.getParent();
        System.out.println(grandpa);
        //测试当前类是由那个类加载器加载的
        Class c1 = Text.class;
       ClassLoader c =  c1.getClassLoader();
        System.out.println(c);
        //测试JDK内部类是由那个类加载器加载的
        ClassLoader c2 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(c2);
        //获得系统类加载器可以加载得路径
        System.out.println(System.getProperty("java.class.path"));
    }
}

在这里插入图片描述

双亲委派机制:

流程图
在这里插入图片描述

当一个编程文件要被加载时。不考虑我们自定义的类加载器情况下,首先会在AppClassLoader中判断是否加载过,如果加载过,那就无需再次加载了。如果没有加载,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上,直到到达BootstrapclassLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

好处:可以使我们的程序更安全,如果有人想替换系统级别的类:如String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会
再去加载,从一定程度上防止了危险代码的植入。

通过反射获取类的钢结构:
新建一个我们要反射的类

public class User {
    public String name;
    private String privateName;
    private Integer id;

    public User() {
    }

    public User(String name, String privateName, Integer id) {
        this.name = name;
        this.privateName = privateName;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrivateName() {
        return privateName;
    }

    public void setPrivateName(String privateName) {
        this.privateName = privateName;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", privateName='" + privateName + '\'' +
                ", id=" + id +
                '}';
    }
}

进行反射获得结构
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws NoSuchMethodException {
        //定义要反射累的class对象
        Class c = User.class;
        //获取类的名字
        System.out.println(c.getName());//包名+类名
        System.out.println(c.getSimpleName());//包类名
        System.out.println("====================");
        //获得累的属性
        Field[] fields = c.getFields();//只能获得public属性
        for (Field f:fields){
            System.out.println(f);
        }

        Field[] field = c.getDeclaredFields();//获得全部属性
        for (Field f:field){
            System.out.println("getDeclaredFields======"+f);
        }
        //获得类的方法
        Method[] methods = c.getMethods();//获得本类及父类的全部public
        for (Method f:methods){
            System.out.println("g"+f);
        }
        Method[] method = c.getDeclaredMethods();//获得本类的全部方法
        for (Method f:method){
            System.out.println("getDeclaredMethods======"+f);
        }
        System.out.println("=============");
        //获得指定的方法======传入方法名和参数类型
      Method s1=  c.getMethod("getName", null);
        Method s2=  c.getMethod("setName", String.class);
        System.out.println(s1);
        System.out.println(s2);
        //获得构造器
        Constructor[] constructors = c.getConstructors();
        for (Constructor con:constructors){
            System.out.println(con);
        }
        Constructor[] constructor = c.getDeclaredConstructors();
        for (Constructor con:constructor){
            System.out.println("==="+con);
        }
        System.out.println("=========");
        //获得指定的构造器
        Constructor constructor1 = c.getConstructor(String.class,String.class,Integer.class);
        Constructor constructor2 = c.getConstructor();
        System.out.println(constructor1);
        System.out.println(constructor2);
    }

}

在这里插入图片描述

在这里插入图片描述

动态创建对象执行方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//通过反射,动态创建对象
public class ReflectionDome {
    public static void main(String[] args) throws Exception{
        //获得class对象
        Class c2 = User.class;
        //构造一个对象
        User user = (User) c2.newInstance();
        System.out.println(user);
        //结果为:  User{name='null', privateName='null', id=null}  创建的是无参对象
        //创建有参对象----通过构造器
       Constructor constructor=c2.getConstructor(String.class,String.class,Integer.class);
      User user1=(User) constructor.newInstance("我","你",18);
      System.out.println(user1);

      //通过反射调用普通方法
        //构造一个对象
        User user2 = (User) c2.newInstance();
        //通过反射获取一个方法
        Method m1= c2.getMethod("setName", String.class);
        //invoke(对象,“方法的值”)
        m1.invoke(user2, "鸿蒙系统");
        System.out.println(user2.getName());
       //通过反射操作属性
        Field name =c2.getField("name");
        //不能直接操作私有属性,要关闭安全检测,-----》属性或方法.setAccessible(true)
        name.setAccessible(true);
        name.set(user2,"华为-鸿蒙harmonyos");
        System.out.println(user2.getName());

    }
}

在这里插入图片描述

反射操作泛型

Java采用泛型擦除的机制引入泛型,java的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,以编译完成,所有和泛型有关的类型全部擦除。
为了通过反射操作这些类型,java引入了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归到class类中的类型但又和原始类型齐名的类型

package reflectiondome;

import org.junit.Test;

import javax.lang.model.element.TypeParameterElement;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//通过反射获取泛型
public class Dome {
    //获取参数
    public void test01(Map<Student, String> map, List<Student> list) {
        System.out.println("test01");
    }

    //获取返回值
    public Map<Student, String> test02() {
        System.out.println("test02");
        return null;
    }

    public static void main(String[] args) throws Exception {
        //先获得方法
        Method method = Dome.class.getMethod("test01", Map.class, List.class);
        Type[] type = method.getGenericParameterTypes();//获取带参数的泛型
        for (Type a : type) {
            System.out.println(a);//输出的是参数化类型
            if (a instanceof ParameterizedType)//判断是否属于参数化类型
            {
                //获得其真实类型
                Type[] type1 = ((ParameterizedType) a).getActualTypeArguments();
                for (Type t : type1) {
                    System.out.println(t);
                }
            }
        }
        //返回值类型

        Method method1 = Dome.class.getMethod("test02",null);
        Type type3 = method1.getGenericReturnType();
        if (type3 instanceof ParameterizedType){
            Type[] types = ((ParameterizedType) type3).getActualTypeArguments();
            for (Type type1:types){
                System.out.println(type1);
            }
        }
    }
}

在这里插入图片描述

通过反射操作注解
package reflectiondome;

import java.lang.annotation.*;
import java.lang.reflect.Field;
//通过反射操作注解

public class test {
    public static void main(String[] args) throws NoSuchFieldException {
        Class c1 = Person1.class;
        //通过反射操作注解
       Annotation[] annotations = c1.getAnnotations();//通过反射获得所有注解
        //获得注解的值
        System.out.println("=======获得注解的值=========");
        for (Annotation annotation :annotations){
            System.out.println(annotation);
        }
        //获得注解的value值
        System.out.println("=======获得注解的value值=========");
        TypeClass annotation = (TypeClass)c1.getAnnotation(TypeClass.class);
        String name = annotation.value();
        System.out.println(name);
        //获得类指定的注解
         //1 获得注解算在的方法或属性
       Field f= c1.getDeclaredField("id");
        FieldClass annotation1 = f.getAnnotation(FieldClass.class);
        System.out.println(annotation1.columnName());
        System.out.println(annotation1.length()); 
        System.out.println(annotation1.type());

    }
}

@TypeClass("db_Person")
class Person1 {
    @FieldClass(columnName = "db_name",type = "String",length = 10)
    private String name;
    @FieldClass(columnName = "db_id",type = "int",length = 10)
    private int id;

    public Person1() {
    }

    public Person1(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
//定义一个类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TypeClass{
    String value();
}
//定义一个属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldClass{
    String columnName();
    String type();
    int length();
}

在这里插入图片描述

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码 - 菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值