获取类运行时的结构

通过反射获取运行时类的完整结构

Field、Method、Constructor、Superclass、Interface、Annotation

>实现的全部接口

>所继承的父类

>全部的构造器

>全部的方法

>全部的Field

>注解

......

举例:

package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; //获取类的结构
public class Test{ public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException {
Class c1 = Class.forName("test.User"); //获得类的名称
System.out.println(c1.getName()); //获得包名+类名
System.out.println(c1.getSimpleName()); //获得类名 //获得类的属性
System.out.println("=============================");
Field[] fields = c1.getFields(); //只能找到public属性 for(Field f:fields) {
System.out.println("public: "+f);
} fields = c1.getDeclaredFields(); //找到全部属性 for(Field f:fields) {
System.out.println(f);
} //获得指定属性的值
Field f = c1.getDeclaredField("name");
System.out.println(f); //获得所有的方法
System.out.println("=============================");
Method[] methods = c1.getMethods(); //只能获取public
for(Method m:methods) {
System.out.println("public: "+m);
} methods = c1.getDeclaredMethods(); //获取所有
for(Method m:methods) {
System.out.println(m);
} //获取指定的方法
Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName",String.class); System.out.println(getName+"\r\n"+setName); //获取构造方法
System.out.println("=============================");
Constructor[] constructor = c1.getConstructors();
for(Constructor c:constructor) {
System.out.println("public: "+c);
} constructor = c1.getDeclaredConstructors();
for(Constructor c:constructor) {
System.out.println(c);
} //获取指定构造器
Constructor c = c1.getConstructor(int.class,String.class,int.class);
System.out.println(c);
} } class User{
private int id;
private String name;
private int age;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
} public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}

结果自行测试!

小结:

1.在实际的开发中,取得类的信息的操作代码并不会经常开发。

2.一定要熟悉java.lang.reflect包的作用、反射机制等。

3.如何取得属性、方法、构造器的名称,修饰符等。

有了Class对象,能做什么?

>创建类的对象,通过Class对象的newInstance()方法.

  1.类必须有一个无参构造器。

  2.类的构造器的访问权限必须足够。

例子(3-1):

package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; //通过反射动态创建对象
public class Test{ public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class c1 = Class.forName("test.User"); //构造一个对象
User user = (User)c1.newInstance(); //本质上调用了无参构造器 System.out.println(user);
} } class User{
private int id;
private String name;
private int age;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
} public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}

打印结果:

 Tip:说明调用无参构造器创建了一个User对象。

思考:难道没有无参构造器就不能创建对象了吗?

答案:可以,只要在操作的时候明确的调用类中的构造器,并将参数传递进去后,就能够实例化。

  步骤如下:

      1.通过Class类的getDeclaredConstructor(Class ..ParmaterTypes)取得本类的指定形参类型的构造器。

      2.向构造器的形参中传递一个数组对象进去,里边包含了构造器中所需的各个参数。

      3.通过Constructor的newInstance()方法去实例化对象。

举例(修改3-1的main方法):

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
Class c1 = Class.forName("test.User"); //通过有参构造器构造一个User对象
Constructor constructor = c1.getDeclaredConstructor(int.class,String.class,int.class); User user = (User)constructor.newInstance(1,"hgqin",20); System.out.println(user); }

运行结果:

通过反射调用类中的方法,通过Method完成

  1.通过Class类的getDeclaredMethod(String name,Class ...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。

  2.之后使用Object invoke(Object obj,Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。

举例(修改3-1的main方法):

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
Class c1 = Class.forName("test.User"); User user = (User)c1.newInstance(); //通过反射获取一个方法
Method method = c1.getDeclaredMethod("setName", String.class); //执行方法(invoke:激活)
//(对象,值)
method.invoke(user, "Hgqin"); System.out.print(user.getName()); }

执行结果:

通过反射操作属性

setAccessible方法:

举例(修改3-1的main方法):

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException{
Class c1 = Class.forName("test.User"); User user = (User)c1.newInstance(); //通过反射操作属性 Field name = c1.getDeclaredField("name"); //不能直接操作私有属性,我们需要关闭权限检测
name.setAccessible(true); //关闭安全检测
name.set(user, "hgqin"); System.out.println(user.getName()); }

执行结果:

性能比较

>通过比较普通方法以及反射方法 执行相同的方法所需要的时间,比较性能。大致结果为(普通方法>反射方法(关闭安全检查)>反射方法(不关闭安全检查))

package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; //性能分析
public class Test{ public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
test01();
test02();
test03(); } public static void test01() {
User user = new User(); Long beginTime = System.currentTimeMillis(); for(int i=0;i<1000000000;i++) {
user.getName();
} Long endTime = System.currentTimeMillis(); System.out.println("普通方法执行10亿次需要时间:"+(endTime-beginTime));
} public static void test02() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
User user = new User(); Class c1 = user.getClass(); Method m = c1.getDeclaredMethod("getName", null); Long beginTime = System.currentTimeMillis(); for(int i=0;i<1000000000;i++) {
m.invoke(user, null);
} Long endTime = System.currentTimeMillis(); System.out.println("反射方式执行10亿次需要时间:"+(endTime-beginTime));
} public static void test03() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
User user = new User(); Class c1 = user.getClass(); Method m = c1.getDeclaredMethod("getName", null); Long beginTime = System.currentTimeMillis(); m.setAccessible(true); for(int i=0;i<1000000000;i++) {
m.invoke(user, null);
} Long endTime = System.currentTimeMillis(); System.out.println("关闭检测执行10亿次需要时间:"+(endTime-beginTime));
}
} class User{
private int id;
private String name;
private int age;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
} public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}

打印结果:

反射操作泛型(了解即可)

>Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型的转换问题,但是一旦编译完成,所有和泛型有关的类型全部擦除。

>为了通过反射操作这些类型,Java新增了ParameterizedType、GenericArrayType、TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。

  ParameterizedType:表示一种参数化类型,比如Collection<String>。

  CenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型。

  WildcardType:代表一种通配符类型的表达式。

举例:

package test;

import java.lang.reflect.*;
import java.util.*; //通过反射获取泛型
public class Test{ public static void main(String[] args) throws NoSuchMethodException, SecurityException {
System.out.println("通过反射获取泛型类型");
//test01
Method method = Test.class.getMethod("test01",Map.class,List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes) {
System.out.println("#"+genericParameterType);
if(genericParameterType instanceof ParameterizedType) {
Type[] types = ((ParameterizedType)genericParameterType).getActualTypeArguments();
for(Type type : types) {
System.out.println(type);
}
}
}
//test02
method = Test.class.getMethod("test02",null);
Type genericReturnType = method.getGenericReturnType();
System.out.println("#"+genericReturnType);
if(genericReturnType instanceof ParameterizedType) {
Type[] types = ((ParameterizedType)genericReturnType).getActualTypeArguments();
for(Type type : types) {
System.out.println(type);
}
}
} public void test01(Map<String,User> map,List<User> list) {
System.out.println("test01");
} public Map<String,User> test02() {
System.out.println("test02");
return null;
}
} class User{
private int id;
private String name;
private int age; public User() {
super();
// TODO Auto-generated constructor stub
} public User(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}

打印结果:

Java高级特性——反射机制(第三篇)的更多相关文章

  1. Java高级特性——反射机制(第二篇)

    在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...

  2. Java高级特性——反射机制(第一篇)

    ——何为动态语言,何为静态语言?(学习反射知识前,需要了解动态语言和静态语言) 动态语言 >是一类在运行时可以改变其结构的语言,例如新的函数.对象.甚至是代码可以被引进,已有的函数可以被删除或者 ...

  3. Java高级特性——反射机制(完结)——反射与注解

    按照我们的学习进度,在前边我们讲过什么是注解以及注解如何定义,如果忘了,可以先回顾一下https://www.cnblogs.com/hgqin/p/13462051.html. 在学习反射和注解前, ...

  4. Java高级特性——反射

    感谢原文作者:peter_RD_nj 原文链接:https://www.jianshu.com/p/9be58ee20dee 注意:同一个类在JVM中只存在一份字节码对象 概述 定义 JAVA反射机制 ...

  5. JAVA高级特性反射和注解

    反射: 枚举反射泛型注解.html34.3 KB 反射, 主要是指通过类加载, 动态的访问, 检测和修改类本身状态或行为的一种能力, 并能根据自身行为的状态和结果, 调整或修改应用所描述行为的状态和相 ...

  6. Java高级特性—反射和动态代理

    1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由 ...

  7. Java高级特性 第5节 序列化和、反射机制

    一.序列化 1.序列化概述 在实际开发中,经常需要将对象的信息保存到磁盘中便于检索,但通过前面输入输出流的方法逐一对对象的属性信息进行操作,很繁琐并容易出错,而序列化提供了轻松解决这个问题的快捷方法. ...

  8. Java的反射机制(应用篇)

    Java的的反射机制,是一个很难但却比较有用的概念.反射机制经常出现在框架设计中,大神说:反射是框架设计的灵魂,也就是说要想看懂框架的源代码,必须得掌握反射机制. 作为初学者的我,觉得至少应该掌握它日 ...

  9. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

随机推荐

  1. P6222 「简单题」加强版 莫比乌斯反演 线性筛积性函数

    LINK:简单题 以前写过弱化版的 不过那个实现过于垃圾 少预处理了一个东西. 这里写一个实现比较精细了. 最后可推出式子:\(\sum_{T=1}^nsum(\frac{n}{T})\sum_{x| ...

  2. P3250 [HNOI2016]网络

    LINK:网络 一棵树 每次添加一条路径 或者删除之前的一条路径 或询问除了不经过某个点之外剩下的最大值. 一个显然的思路 对于一条路径的权值我们直接把权值塞上去 标记永久化一下即可. 考虑如何求答案 ...

  3. Python selenium 三种消息框处理和浏览器(页面跳转)句柄处理

    1. alert: 警告框,只是一个提示信息,只有一个确定按钮,起提示用户的作用: 2.confirm: 确认框,确定和取消按钮会带来不同的结果.点击确定会执行操作,点击取消按钮会取消操作: 3.pr ...

  4. 【NOIP2016】天天爱跑步 题解(LCA+桶+树上差分)

    题目链接 题目大意:给定一颗含有$n$个结点的树,每个结点有一个权值$w$.给定$m$条路径,如果一个点与路径的起点的距离恰好为$w$,那么$ans[i]++$.求所有结点的ans. 题目分析 暴力的 ...

  5. Linux常用命令之用户权限管理chmod、chown、chgrp、umask命令讲解

    这节课我们重点来学习权限管理命令,说到权限大家可能第一时间能想到的就是读.写.执行 rwx 三种权限,在正式讲解权限命令之前,先简单的介绍一下rwx权限对于文件和目录的不同含义. 权限字符 权限 对文 ...

  6. Android 的OkHttp(发送网络请求)

    今天讲的是和HttpURLConnection差不多的OkHttp; 先把网站献上: 官网介绍okhttp的: https://square.github.io/okhttp/ 下载postman的: ...

  7. IdentityServer4 (3) 授权码模式(Authorization Code)

    写在前面 1.源码(.Net Core 2.2) git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git 2.相关章节 2.1. ...

  8. APP常用控件学习理解

    1.TextView 示例: layout_width指的是文本的所占宽度(不一定填充满),layout_height指的是文本所占高(不一定填充满),warp_coonent :包裹文本宽度 mat ...

  9. docker安装gitlab并部署CICD

    摘要 本文主要实现了在docker下安装gitlab,将gitlab绑定在宿主机的180端口,将gitlab的clone的URL添加指定端口号:部署了CI/CD,并公布了测试项目. 安装docker[ ...

  10. object detection 总结

    1.基础 自己对于YOLOV1,2,3都比较熟悉. RCNN也比较熟悉.这个是自己目前掌握的基础2.第一步 看一下2019年的井喷的anchor free的网络3.第二步 看一下以往,引用多的网路4. ...