反射概念:

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. faster rcnn源码阅读笔记1

    自己保存的源码阅读笔记哈 faster rcnn 的主要识别过程(粗略) (开始填坑了): 一张3通道,1600*1600图像输入中,经过特征提取网络,得到100*100*512的feature ma ...

  2. jscript DOM操作

    \n 换行符 \b 空格 \r 回车 && 与 || 或 ! 非(取反) classList属性 classList 属性返回元素的类名,作为 DOMTokenList 对象. 该属性 ...

  3. cdnbest区域自定义配置里添加防xss攻击配置

    把下面代码复制进去即可: <!--#start 300 --><config> <response action='allow' > <table name= ...

  4. mysql学习笔记--数据操作

    一.插入数据 1. 语法:insert into 表名 (字段名.字段名,...) values (值1,值2...) 2. 注意: a. 插入字段的个数和顺序与值的个数和顺序必须一致 b. 通过de ...

  5. [leetcode]49. Group Anagrams变位词归类

    Given an array of strings, group anagrams together. Example: Input: ["eat", "tea" ...

  6. ubuntu6.4系统安装JIRA-7.8

    一.系统环境: system version:ubuntu6.4 openjdk version  (java版本) :1.8.0_191  mysql version:14.14 jira vers ...

  7. Selenium 学习汇总

    Commands (命令) Action 对当前状态进行操作 失败时,停止测试 Assertion 校验是否有产生正确的值 Element Locators 指定HTML中的某元素 Patterns ...

  8. (sealed)密封类及密封方法优缺点

    1. 密封类防止被继承 (有利于代码优化, 由于密封类的不被继承性, 代码在搜索此方法时可以直接定位, 不需要一层层的找继承关系) 只有本程序集可以使用 2. 密封类中不需要再写密封方法(一般密封方法 ...

  9. Java 接口多继承

    按照理解,一般都是说Java 类是单继承,但可以实现多个接口.但是可以通过接口来实现类的多继承.(如何通过接口来实现多继承???) 那么就一直以为Java里面是单继承,今天看FutureTask源码的 ...

  10. 28.Mysql权限与安全

    28.Mysql权限与安全28.1 Mysql权限管理 28.1.1 权限系统的工作原理对连接的用户进行身份认证,合法的用户通过认证,不合法的用户拒绝连接:对通过认证的合法用户赋予相应的权限,用户可以 ...