Java反射01

1.反射(reflection)机制

1.1反射机制问题

一个需求引出反射

请看下面问题:

  1. 根据配置文件 re.properties 指定信息,创建Cat对象并调用方法hi
classfullpath=li.reflection.Cat
method=hi

使用现有的技术,你能做的到吗?

  1. 这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码的情况下来控制程序,也符合设计模式的ocp原则(开闭原则)

    开闭原则:不修改源码,扩展功能

例子:

re.properties:

classfullpath=li.reflection.Cat
method=cry

Cat:

package li.reflection;

public class Cat {
private String name = "招财猫"; public void hi() {
System.out.println("hi " + name);
} public void cry() {
System.out.println(name + " cry");
}
}

ReflectionQuestion:

package li.reflection;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties; public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { //根据配置文件 re.properties 指定信息,创建Cat对象 并调用方法hi //1.传统方法 new 对象 -->调用方法
//Cat cat = new Cat();
//cat.hi(); //2.尝试使用读取文件的方法
//2.1使用properties类,可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpatch = properties.get("classfullpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classfullpath" + classfullpatch);
System.out.println("method" + methodName);
//2.2创建对象
//使用传统的方法行不通 //3.使用反射机制解决
//3.1加载类,返回一个Class类型的对象cls(这里的Class就是一个类,他的类名就叫Class)
Class cls = Class.forName(classfullpatch); //3.2通过cls得到加载的类 li.reflection.Cat 的一个对象实例
Object o = cls.newInstance();
System.out.println("o的运行类型=" + o.getClass());//o的运行类型 //3.3通过 cls 得你加载的类 li.reflection.Cat 的methodName"hi" 的方法对象
// 即:在反射机制中,可以把方法视为一个对象(万物皆对象)
Method method1 = cls.getMethod(methodName);
//3.4通过 method1 调用方法:即通过方法对象来实现调用方法
System.out.println("========");
method1.invoke(o);//传统方法: 对象.方法() , 反射机制:方法.invoke(对象) //意义在与反射机制可以通过不求该源码就完成功能的拓展
/**
* 例如,在Cat类中有两个方法,hi()和cry(),现在要求将调用用的hi方法改为调用cry方法,
* 这时候只需要在配置文件re.properties中修改引用的方法名即可
* 不需像想传统方法一样,需要在源码中修改
*/
}
}

1.2反射机制

1.2.1Java Reflection

  1. 反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能够操作对象的属性以及方法。反射在设计模式和框架底层都会用到
  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到了的结构,所以形象地称之为:反射

例如:一个Person类型的实例对象叫 p

则 p 对象 - -> 类型 Person类

Class 对象 cls --> 类型 Class 类(这个类的名字就叫Class)

1.2.2Java反射机制原理图

  • Java反射机制可以完成

    1. 在运行时判断任意一个对象所属的类
    2. 在运行时构造任意一个类的对象
    3. 在运行时得到任意一个类所具有的成员变量和方法
    4. 在运行时调用任意一个对象的成员变量和方法
    5. 生成动态代理

1.2.3反射相关类

反射相关的主要类:

  1. java.lang.Class:代表一个类,Class对象表示某个类加载过后在堆中的对象
  2. java.lang.reflect.Method:表示类的方法(Method对象表示某个类的方法)
  3. java.lang.reflect.Field:表示类的成员变量(Field对象表示某个类的成员变量)
  4. java.lang.reflect.Constructor:表示类的构造方法(Constructor对象表示某个类的构造器)

​ 这些类在 java.lang.reflect

例子:

Cat:

package li.reflection;

public class Cat {
private String name = "招财猫";
public int age = 10; public Cat() {
}//无参构造器 public Cat(String name) {
this.name = name;
} public void hi() {
System.out.println("hi " + name);
} public void cry() {
System.out.println(name + " cry");
}
}

re.properties:

classfullpath=li.reflection.Cat
method=hi

Reflection01:

package li.reflection;

import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties; public class Reflection01 {
public static void main(String[] args) throws Exception { //使用properties类,读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpatch = properties.get("classfullpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classfullpath" + classfullpatch);
System.out.println("method" + methodName); //反射机制
//1.加载类,返回一个Class类型的对象cls(这里的Class就是一个类,他的类名就叫Class)
Class cls = Class.forName(classfullpatch); //通过cls得到加载的类 li.reflection.Cat 的一个对象实例
Object o = cls.newInstance();
System.out.println("o的运行类型=" + o.getClass());//o的运行类型 //2.通过 cls得到加载的类 li.reflection.Cat 的methodName"hi" 的方法对象
// 即:在反射机制中,可以把方法视为一个对象(万物皆对象)
Method method1 = cls.getMethod(methodName);
//通过 method1 调用方法:即通过方法对象来实现调用方法
System.out.println("========");
method1.invoke(o);//传统方法: 对象.方法() , 反射机制:方法.invoke(对象) //3.java.lang.reflect.Field:表示类的成员变量(Field对象表示某个类的成员变量)
//得到name字段
//getField不能得到私有的属性
Field nameField = cls.getField("age");
System.out.println(nameField.get(o));//传统方法:对象.成员变量 , 反射:成员变量的对象.get(对象) //4.java.lang.reflect.Constructor:表示类的构造方法(Constructor对象表示某个类的构造器)
Constructor constructor1 = cls.getConstructor();//()中可以指定构造器的类型,这里返回无参构造器
System.out.println(constructor1);//Cat() Constructor constructor2 = cls.getConstructor(String.class);//这里传入的String.class 就是String类的Class对象
System.out.println(constructor2);//Cat(String name)
}
}

1.2.4反射优点和缺点

  1. 优点:可以动态地创建和使用对象(也是底层框架的核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
  2. 缺点:使用反射机制基本是解释执行,对执行速度有影响
  • 调用反射优化-关闭访问检查
  1. Method和Field、Constructor对象都有setAccessible()方法
  2. setAccessible作用是启动和禁用服务安全检查的开关
  3. 参数值为true表示 反射的对象在使用时 取消访问检查,提高反射效率。参数值为false则表示反射的对象执行访问检查

例子:测试反射调用的性能 和优化方案

package li.reflection;

import java.lang.reflect.Method;

//测试反射调用的性能 和 优化方案
public class Reflection02 {
public static void main(String[] args) throws Exception {
m1();
m2();
m3();
} //传统方法,调用hi
public static void m1() {
Cat cat = new Cat();
long start = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("m1() 耗时=" + (end - start));
} //反射机制调用hi
public static void m2() throws Exception {
//拿到Cat类的Class对象
Class cls = Class.forName("li.reflection.Cat");//这里为了方便,就不读文件了
//构造Cat类的对象
Object o = cls.newInstance();
//得到Cat类的成员方法
Method hi = cls.getMethod("hi"); long start = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);//反射机制调用方法
}
long end = System.currentTimeMillis();
System.out.println("m2() 耗时=" + (end - start));
} //反射调用优化
public static void m3() throws Exception {
//拿到Cat类的Class对象
Class cls = Class.forName("li.reflection.Cat");//这里为了方便,就不读文件了
//构造Cat类的对象
Object o = cls.newInstance();
//得到Cat类的成员方法
Method hi = cls.getMethod("hi");
hi.setAccessible(true);//在反射调用方法时,取消访问检查 long start = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);//反射机制调用方法
}
long end = System.currentTimeMillis();
System.out.println("m3()反射调用优化耗时=" + (end - start));
}
}

2.Class类

2.1基本介绍

  1. Class类也是类,因此也继承Object类

  2. Class类对象不是new出来的,而是系统创建的

  3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次

  4. 每个类的实例都会记得自己是由哪个Class实例所生成

  5. 通过Class对象可以得到一个类的完整结构(通过一系列API)

  6. Class对象是存放在堆的

  7. 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等)

    当我们加载完类之后,除了会在堆里生成一个Class类对象,还会在方法区生成一个类的字节码二进制数据(元数据)

例子:

package li.reflection.class_;

import li.reflection.Cat;

//对Class类的特点的梳理
public class Class01 {
public static void main(String[] args) throws ClassNotFoundException { //1.Class类对象不是new出来的,而是系统创建的
//1.1.传统的 new对象
/**通过ClassLoader类中的loadClass方法:
* public Class<?> loadClass(String name) throws ClassNotFoundException {
* return loadClass(name, false);
* }
*/
//Cat cat = new Cat(); //1.2反射的方式
/**在这里debug,需要先将上面的Cat cat = new Cat();注释掉,因为同一个类只加载一次,否则看不到loadClass方法
* (这里也验证了:3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次)
* 仍然是通过 ClassLoader类的loadClass方法加载 Cat类的 Class对象
* public Class<?> loadClass(String name) throws ClassNotFoundException {
* return loadClass(name, false);
* }
*/
Class cls1 = Class.forName("li.reflection.Cat"); //2.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
Class cls2 = Class.forName("li.reflection.Cat");
//这里输出的hashCode是相同的,说明cls1和cls2是同一个Class类对象
System.out.println(cls1.hashCode());//1554874502
System.out.println(cls2.hashCode());//1554874502
}
}

Class类对象不是new出来的,而是系统创建的:

  1. Cat cat = new Cat();处打上断点,点击force step into,可以看到

  1. 注释Cat cat = new Cat();,在Class cls1 = Class.forName("li.reflection.Cat");处打上断点,可以看到 仍然是通过 ClassLoader类加载 Cat类的 Class对

2.2Class类常用方法

public static Class<?> forName(String className)//传入完整的“包.类”名称实例化Class对象
public Constructor[] getContructors() //得到一个类的全部的构造方法
public Field[] getDeclaredFields()//得到本类中单独定义的全部属性
public Field[] getFields()//得到本类继承而来的全部属性
public Method[] getMethods()//得到一个类的全部方法
public Method getMethod(String name,Class..parameterType)//返回一个Method对象,并设置一个方法中的所有参数类型
public Class[] getInterfaces() //得到一个类中锁实现的全部接口
public String getName() //得到一个类完整的“包.类”名称
public Package getPackage() //得到一个类的包 public Class getSuperclass() //得到一个类的父类
public Object newInstance() //根据Class定义的类实例化对象
public Class<?> getComponentType() //返回表示数组类型的Class
public boolean isArray() //判断此class是否是一个数组

day42-反射01的更多相关文章

  1. 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息

    0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...

  2. Java反射01 : 概念、入门示例、用途及注意事项

    1.Java反射定义 本文转载自:https://blog.csdn.net/hanchao5272/article/details/79360452 官方定义如下: Reflection enabl ...

  3. 03.反射--01【反射机制】【反射的应用场景】【Tomcat服务器】

    https://blog.csdn.net/benjaminzhang666/article/details/9408611 https://blog.csdn.net/benjaminzhang66 ...

  4. 编程从入门到提高,然后放弃再跑路(Java)

    1.Java入门篇 1.1 基础入门和面向对象 1.1.1 编程基础 [01] Java语言的基本认识 [02] 类和对象 [03] 类的结构和创建对象 [04] 包和访问权限修饰符 [05] 利用p ...

  5. 编程从入门到放弃(Java)

      1.Java入门篇 1.1 基础入门和面向对象 1.1.1 编程基础 [01] Java语言的基本认识 [02] 类和对象 [03] 类的结构和创建对象 [04] 包和访问权限修饰符 [05] 利 ...

  6. java 反射机制01

    // */ // ]]>   java反射机制01 Table of Contents 1 反射机制 2 反射成员 2.1 java.lang.Class 2.2 Constructor 2.3 ...

  7. java反射机制入门01

    java反射机制入门是我从极客学院的视频中学习的. 1.反射机制背景概述 反射(Reflection)是java被视为动态(或准动态)语言的一个关键性质.反射机制指的是程序在运行时能够获取任何类的内部 ...

  8. C#反射 入门学习 01

    前言     获取方法的相关信息的两种形式 反射是一种允许用户获得类信息的C#功能,Type对象映射它代表的底层对象: 在.Net 中, 一旦获得了Type对象,就可以使用GetMethods()方法 ...

  9. java黑魔法-反射机制-01

    在java的帮助文档中,java.lang包中有一个Class类,注意这里的"C“是大写,所以这个不是表示类的声明,而是一个真正的类.在java的帮助文档中,这样定义的Class类: pub ...

随机推荐

  1. 01 Mybatis框架添加英雄步骤

    客户端发出请求的几种方式 通过浏览器的地址栏中发出请求 通过html页面中的超链接发出请求 通过html页面中的form表单发出请求 通过前端框架发出请求 工程中使用数据库需要做的几件事: 在pom. ...

  2. 【Kaggle】如何有效避免OOM(out of memory)和漫长的炼丹过程

    本文介绍一些避免transformers的OOM以及训练等流程太漫长的方法,主要参考了kaggle notebook Optimization approaches for Transformers ...

  3. python操作ini文件

    简介 ini文件作为常见的配置文件,因此需要对ini文件做处理,此处使用configparser模块,本文介绍以下ini文件常用的处理方式. 需要读取的ini文件 如下文件,[ ]包含的称为secti ...

  4. Linux—系统基础一

    Linux系统基础(一) Linux的基本原则: 由目的单一的小程序组成,组合小程序完成复杂任务: 一切皆文件: 配置文件保存为纯文本格式. 1.shell 1.1 shell简介 Shell俗称壳( ...

  5. 【系统设计】S3 对象存储

    在本文中,我们设计了一个类似于 Amazon Simple Storage Service (S3) 的对象存储服务.S3 是 Amazon Web Services (AWS) 提供的一项服务, 它 ...

  6. Win10使用fvm管理多个Flutter版本

    Win10使用fvm管理多个Flutter版本 参考:https://blog.csdn.net/PyMuma/article/details/115298645 1.升级Flutter 由于现在的f ...

  7. java学习第二天面向对象.day07

    变量的生命周期 成员变量:存储在堆内存中,随着对象的销毁而销毁 局部变量:存储在栈内存中,随着所定义方法的调用结束而销毁 局部变量存储在方法中,每次调用方法都会在栈空间开辟一块内存空间--栈帧,方法调 ...

  8. monodepth2学习1-原理介绍

    monodepth2介绍 monodepth2是在2019年CVPR会议上提出的一种三维重建算法,monodepth2是基于monodepth进行了改进,采用的是基于自监督的神经网络,提出了一下三点优 ...

  9. Python自动化测试之文件操作

    1.读.写.追加文件 读:打开文件  r    读写:r+ 写:w 可写不可读  清空原文件   写读:w+ 清空文件 追加:a+  可以读写,文件不存在自动创建 练习读txt文件类容: #-*- c ...

  10. STC8H开发(十六): GPIO驱动XL2400无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...