java基础第12期——反射、注解
一. 反射
反射: 将类的各个组成部分封装为其他对象.
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期——反射、注解的更多相关文章
- java基础解析系列(六)---深入注解原理及使用
java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...
- JAVA基础知识之JVM-——通过反射查看类信息
Class实例 当类被加载之后,JVM中就会生成一个Class实例,通过这个实例就可以访问JVM中的这个类.有三种方式可以获取Class对象 使用Class的静态方法forName(完整包名) 调用类 ...
- Java基础教程(12)--深入理解类
一.方法的返回值 当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...
- 夯实Java基础系列12:深入理解Java中的反射机制
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- JAVA基础 (二)反射 深入解析反射机制
在谈论到反射这个问题时,你是否有例如以下疑问? 不管是在.NET还是Java中反射的原理和机制是一样的,理解了一种还有一种就能够迎刃而解,想要理解反射首先须要了解底层的一些概念和执行.理解了反射有助于 ...
- java基础强化——深入理解反射
目录 1.从Spring容器的核心谈起 2. 反射技术初探 2.1 什么是反射技术 2.2 类结构信息和java对象的映射 3 Class对象的获取及需要注意的地方 4. 运行时反射获取类的结构信息 ...
- Java基础(十一)——反射
一.概述 1.介绍 Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法. 加载完类 ...
- 【Java基础】RTTI与反射之Java
一.引言 很多时候我们的程序可能需要在运行时识别对象和类的信息,比如多态就是基于运行时环境进行动态判断实际引用的对象.在运行时识别对象和类的信息主要有两种方式:1.RTTI,具体是Class对象,它假 ...
- java基础篇3之反射
1.反射的基础 反射的基石---->Class类 java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class 获取字节码对应的实例对象(Class类型) class ...
随机推荐
- Go语言学习笔记(2)——零散的话题(反射)
这部分是<Go语言编程>这本书的第9章的内容.书中给该章节的定位是一个文章集,其包含了一些Go语言中比较少涉及,或是比较深入的讨论的内容.因为第一节就是反射,而反射在我看来是比较重要的内容 ...
- springBoot之 spring-boot-starter-parent 引入详解
springBoot中引入 <parent> <groupId>org.springframework.boot</groupId> <artifactId& ...
- SOS DP学习笔记
Sum over Subsets(SOS) DP 一.引入 给出一个长度为\(2^n\)的数组\(A\),对于每一个\(mask< 2^n\)要求计算出\(f[mask]=\sum_{sub\i ...
- 【bzoj 4455】小星星(树型DP+容斥原理+dfs建树和计算的2种方式)
题意:给一个n个点的图和一个n个点的树,求图和树上的点一一对应的方案数.(N<=17) 解法:1.在树的结构上进行tree DP,f[i][j]表示树上点 i 对应图上点 j 时,这个点所在子树 ...
- Codeforces Round #544 (Div. 3) E. K Balanced Teams (DP)
题意:有\(n\)个人,每个人的能力值是\(a_i\),现在你想将这些人分成\(k\)组(没必要全选),但是每组中最高水平和最低水平的人的能力差值必须\(\le 5\),问最多能选多少人. 题解:想了 ...
- hdu5289 Assignment
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission ...
- Proud Merchants HDU - 3466 01背包&&贪心
最近,我去了一个古老的国家.在很长一段时间里,它是世界上最富有.最强大的王国.结果,这个国家的人民仍然非常自豪,即使他们的国家不再那么富有.商人是最典型的,他们每个人只卖一件商品,价格是Pi,但是如果 ...
- H5网页应用打包安卓App (全网最详细教程)
img { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important } .red { color: rgba(255, 0, 0, 1) } ...
- MongoDB 部署 & 基础命令
MongoDB 官方文档 MongoDB 介绍 Mongodb 由 C++ 语言编写的,是一个基于分布式文件存储的开源数据库系统. 是专为可扩展性,高性能和高可用性而设计的数据库, 是非关系型数据库中 ...
- Redis 管理命令
INFO 命令 # 查看redis相关信息 127.0.0.1:6379> info # 服务端信息 # Server # 版本号 redis_version:3.2.12 # redis版本控 ...