Java-反射和注解篇

注解和反射

注解定义

  • Annotation是从JDK5.0开始引入的技术
  • 作用:
    • 有注释的作用,本身不是程序
    • 可以被其它程序读取(如:编译器)
  • Annotation格式:@注释名,可以加一些参数。如:@SuppressWarnings(value = “unchecked”)
  • 注解可以使用在package、class、method、field等上面,相当于添加了额外的辅助信息,可以通过反射机制访问注解。

内置注解

  • @SuppressWarnings:抑制编译时的警告信息
  • @Override:重写方法
  • @Deprecated:表示不推荐使用

元注解

  • 元注解的作用负责注解其它注解
  • Java定义了四个标准的元注解类型
    • @Target:描述注解的使用地方(class,method,field等)
    • @Retention:表示什么级别保存该注释信息,表述注解的生命周期。SOURCE
    • @Document:表示注解将包含在文档中(JavaDoc)
    • @Inherited:表示子类可以继承父类中的注解

自定义注解

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

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

public class DefAnno {
     
    
    //注解参数无默认值,需赋值。注解中有多个参数名时,参数名不能省略。
    @MyAnnotation(nameArray = {
     "Lily","Tom"})
    public void test(){
     
        
    }
    //注解中只有一个参数时,可以省略value参数名
    @MyAnnotation1("Mary")
    public void test1(){
     
        
    }
    
}

//自定义注解
@Target({
     ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
     
    String name() default "";
    int age() default 0;
    String[] nameArray();
}

//自定义注解,只有一个参数
@Target({
     ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation1{
     
    String value();
}

反射

  • Reflection(反射)是Java被视为动态语言(在运行时,可以根据某些条件改变自身结构)的关键。反射机制允许程序在执行期间借助Reflection API获取任何类的内部信息,并能直接操作任何内部属性及方法。

    反射方式:实例化对象---->getClass()---->得到完整的“包类”名称。

  • Reflection功能:

    • 运行时判断一个对象所属的类
    • 运行时构造任意一个类的对象
    • 运行时判断一个类所拥有的变量和方法
    • 运行时处理注解
    • 生成动态代理
  • Reflection优缺点

    • 优点:可以动态创建对象和编译,体现很大的灵活性
    • 缺点:对性能有影响
Class c = Class.forName("com.school.reflection.User")--获取User类对应的Class类
  • Class类的常用方法

    • static ClassforName(String name):返回指定包名的Class对象
    • Object newInstance():调用缺省构造函数,返回Class对象的一个实例
    • getName():返回类名
  • 获取Class类的方式:

    • 已知具体的类:Person.Class

    • 已知某个类的实例:person.getClass();

    • 已知一个类的路径:Class.forName(“类路径”)

    • 基本内置类型的包装类都有一个Type属性

      Class c1 = Integer.TYPE;
      
  • class、interface、数组、enum、annotation、primitive type(基本数据类型)和void

Java 内存分析

  • 堆:存放new对象和数组,可以被线程共享。栈:存放基本变量类型(包含具体数值)和引用对象的变量。方法区:所有的class和static变量,可以被所有线程共享。
  • 类的加载过程:
    • 类的加载(load):将类的class文件读入内存,将静态数据转换为方法区运行时的数据结构并创建一个java.lang.Class对象,此过程有类加载器完成。
    • 类的链接(Link):将类的二进制数据合并到JRE中,同时为类变量进行默认初始值并在方法区中分配内存。
    • 类的初始化(Initialize):JVM负责对类初始化,对静态变量执行赋值操作和执行静态代码块。
  • 类初始化
    • 类主动引用(一定会发生类的初始化)
      • 虚拟机启动时,先初始化main方法所在的类
      • new 一个类的对象
      • 调用类的静态成员和静态方法
      • 使用java.lang.reflect包得方法对类进行反射调用
      • 当初始化一个类时,如果父类没有被初始化,则先初始化它的父类。
    • 类的被动引用(不会发生类的初始化)
      • 通过子类引用父类的静态变量,不会导致子类的初始化
      • 通过数组定义类引用,不会触发此类的初始化
      • 引用常量不会触发此类的初始化。(常量在链接阶段就存入调用类的常量池中)
package definition;

public class Reflection {
     
    //主动调用:main方法对应的类被初始化
    public static void main(String[] args) throws ClassNotFoundException {
     
        System.out.println("main类被初始化");

        //主动调用:new类的实例
        Son son = new Son();

        //主动调用:反射
        Class c = Class.forName("definition.Son");

        //被动调用:子类调用父类静态变量
        System.out.println(Son.b);
        //通过数组定义类引用,不会触发此类的初始化
        Son[] sonArray = new Son[10];
        //引用常量不会触发此类的初始化
        System.out.println(Son.M);

    }
}


class Father{
     
    static int b = 10;
    static{
     
        System.out.println("父类被初始化");
    }
}

class Son extends Father{
     

    static {
     
        System.out.println("子类被初始化");
    }
    static final int M = 10;
}
  • 类加载器:将类的class文件读入内存,将静态数据转换为方法区运行时的数据结构并创建一个java.lang.Class对象,此过程有类加载器完成。

    • 加载器类型:引导类加载器:负责java平台核心库。扩展类加载器;负责jre/lib/ext目录下的jar包或D java.ext.dirs指定目录下的jar包装入工作库。系统类加载器:负责java-classpath或D java.class.path目录下的类或jar包装入工作库。

      ClassLoader  systemClassLoader = ClassLoader.getSystemClassLoader(); --获取系统类的加载器
      ClassLoader parent = systemClassLoader.getParent(); --获取扩展类加载器
      ClassLoader parent1 = parent.getParent();  --获取引导类加载器
      Class.forName("类路径名");  --当前类由哪个类加载器加载
      System.getProperty("java.class.path")  --获取系统记载器可以加载的路径
          
      
    • 双亲委派机制:如自定义类String,在类加载过程中,在系统/扩展/引导加载器中寻找String类,由于存在java.lang.String类,自定义类会失效,保证安全性。

获取运行时类的完整结构

Class c = Class.forName("类路径名");
c1.getFields();  --只能获取public的属性
c1.getDeclaredField();  --获取类中全部属性
c1.getDeclaredField("name");  --获取指定属性
c1.getMethods()  --获取本类以及父类的public方法
c1.getDeclaredMethods();  --获取本类中的所有方法
c1.getMethods(方法名,方法所需参数)
c1.getConstructors();  --获得public构造器方法
c1.getDeclaredConstructors();   --获得所有构造器方法 
c1.getDeclaredConstructors(参数:String.class,int.class);   ----获得指定构造器方法   

反射使用方法

  • 创建类的对象:

    • 调用Class对象的newInstance() --类必须有一个无参的构造器
    • 调用Class对象的getDeclaredConstructor(参数)
  • 调用指定方法:

    • 调用Class对象的getDeclaredMethods(参数)
    • 之后使用Object invoke(Object obj,Object… args) ,并向方法中传递要设置的obj对象的参数信息。
      • Object 对应原方法的返回值,若原方法中无返回值,此时返回null
      • 若原方法为静态方法,形参Object obj可为null
      • 若原方法为形参列表为空,形参Object[] argsj可为null
      • 若原方法为private的私有方法,在调用invoke()前,需调用setAcessible(true)
  • setAcessible()

    • Method和Field,Constructor对象都有setAcessible()方法
    • setAcessible()作用是启动和禁用访问安全检查的开关。

    User类:

package reflector;

public class User {
     

    private String name;
    private int age;
    private String sex;

    public User(){
     

    }

    public User(String name,int age,String sex){
     
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public void setName(String name){
     
        this.name = name;
    }
    public String getName(){
     
        return name;
    }
    private void display(String name,int age,String sex){
     
        System.out.println("姓名:" + name + "," + "年龄:" + age + "," + "性别:" + sex);
    }

    public void test(){
     
        System.out.println("dsddd");
    }

}

反射创建类实例,调用类方法以及调用类字段:

package reflector;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class RefleExec {
     
    public static void main(String[] args) throws Exception {
     
        //创建class对象
        Class c = Class.forName("reflector.User");
        //方法一:构造User对象
        User user = (User)c.newInstance();
        //方法二:构造User对象
        Constructor constructor = c.getDeclaredConstructor(String.class,int.class,String.class);
        User user1 = (User)constructor.newInstance("sgay",14,"男");

//        System.out.println(user+"    "+user1);
        //反射调用方法
        Method method = c.getDeclaredMethod("display",String.class,int.class,String.class);
        //如果是私有方法,修改访问权限
        method.setAccessible(true);
        method.invoke(user,"dfdd",20,"男");
//        user.test();
//        System.out.println( user1.getName());

        //反射操作属性
        Field field = c.getDeclaredField("name");
        field.setAccessible(true);
        field.set(user,"dcss");
//        user.setName("ysadc");
        System.out.println(user.getName());

    }
}

反射操作泛型

  • parameterizedType:表示一种参数化类型,如:collection

  • GenericArrayType:表示一种参数化类型或者类型变量的数组类型

  • TypeVariable:各种类型变量的公共父接口

  • WildcardType:表示一种通配符类型表达式

package reflector;

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 Generic {
     
    public void test1(Map<String,User> map, List<User> list){
     
        System.out.println("test1");
    }

    public Map<String,User>test2(){
     
        System.out.println("test2");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
     
        Method method = Generic.class.getDeclaredMethod("test1", Map.class, List.class);
        //获取方法中的泛型参数
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType:genericParameterTypes ){
     
//            System.out.println(genericParameterType);
            //Map --得到String,User
            if(genericParameterType instanceof ParameterizedType){
     
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for(Type actualTypeArgument:actualTypeArguments){
     
                    System.out.println(actualTypeArgument);
                }
            }
        }

        //获取方法的返回值反泛型类型
        Method method1 = Generic.class.getDeclaredMethod("test2");
        Type returnType = method1.getGenericReturnType();
        if(returnType instanceof ParameterizedType){
     
            Type[] actualTypeArguments= ((ParameterizedType) returnType).getActualTypeArguments();
            for(Type actualTypeArgument:actualTypeArguments){
     
                System.out.println(actualTypeArgument);
            }
        }

    }
}

反射操作注解

package reflector;

import java.lang.annotation.*;
import java.lang.reflect.Field;


public class RefOperAnno {
    public static void main(String[] args) throws NoSuchFieldException {
        //获取类的注解
        Class c = Student.class;
        Annotation[] annotations = c.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获取注解的值
        Table table = (Table)c.getAnnotation(Table.class);
        System.out.println(table.value());


        //获取属性注解
        Field field = c.getDeclaredField("id");
        FieldPro fieldPro  = (FieldPro)field.getAnnotation(FieldPro.class);
        System.out.println(fieldPro.columnName());
        System.out.println(fieldPro.length());
        System.out.println(fieldPro.type());

    }

}

@Table("db_student")
class Student{
    @FieldPro(columnName = "id",type = "int",length = 100)
    private int id;
    @FieldPro(columnName = "age",type = "int",length = 100)
    private int age;
    @FieldPro(columnName = "name",type = "String",length = 100)
    private String name;

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


    public int getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

//类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}

//属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldPro{
    String columnName();
    String type();
    int length();
}

你可能感兴趣的:(Java,SE,java,反射)