一. 反射

反射: 将类的各个组成部分封装为其他对象.

1.1 获取class对象的方式

Class.forName("全类名"):
将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中,读取文件,加载类 类名.class:
通过类名的属性class获取
多用于参数的传递 对象.getClass():
多用于对象的获取字节码的方式

注意:

以上三种方法获得的字节码文件地址相同

同一个字节码文件在一次程序运行中只会加载一次.

1.1.1 代码演示

示例person:

package reflecting;

public class demo00_person {

    public String name;
protected String name1;
String name2;
private String name3; //成员方法
public static void method1(){
System.out.println("我是空参方法");
}
public static void method11(String s){
System.out.println("我是有参方法"+s);
} public demo00_person() {
} public demo00_person(String name) {
this.name = name;
} @Override
public String toString() {
return "demo00_person{" +
"name='" + name + '\'' +
'}';
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

使用:

public static void main(String[] args) throws ClassNotFoundException {//异常
Class cl1 = Class.forName("reflecting.demo00_person");//从包名开始
Class cl2 = demo00_person.class;
Class cl3 = demo00_person.class; System.out.println(cl1 ==cl2);//true
System.out.println(cl1==cl3);//true
}

1.2 class对象的功能

1.2.1 获取

1.成员变量:
Filed[] getFields(): 获取public修饰的成员变量
Filed getFiled(String name): 获取public修饰的指定名称的成员变量
Filed[] getDeclaredFields()
Filed getDeclaredField(String name) 2.构造方法:
Constructor<?>[] getConstructors()
Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) 3.成员方法:
Method getMethod(String name, 类<?>... parameterTypes),方法名和按声明顺序标识该方法形参类型
Method[] getMethods()
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
method[] getDeclaredMethods() 4.类名
String getName()

1.2.2 使用

一.成员变量:Field对象操作:
1.设置值:
void set(Object obj, Object value)
2.获取值:
Object get(Object obj)
3.忽略访问权限修饰符的安全检查:
SetAccessible(true): 暴力反射 二. 构造方法Constructor对象
1.创建对象:
T newInstance(Object... initargs)
使用此Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
2.如果创建空参数构造器,可以使用:
class.getDeclaredConstructor().newInstance()
getDeclaredConstructor()根据他的参数对该类的构造函数进行搜索并返回对应的构造函数,
没有参数就返回该类的无参构造函数,然后再通过newInstance进行实例化。
同样有SetAccessible(true)暴力反射. 三. 成员方法Method对象
1. 获取成员方法后,执行方法:
Object invoke(Object obj, Object... args), 传入调用该方法的类的对象和实参
同样有SetAccessible(true).
2. 获取方法名
String getName()

1.2.3 代码演示

public static void main(String[] args) throws Exception {
//获取person的Class对象
Class<demo00_person> p1 = demo00_person.class;
//获取成员变量
Field[] fields = p1.getFields();
for (Field field : fields) {
System.out.println(field);//person写了四个权限,只获取到public修饰的
}
//获取Field对象:名为name的成员变量
Field name = p1.getField("name");
//获取值,传入person对象
demo00_person person = new demo00_person();
Object value = name.get(person);//获得值,字符串默认值null //设置值
name.set(person,"bronya");
System.out.println(person);//打印结果name="bronya" System.out.println("---------"); //忽略访问权限的安全检查
Field dc = p1.getDeclaredField("name3");
dc.setAccessible(true);//忽略权限
Object o = dc.get(person);
System.out.println(o);//null System.out.println("---获取构造方法---");
Constructor<demo00_person> constructor = p1.getConstructor(String.class);
System.out.println("构造器:"+constructor);
//T newInstance(Object... initargs)方法创建对象
demo00_person person1 = constructor.newInstance("板鸭");
System.out.println("创建的对象:"+person);
//创建空参数构造器
demo00_person person2 = p1.getDeclaredConstructor().newInstance();
System.out.println("空参数:"+person2); //获取成员方法,传入指定方法名,和形参类型
Method method1 = p1.getMethod("method1");//空参的
Method method11 = p1.getMethod("method11", String.class);//有参写法
//执行方法,传入类对象和实参
method1.invoke(p1);
method11.invoke(p1,"666");
//获取所有public修饰的成员方法
Method[] methods = p1.getMethods();
for (Method method : methods) {
System.out.println(method);//还包括Object类的方法
System.out.println(
method.getName()
);
}
}

1.2.4 框架应用

写个框架,创建任意类的对象,执行其中任意方法.
1.将要创建对象的全类名和需要执行的方法定义在配置文件中
2.在程序中加载配置文件
3.用反射技术加载类文件进内存
4.创建对象, 执行方法

src目录下新建一个properties配置文件:

className = reflecting.demo00_person
methodName = method11

使用:

public class demo03_Test {
public static void main(String[] args) throws Exception {
//加载配置文件,先创建Properties对象,用load方法加载
Properties properties = new Properties();
//获取该字节码文件对应的类加载器,
ClassLoader classLoader = demo03_Test.class.getClassLoader();
//调用getResourceAsStream()传入配置文件名称,获取字节输入流
InputStream ras = classLoader.getResourceAsStream("pro.properties");
//字节输入流给属性集合
properties.load(ras);
//获取配置文件中定义的数据
String classname = properties.getProperty("className");
String method = properties.getProperty("methodName");
//加载该类进内存
Class<?> aClass = Class.forName(classname);
//创建类对象
Object obj = aClass.getDeclaredConstructor().newInstance();
//获取方法对象,传入方法名和参数
Method method1 = aClass.getMethod(method,String.class);
//执行方法,传入类对象和实参
method1.invoke(obj,"111");
}
}

二. 注解

2.1 定义

注解(Annotation),也叫元数据。一种代码级别的说明。
它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】java doc命令
②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

2.2 jdk内置的注解

@Override: 检查该方法是否是继承自父类的
@Deprecated: 该注解标注的内容已经过时(但仍能使用)
@SuppressWarnings: 告诉编译器忽略指定的警告,不用在编译完成后出现警告信息。参数传入all表示全部

2.3 自定义注解

2.3.1 格式

元注解
public @interface 名称{}

注解本质是接口,继承java.lang.annotation.Annotation接口.

2.3.2 元注解

元注解是用于描述注解的注解

@Target: 表示注解能够作用的位置
参数ElementType.
TYPE: 表示注解可以作用到类上
METHOD: 表示可以作用到方法
FIELD: 可以作用于成员变量上
@Retention: 描述注解被保留的阶段
参数RetentionPolicy.
SOURCE: 不会保留到Class字节码文件中
CLASS: 会保留到Class字节码文件中
(常用) RUNTIME: 当前被描述的注解会保留到Class字节码文件中并被JVM读取到
@Documented: 描述注解是否被抽取到api文档中
@Inherited: 描述注解是否被子类继承

2.3.3 注解属性

注解里的抽象方法称作注解属性,

注解属性的要求:

1.返回值类型必须为之一: 基本数据类型\String\枚举\注解\以上类型的数组
2.使用时需要赋值, 或者定义属性时用default初始化默认值

2.3.4 代码演示

定义一个枚举类:

public enum meiju {
p1,p2,p3;
}

定义一个注解类:

public @interface an0 {
}

自定义注解, 比如用到了枚举类和注解类:

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
@Documented
@Inherited
public @interface an1 {
//定义一个注解里的抽象方法,称注解的属性
String mt3() default "111";
int mt4();//基本数据类型
String mt5();//String类型
meiju mt6();//枚举类型
an0 mt7();//注解类型
String[] mt8();//数组类型
}

给注解赋值:

//压制该类全部警告
@SuppressWarnings("all")
public class demo00 {
//表示已经过时
@Deprecated
public void mt1(){
System.out.println("1");
}
//注意如何赋值:基本数据类型\String\枚举\注解\以上类型的数组
@an1(mt4 = 1,mt5 = "1",mt6 = meiju.p1,mt7 = @an0,mt8 = {"1","2","a"})
public void mt2(){
mt1();
}
}

2.4 解析注解

在程序中使用(解析)注解: 用来替换配置文件

步骤:
1. 获取注解定义的位置的对象
2. 获取指定的注解: getAnnotation(class) 方法
3. 调用注解的抽象方法获取配置的属性值

首先自定义一个注解:

//该注解用来描述需要执行的类名和方法名
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface demo01 {
String className();
String methodName();
}

我们要使用的类Annotation.demo00, 假如我们要使用其中的mt1()

//压制该类全部警告
@SuppressWarnings("all")
public class demo00 {
//表示已经过时
@Deprecated
public void mt1(){
System.out.println("1");
}
//注意如何赋值:基本数据类型\String\枚举\注解\以上类型的数组
@an1(mt4 = 1,mt5 = "1",mt6 = meiju.p1,mt7 = @an0,mt8 = {"1","2","a"})
public void mt2(){
mt1();
}
}

最后的具体操作:

@demo01(className = "Annotation.demo00",methodName = "mt1")
public class demo011 {
public static void main(String[] args) throws Exception {
//解析注解
//获取该类字节码文件对象
Class<demo011> cls = demo011.class;
//获取注释对象
demo01 an = cls.getAnnotation(demo01.class);//在内存中生成了该注解接口的子类实现对象
//调用注解对象中定义的抽象方法获取返回值
String className = an.className();
String methodName = an.methodName(); //加载该类进内存
Class<?> aClass = Class.forName(className);
//创建类对象
Object obj = aClass.getDeclaredConstructor().newInstance();
//获取方法对象,传入方法名和参数
Method method1 = aClass.getMethod(methodName);
//执行方法,传入类对象和实参
method1.invoke(obj);
}
}

java基础第12期——反射、注解的更多相关文章

  1. java基础解析系列(六)---深入注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...

  2. JAVA基础知识之JVM-——通过反射查看类信息

    Class实例 当类被加载之后,JVM中就会生成一个Class实例,通过这个实例就可以访问JVM中的这个类.有三种方式可以获取Class对象 使用Class的静态方法forName(完整包名) 调用类 ...

  3. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

  4. 夯实Java基础系列12:深入理解Java中的反射机制

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  5. JAVA基础 (二)反射 深入解析反射机制

    在谈论到反射这个问题时,你是否有例如以下疑问? 不管是在.NET还是Java中反射的原理和机制是一样的,理解了一种还有一种就能够迎刃而解,想要理解反射首先须要了解底层的一些概念和执行.理解了反射有助于 ...

  6. java基础强化——深入理解反射

    目录 1.从Spring容器的核心谈起 2. 反射技术初探 2.1 什么是反射技术 2.2 类结构信息和java对象的映射 3 Class对象的获取及需要注意的地方 4. 运行时反射获取类的结构信息 ...

  7. Java基础(十一)——反射

    一.概述 1.介绍 Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法. 加载完类 ...

  8. 【Java基础】RTTI与反射之Java

    一.引言 很多时候我们的程序可能需要在运行时识别对象和类的信息,比如多态就是基于运行时环境进行动态判断实际引用的对象.在运行时识别对象和类的信息主要有两种方式:1.RTTI,具体是Class对象,它假 ...

  9. java基础篇3之反射

    1.反射的基础 反射的基石---->Class类 java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class 获取字节码对应的实例对象(Class类型) class ...

随机推荐

  1. RabbitMQ (简单集群部署操作)

    RabbitMQ 集群部署 前期准备 第一步:三台linux系统(centos7.3) 主机名(hostname) 网卡ip node1 192.168.137.138 node2 192.168.1 ...

  2. 秒啊,速来get这9个jupyter实用技巧

    1 简介 jupyter notebook与jupyter lab作为广受欢迎的ide,尤其适合开展数据分析相关工作,而掌握它们相关的一些实用技巧,势必会大大提升日常工作效率.而今天我就来给大家介绍9 ...

  3. mac外接键盘HOME,END键问题

    参考: How to Fix the Home and End Buttons for an External Keyboard in Mac mac老用户应该都知道, MAC自带的键盘的 cmd+左 ...

  4. UDP实现多人聊天

    发送端 package com.zy.exercise; import java.net.DatagramPacket; import java.net.DatagramSocket; import ...

  5. 【uva 1312】Cricket Field(算法效率--技巧枚举)

    题意:一个 L*R 的网格里有 N 棵树,要求找一个最大空正方形并输出其左下角坐标和长.(1≤L,R≤10000, 0≤N≤100) 解法:枚举空正方形也就是枚举空矩阵,先要固定一个边,才好继续操作. ...

  6. js面向对象封装级联下拉菜单列表

    本实例开发的级联下拉菜单是根据已有json数据创建的DOM元素.点击文本框后,显示一级菜单.如果菜单中包含子菜单,菜单右侧会有指示箭头.点击菜单之后,会再显示下一级菜单,以此类推.当菜单下无子菜单时, ...

  7. GitHub Actions 支持 "skip ci" 了

    GitHub Actions 支持 "skip ci" 了 Intro GitHub Actions 作为 GitHub 官方的 CI 支持,很多开源项目已经在使用 Actions ...

  8. [Golang]-8 工作池、速率限制、原子计数器、互斥锁

    目录 工作池 速率限制 原子计数器 互斥锁 工作池 在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . func worker(id int, jobs <-chan int, ...

  9. HashMap三百问

    文章目录: 一.JDK1.7之HashMap 二.JDK1.8之HashMap 三.Hashtable JDK1.7之HashMap 1. 定义 HashMap实现了Map接口,继承AbstractM ...

  10. 手工数据结构系列-C语言模拟栈 hdu1022

    这个题我一开始是这么想的.. 爆搜所有可能的出栈序列 然后对输入进行匹配 这样我感觉太慢 然后我们可以想到直接通过入栈序列对出栈序列进行匹配 但是我犯了一个错误..那就是出栈序列一定到入栈序列里找.. ...