前言

上篇文章我们提到了可以使用反射机制破解单例模式。这篇文章我们就来谈一谈什么是反射,反射有什么用,怎么用,怎么实现反射。

概述

Java的反射(reflection)机制:是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键

功能

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理。

java虽然不是动态语言,但是它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。

换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

特点

优点:

  • 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
  • 与Java动态编译相结合,可以实现无比强大的功能

反射机制的功能非常强大,但不能滥用。在能不使用反射完成时,尽量不要使用,原因有以下几点:

缺点:

  • 性能问题。

    Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。我们应该避免在对性能要求很高的程序或经常被执行的代码中使用反射。而且,如何使用反射决定了性能的高低。如果它作为程序中较少运行的部分,性能将不会成为一个问题。
  • 安全限制。

    使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。
  • 程序健壮性。

    反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果。反射代码破坏了Java程序结构的抽象性,所以当程序运行的平台发生变化的时候,由于抽象的逻辑结构不能被识别,代码产生的效果与之前会产生差异。

获取Class对象的三种方式

三种方式

  • Class.forName("全类名") 多用于配置文件时
  • 类名.class 多用于参数传递时
  • 对象.getClass 多用于有对象实例时

==我们创建一个Person类用于实验,分别使用三种方法获取他们的对象,并打印他们的hashCode(),我们会发现他们的hashcode是相同的,证明他们是获取的是相同的,所有统一个字节码文件(*.class)在一次运行中,只会被加载一次。不论通过哪一种方式获取的对象都是同一个。

package hello;

public class ReflectDemo {

    public static void main(String[] args) throws Exception{

        //Class.forName("全类名")
Class<?> aClass = Class.forName("hello.Person");
System.out.println(aClass);
System.out.println(aClass.hashCode());
//类名.clss
Class<Person> personClass = Person.class;
System.out.println(personClass);
System.out.println(personClass.hashCode());
//对象.getClass()
Person person = new Person();
System.out.println(person.getClass());
System.out.println(person.getClass().hashCode()); }
} class Person{ private String name; public Person(){ } public Person(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

Class对象功能

Class对象里面大概有120多个方法,我们不可能全部都记住,也没必要全部都记住,我们只需要记住常用的方法和功能就可以了。

获取功能

  • 获取成员变量

    • Field[] getFields()
    • Field getFields(String name)
    • FIeld[] getDeclaredFields()
    • FIeld getDeclaredField(String name)
  • 获取构造方法

    • Constructor<?>[] getConstructors()
    • Constructor getConstructor(类<?>..., parameterTypes)
    • Constructor getDeclaredConstructor(类<?>..., parameterTypes)
    • Constructor<?>[] getDeclaredConstructors()
  • 获取成员方法

    • Method[] getMethods()
    • Method getMethod(String name,类<?>..., parameterType)
    • Method[] getDeclaredMethods()
    • Method getDeclaredMethod(String name,类<?>...,parameterTypes)
  • 获取类名

    • String getName()

方法 作用
Field[] getFields() 获取public的成员变量名
Field getFields(String name) 获取public的成员变量名,需要指定名称
FIeld[] getDeclaredFields() 获取所有的成员变量,包括private
FIeld getDeclaredField(String name) 获取指定的成员变量,私有的也可以获取,如果要改这个变量的值需要setAccessible(ture)暴力反射
Constructor<?>[] getConstructors() 用于返回一个构造函数对象数组,该数组反映此Class对象表示的类的所有公共构造函数。
Constructor getConstructor(类<?>..., parameterTypes) 获取指定参数的构造方法
Constructor getDeclaredConstructor(类<?>..., parameterTypes) 方法返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类或接口的指定构造函数
Constructor<?>[] getDeclaredConstructors() 用于返回一个Constructor对象数组,该数组指示此Class对象所表示的类定义的构造函数的类型(Constructor可以是public,private,protected或default)
Method[] getMethods() 公共的所有方法
Method getMethod(String name,类<?>..., parameterType) 指定公共的其中的方法,parameterType时一个数组
Method[] getDeclaredMethods() 所有的包括私有的
Method getDeclaredMethod(String name,类<?>...,parameterTypes) 指定的,parameterTypes表示数组
String getName() 获取类名程

package hello;

import com.sun.org.apache.xerces.internal.impl.XMLEntityScanner;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; public class ReflectDemo { public static void main(String[] args) throws Exception{
//获取class对象
Class<Person> personClass = Person.class; //Field[] getFields()
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("******************************");
//FIeld[] getDeclaredFields()
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("******************************");
//Constructor<?>[] getConstructors()
Constructor<Person> constructor = personClass.getConstructor();
System.out.println(constructor);
System.out.println("******************************"); //Method[] getMethods()
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
} System.out.println("******************************");
//String getName()
System.out.println(personClass.getName()); }
} class Person{ public int id;
private String name; public Person(){ } public Person(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

案例

创建一个功能,不改里面的代码,只需要修改配置文件就能调用不同的方法

第一步:创建配置文件,”data.properties"

这个路径一定要写成hello.Preson,写成斜杠会识别不了。

# 这个写全路径类名
className=hello.Preson
# 这个写类里面想要调用的方法
methodName=eat

第二步:具体类"Preson.java"

package hello;

public class Preson {

    public String name;

    public void setName(String name) {
this.name = name;
} public String getName() {
return name;
}
public void eat(){
System.out.println("eat....");
} }

第三步:编写实现代码,名成ReflectDemo.java

package hello;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties; public class ReflectDemo { public static void main(String[] args) throws Exception{ //加载配置文件
//创建properties对象
Properties properties = new Properties();
//加载配置文件,转为一个集合
ClassLoader classLoader = ReflectDemo.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("hello/data.properties");
properties.load(resourceAsStream); //获取配置文件定义的数据
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName"); //加载该类进入内存
Class aClass = Class.forName(className);
Object o = aClass.newInstance();
Method method = aClass.getMethod(methodName);
method.invoke(o);
}
}

第四步:运行,我们只需要修改properties文件里面的类名和方法就能实现不同类不同方法的创建了。

浅析Java反射--Java的更多相关文章

  1. java反射 java动态代理和cglib动态代理的区别

    java反射      https://blog.csdn.net/f2764052703/article/details/89311013 java 动态代理   https://blog.csdn ...

  2. java反射+java泛型,封装BaseDaoUtil类。供应多个不同Dao使用

    当项目是ssh框架时,每一个Action会对应一个Service和一个Dao.但是所有的Ation对应的Dao中的方法是相同的,只是要查的表不一样.由于封装的思想,为了提高代码的重用性.可以使用jav ...

  3. 解析Java反射java.lang.IllegalArgumentException: wrong number of arguments

    项目中遇到的问题 import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; public cl ...

  4. Java反射——java.lang.Class和类的加载

    反射的基础: java.lang.Class Class类的实例对象,用于记录类描述信息. 源码说:represent classes and interfaces in a running Java ...

  5. Java反射——java.lang.Class 类简介

    Java的基本思想之一是万事万物即对象,类也是一种对象.但是类是什么对象呢?Java中的类是java.lang.Class的实例化对象,这被成为类类型. //java.lang.Class类中的的主要 ...

  6. java反射知识

    java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称 ...

  7. java反射机制简单实例

    目录 Java反射 简单实例 @(目录) Java反射 Java语言允许通过程序化的方式间接对Class进行操作.Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通 ...

  8. Java反射及其在Android中的应用学习总结

    一. Java反射机制 Reflection 是Java被视为动态(或准动态)语言的一个关键性质.这个机制同意程序在执行时透过Reflection APIs取得不论什么一个已知名称的class的内部信 ...

  9. java反射(1)

    反射反射,程序员的快乐. 第一次了解反射这个概念是从<<大话设计>>中所了解到的.当时只是对概念的模糊了解,具体对它的机制并不清楚.最近在学习并实践SSH框架,其中Spring ...

随机推荐

  1. Keras学习:试用卷积-训练CIFAR-10数据集

    import numpy as np import cPickle import keras as ks from keras.layers import Dense, Activation, Fla ...

  2. 搭建 Nginx 服务

    今日内容 上一篇测试 c出现问题 web 服务 部署 Nginx 内容详细 上一篇测试 NFS共享文件步骤 - 服务端 [root@backup ~]# yum install nfs-utils r ...

  3. RSA公私钥生成与使用

    参考 KeyStore 简述 Keytool 简述 Certificate Chain (证书链) 简述 详解RSA加密算法

  4. 施耐德NOE77101后门漏洞分析

    固件下载地址: GitHub - ameng929/NOE77101_Firmware 文件目录结构,这里只列出了一些主要的文件信息: ├── bin ├── ftp ├── fw ├── rdt ├ ...

  5. 力扣第二题 大数相加 ,链表在python到底该怎么写?

    但问题在于链表的表示  如何创建一个L3呢 如何用next将他们连接起来呢? 原来是采用 制作链表的形式 l3_pointer.next = ListNode(l1_pointer.val + l2_ ...

  6. 什么是jQuery?

    目录 一:jQuery 1.jQuery介绍 2.jQuery的宗旨 3.有了jQuery那我们还使用BOM与DOM吗? 4.jQuery的优势 5.python与jQuery导入(复习) 6.jQu ...

  7. Django模板的继承与模板的导入

    目录 一:模版的继承 1.什么是模板继承? 2.使用继承流程原理 3.模板继承语法 二:模板的继承使用 1.案例需求 2.总结模板继承 三:模版的导入 1.模板导入 2.模板导入格式 3.模板导入使用 ...

  8. ASP.NET Core 6框架揭秘实例演示[14]:日志的进阶用法

    为了对各种日志框架进行整合,微软创建了一个用来提供统一的日志编程模式的日志框架.<日志的基本编程模式>以实例演示的方式介绍了日志的基本编程模式,现在我们来补充几种"进阶" ...

  9. 【windows 访问控制】四、访问控制项ACE

    访问控制项 具体内容 : https://docs.microsoft.com/zh-cn/windows-hardware/drivers/ifs/access-control-entry   访问 ...

  10. shell脚本创建身份证号

    --作者:飞翔的小胖猪 --创建时间:2021年5月16日 --修改时间:2021年5月16日 说明 运行脚本,用户手动输入信息生成身份证号.该程序的核心在于函数模块化及select的使用. 注意:该 ...