2020年java反射课堂笔记

反射

1. Junit单元测试

测试分类

  1. 黑盒测试:不需要写代码,输入值看结果
  2. 白盒测试:需要写代码,关注程序的执行流程(如:Junit测试)

Junit测试

实现步骤:

  1. 定义一个测试类(测试用例)
    • 测试类名:被测试的类名Test
    • 包名:xxx.xxx.xx.test
  2. 定义测试方法:可以独立运行
    • 方法名:test即将测试的方法名
    • 返回值:void
    • 参数列表:空参
  3. 给方法加注解:@Test
  4. 导入Junit的依赖环境

判定结果:

  • 红色:失败

  • 绿色:失败

  • 一般情况下,使用断言操作来操作结果

Assert.assertEquals(期望值,result);

@Before&@After

  • @Before:修饰的方法会在测试方法之前被自动执行
  • @After:修饰的方法会在测试方法之后自动被执行

实例代码

public class Calcutor {
    public int add(int a,int b){
        return a+b;
    }
    public int del(int a,int b){
        return a-b;
    }
}

Junit测试类实例代码

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;


public class CalcutorTest {
    @Before
    public void init(){
        System.out.println("执行初始化方法");
    }
    @Test
    public void testadd(){
        Calcutor calcutor = new Calcutor();
        int result = calcutor.add(3,4);
        Assert.assertEquals(7,result);
    }
    @After
    public void after(){
        System.out.println("执行的最后方法");
    }
}

2.反射

反射概述

反射是框架设计的灵魂

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

反射机制:将类的各个组成部分(成员变量、成员方法等)封装为其他对象。

反射优点:

  1. 可以在程序运行过程中,操作这些对象
  2. 可以解耦,提高程序的扩展性

反射详解

获取class对象的3种方式

  1. Class.forName("全类名")

应用:多用于配置文件,将类名定义在配置文件中。读取文件,加载类

  1. 类名.class

应用:多用于参数的传递

  1. 对象.getClass()(常用)

应用:多用于对象获取字节码

结论:同一字节码文件.class文件在程序运行过程中,只会加载一次,三种方式获取的class对象都是同一个。

实例代码

public class Example {
    public static void main(String[] args) throws Exception {
        //1.Class.forName("全类名");
        Class cls1 = Class.forName("AFan.Test.Calcutor");
        System.out.println(cls1); // class AFan.Test.Calcutor
        //2.类名.class
        Class cls2 = Calcutor.class;
        System.out.println(cls2); // class AFan.Test.Calcutor
        //3.对象.getClass()
        Calcutor calcutor = new Calcutor();
        Class cls3 = calcutor.getClass();
        System.out.println(cls3); // class AFan.Test.Calcutor

        System.out.println(cls1 == cls2); //true
        System.out.println(cls1 == cls3); //true

        /*结论:三种方式指向的是同一对象*/
    }
}

Class对象的常用方法

将类的各个部分转化为对象

  1. 获取成员变量们
方法声明功能描述
Field[] getFields()获取所有public修饰的成员变量
Field getFields(String name)获取所有public修饰的name变量名的成员变量
Filed[] getDeclaredFields()获取所有成员变量,不考虑修饰符
Field getDeclaredField(String name)获取name变量名的成员变量
  1. 获取构造方法们
方法声明功能描述
Constructor<?>[] getConstructors()获取所有public修饰的构造器
Constructor getConstructor(类<?>… parameterTypes)获取public修饰的指定的构造器
Constructor<?>[] getDeclaredConstructors()获取所有构造器
Constructor getDeclaredConstructor(类<?>… parameterTypes)获取指定的构造器
  1. 获取成员方法们
方法声明功能描述
Method[] getMethods()获取所有public修饰的成员方法
Method getMethod(String name,类<?>… parameterTypes)获取public修饰的指定的成员方法
Method[] getDeclaredMethods()获取所有成员方法
Method getDeclaredMethod(String name,类<?>… parameterTypes)获取指定的常用方法
  1. 获取类名
方法声明功能描述
String getName()获取类名

操作class对象的方法

  1. Field:操作成员变量们
方法声明功能描述
void set(Object obj,Object value)设置值
Object get(Object obj)获取值
void setAccessible(true)忽略访问权限修饰符的安全检查
  1. Constructor:创建对象
方法声明功能描述
T newInstance(Object obj)创建对象
  1. Method:方法对象
方法声明功能描述
Object invoke(Object obj,Object …args)创建方法对象
String getName()获取方法名

反射实例代码

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

public class Example {
    public static void main(String[] args) throws Exception {
        //获取class对象
        Class personClass = Person.class;
        //获取构造方法的对象
        Constructor personClassConstructor = personClass.getConstructor(String.class, int.class);
        Object person = personClassConstructor.newInstance("afan", 20);
        System.out.println(person);
        //获取成员变量
        Field a = personClass.getField("a");
        a.set(person,"我是a");
        System.out.println(a.get(person));
        //获取成员方法的对象
        Method method = personClass.getMethod("eat", String.class);
        method.invoke(person,"大米饭");
    }
}

反射案例

需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

实现步骤:

  1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
  2. 在程序中加载读取配置文件
  3. 使用反射技术来加载类文件进内存
  4. 创建对象,执行方法

实例代码

className = AFan.Person
methodName = eat
public class Person {
    private String name;
    private int age;

    public Person(){

    }
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println("eat···");
    }
}
import java.io.InputStream;
import java.util.Properties;

public class Example {
    public static void main(String[] args) throws Exception {
        //创建Properties对象
        Properties pro = new Properties();
        //加载配置文件,转换为一个集合
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("pro.properties");
        pro.load(in);
        //获取全类名和方法
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //创建对象,执行方法
        Class proClass = Class.forName(className);
        Object obj = proClass.getConstructor().newInstance();
        proClass.getMethod(methodName).invoke(obj);
    }
}

3.注解

注解介绍

作用:用来对包、类、方法、局部变量、方法参数等元素进行说明,注释。

使用注解:@注解名称

注解与注释的区别:

  • 注解:说明程序,给计算机看的
  • 注释:用文字描述程序的,给程序员看的

作用分类:

  • 编写文档:生成javadoc (API)文档
  • 代码分析:使用反射
  • 编译检查:Override

JDK预定义的一些注解

注解功能描述
@Override检测被该注解标注的方法是否继承自父类(接口)
@Deprecated表示该方法已过时
@SuppressWarnings压制警告
@SuppressWarnings(“all”)压制所有警告

自定义注解

  • 格式:

public @interface 类名{

//属性列表(返回值类型 方法名() )

}

  • 本质:注解本质还是一个接口,该接口默认继承Annotation接口

public interface MyAnno extends java.lang.annotation.Annotation {}

  • 属性:接口中可以定义的抽象方法
    1. 属性的返回值类型:基本数据类型、String、枚举、注解、数组
    2. 定义了属性,在使用时需要给属性赋值
      1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
      2. 如果只有一个属性需要赋值,并且属性的名称是value。则value可以省略,直接定义值即可。
      3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}省略

元注解

定义:描述注解的注解

元注解功能描述
@Target(ElementType e)描述注解能够作用的位置
@Retention描述注解被保留的阶段
@Documented描述注解是否被抽取到API文档中
@Inherited描述注解是否被子类继承

注意:

@Target中ElementType的取值:

  • TYPE:作用在类上
  • METHOD:作用在方法上
  • FIELD:作用在成员变量上

@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到

解析注解

作用:获取注解中定义的属性值

实例代码

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anna {
    String className();
    String methodName();
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

@Anna(className = "AFan.Person",methodName = "eat")
public class Example {
    public static void main(String[] args) throws Exception {
        //获取注解定义的位置的对象
        Class<Example> exampleClass = Example.class;
        //获得指定的注解
        Anna an = exampleClass.getAnnotation(Anna.class);
        String className = an.className();
        String methodName = an.methodName();
        Class newclass = Class.forName(className);
        Constructor constructor = newclass.getConstructor();
        Object p = constructor.newInstance();
        Method method = newclass.getMethod(methodName);
        method.invoke(p);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值