反射概念:

java反射机制是在运行状态中,对于任意一个类,都能知道所有属性和方法

对于任意一个对象都能调用它的任意一个方法和属性,这种动态获取和调用的功能称为java的反射机制

实际作用:

已经完成一个java程序,但是想再添加新功能,又不能修改源码,这时候就用到反射机制了

获取class文件的三种方式:

简单地自定义一个Person类:

package demo;

public class Person {
public String name;
private int age; public Person() {
} public Person(String name, int age) {
this.name = name;
this.age = age;
} private Person(int age, String name) {
this.name = name;
this.age = age;
} public void eat() {
System.out.println("人吃饭");
} public void sleep(String s, int a, double d) {
System.out.println("人在睡觉" + s + "....." + a + "....." + d);
} private void playGame() {
System.out.println("人在打游戏");
} public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
} 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;
} }

获取person类class文件(三种方法本质上获取的是同一个对象):

package demo;

public class ReflectDemo {
public static void main(String[] args) {
//1.对象获取
Person p = new Person();
Class c = p.getClass();
System.out.println(c);
//2.类名获取
Class c1 = Person.class;
System.out.println(c1); System.out.println(c==c1);//true
System.out.println(c.equals(c1));//true
//只存在一个class文件,两种方式都是获得同一个对象 //3.Class类的静态方法,参数注意带着包名防止重名
try {
Class c2 = Class.forName("demo.Person");
System.out.println(c2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

反射获取空参构造方法:

package demo;

import java.lang.reflect.Constructor;

public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
Class c = Class.forName("demo.Person");
function1(c);
function2(c);
} private static void function1(Class c) {
// 获得所有公共权限(public)的构造器
Constructor[] cons = c.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
// 输出:
// public demo.Person(java.lang.String,int)
// public demo.Person()
}
} public static void function2(Class c) {
// 获取空参构造器并执行(toString方法)
try {
Constructor con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
// 输出:Person [name=null, age=0]
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

反射获取有参构造方法:

package demo;

import java.lang.reflect.Constructor;

public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class c = Class.forName("demo.Person");
Constructor con = c.getConstructor(String.class, int.class);
System.out.println(con);
Object object = con.newInstance("张三", 20);
System.out.println(object);
}
}
/*输出:
public demo.Person(java.lang.String,int)
Person [name=张三, age=20]
*/

发现上边的方式代码量偏大,快捷一些的方式:

前提:被反射的类,必须具有空参构造方法,且构造方法权限必须是public

package demo;

public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class c = Class.forName("demo.Person");
// Class类中定义方法, T newInstance() 直接创建被反射类的对象实例
Object obj = c.newInstance();
System.out.println(obj);
}
}

反射获取私有构造方法(日常开发不建议使用,这种方法了解即可):

package demo;

import java.lang.reflect.Constructor;

public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class c = Class.forName("demo.Person");
// 获取所有构造方法(包括私有的)
// Constructor[] cons = c.getDeclaredConstructors();
Constructor con = c.getDeclaredConstructor(int.class, String.class);
con.setAccessible(true);// 取消权限,破坏了封装性
Object object = con.newInstance(18, "张三");
System.out.println(object);
// Person [name=张三, age=18]
}
}

反射获取类的成员变量并修改:

package demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field; public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class c = Class.forName("demo.Person"); // 获得所有public成员
Field[] fields = c.getFields();
// 获得所有成员变量
Field[] fields2 = c.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
} // 获取指定成员变量并修改
Field field = c.getField("name");
Object object = c.newInstance();
field.set(object, "张三");
System.out.println(object);
// 输出:Person [name=张三, age=0]
}
}

反射获取成员方法并执行:

package demo;

import java.lang.reflect.Method;

public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("demo.Person");
// 获得所有public方法
/*
* Method[] methods = c1.getMethods();
* for(Method method:methods){
* System.out.println(method); }
*/ // 获取指定方法运行(空参)
Method method = c1.getMethod("eat");
Object obj = c1.newInstance();
method.invoke(obj);
// 输出:人吃饭 // 有参
Method method1 = c1.getMethod("sleep", String.class, int.class, double.class);
Object obj1 = c1.newInstance();
method1.invoke(obj1, "休息", 10, 10.11);
// 输出:人在睡觉休息.....10.....10.11 // 可以利用前面提到的方法暴力运行私有方法
}
}

反射的泛型擦除:

package demo;

import java.lang.reflect.Method;
import java.util.ArrayList; public class ReflectTest {
public static void main(String[] args) throws Exception {
ArrayList<String> array = new ArrayList<String>();
// 通常添加方式
array.add("a");
array.add("1"); Class class1 = array.getClass();
Method method = class1.getMethod("add", Object.class);
method.invoke(array, 100);
method.invoke(array, 666.666);
method.invoke(array, 0.1);
System.out.println(array);
// 输出:[a, 1, 100, 666.666, 0.1]
}
}

反射实现通过配置文件运行:

有时候想改源码,但是不能改源码,可以这样做:

自定义三个类:

package demo;

public class Person {
public void eat(){
System.out.println("人在吃饭");
}
}
package demo;

public class Student {
public void study(){
System.out.println("学生在学习");
}
}
package demo;
public class Worker {
public void job(){
System.out.println("上班族在工作");
}
}

配置文件:config.properties

#className=demo.Student
#methodName=study
className=demo.Person
methodName=eat
#className=demo.Worker
#methodName=job

测试类:

package demo;

import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties; /*
* 调用Person方法,调用Student方法,调用Worker方法
* 类不清楚,方法也不清楚
* 通过配置文件实现此功能
* 运行的类名和方法名字,以键值对的形式,写在文本中
* 运行哪个类,读取配置文件即可
* 实现步骤:
* 1. 准备配置文件,键值对
* 2. IO流读取配置文件 Reader
* 3. 文件中的键值对存储到集合中 Properties
* 集合保存的键值对,就是类名和方法名
* 4. 反射获取指定类的class文件对象
* 5. class文件对象,获取指定的方法
* 6. 运行方法
*/
public class Test {
public static void main(String[] args) throws Exception{
//IO流读取配置文件
FileReader r = new FileReader("config.properties");
//创建集合对象
Properties pro = new Properties();
//调用集合方法load,传递流对象
pro.load(r);
r.close();
//通过键获取值
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//反射获取指定类的class文件对象
Class c = Class.forName(className);
Object obj = c.newInstance();
//获取指定的方法名
Method method = c.getMethod(methodName);
method.invoke(obj);
}
}

Java学习笔记54(反射详解)的更多相关文章

  1. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  2. java学习笔记:反射

    1.什么是反射? Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法 2.反射相关的 ...

  3. Struts2学习笔记(二)——配置详解

    1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...

  4. Struts2学习笔记二 配置详解

    Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...

  5. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

  6. [C#] 类型学习笔记二:详解对象之间的比较

    继上一篇对象类型后,这里我们一起探讨相等的判定. 相等判断有关的4个方法 CLR中,和相等有关系的方法有这么4种: (1) 最常见的 == 运算符 (2) Object的静态方法ReferenceEq ...

  7. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  8. Android学习笔记之Activity详解

    1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...

  9. vue.js学习笔记(二)——vue-router详解

    vue-router详解 原文链接:www.jianshu.com 一.前言 要学习vue-router就要先知道这里的路由是什么?为什么我们不能像原来一样直接用<a></a> ...

  10. linux命令学习笔记-eval命令详解

    功能说明:重新运算求出参数的内容. 语 法:eval [参数] 补充说明:eval可读取一连串的参数,然后再依参数本身的特性来执行. 参 数:参数不限数目,彼此之间用分号分开. .eval命令将会首先 ...

随机推荐

  1. Linux网络编程学习(一) ----- 概论和Linux模型(第一章第二章)

    1.什么是计算机网络,通信方式是什么? 计算机网络就是通过通信线路相互连接的计算机的集合,主要通过双绞线.同轴电缆.电话线或者光缆等有形传输介质通信,还有就是通过激光.微波.卫星等实现无线通信 2.W ...

  2. cdnbest配置强制ssl跳转

    如何配置强制ssl跳转 1. 登陆用户站点,点击下图图标: 2. 如下图添加证书和开启强制ssl即可 hsts解释和作用: 国际互联网工程组织IETF正在推行一种新的Web安全协议HTTP Stric ...

  3. DJango 基础 (2)

    urls.py路由用法 知识点 url基本概念 url格式 urls.py的作用 url解析过程 include的作用 kwarg的作用 name的作用 URL概念 URL(Uniform Resou ...

  4. NLTK 统计词频

    import nltk Freq_dist_nltk = nltk.FreqDist(list) for k,y in Freq_dist_nltk: print str(k),str(y)

  5. as3.0 嵌入字体的用法

    var txt:TextField = new TextField();//创建文本 txt.embedFonts=true;//确定嵌入字体 var font:Font=new MyFont();/ ...

  6. Teemo's tree problem

    题目链接 : https://nanti.jisuanke.com/t/29228 There is an apple tree in Teemo's yard. It contains n node ...

  7. react项目的ant-design-mobile的使用

    现在测试一下ant-design-mobile的使用,引用一个Button 没有样式 这个问题是没有引入样式 解决方法有两种 这种方法自己弄不出来,然后用另外一种方法 引入样式: import 'an ...

  8. centos7 下安装pycharm

    CentOS 7环境下Pycharm安装流程记录: 1.准备安装文件: 方法1: 使用内置火狐浏览器访问下载最新格式为tar.gz的压缩包 网址:https://www.jetbrains.com/p ...

  9. 彻底关闭win10后台同步数据(转自技术社区)

    设置隐私里面关闭所有同步数据选项 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\将下面子项属性修改 OneSyncSvc的start属相修改 ...

  10. python之运算符

    运算符的定义 运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算. 运算符类型 .算数运算符 .比较运算符 .赋值运算符 .位运算符 .逻辑运算符 .成员运算符 7身份运算符 详情介绍 1 ...