Class对象可以获取类里的方法,由Method对象表示,调用Method的invoke可以执行对应的方法;可以获取构造器,由Constructor对象表示,调用Constructor对象的newInstance方法可以执行类对应的构造方法;可以获取成员变量,由Field对象表示,通过Field对象可以直接修改类的成员变量的访问权限和值。

创建对象

通过反射有两种方式创建对象

使用Class对象的newInstance(),这是最常用的方式,根据配置文件信息创建对象。

使用Class对象获取指定的Constructor对象,再由Constructor对象的newInstance创建类的对象。

调用方法

首先要获取类在JVM中对应的Class对象,通过类的Class对象的getMethod方法来获取类的方法,返回Method类型的对象,最后通过Method对象的invoke来执行类的方法。

下面的例子将演示从配置文件中读取数据来动态地创建对象,还通过配置文件信息来执行对象的setter来初始化对象。

 package jvmTest;

 import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties; public class ExtendedObjectPoolFactory {
private Map<String, Object> objectPool = new HashMap<>();
private Properties config = new Properties();
public void init(String fileName) {
try {
FileInputStream fis = new FileInputStream(fileName);
config.load(fis);
} catch (IOException ex) {
System.out.println("读取 " + fileName + " 异常");
ex.printStackTrace();
}
}
private Object createObject(String clazzName) throws Exception {
Class<?> clazz = Class.forName(clazzName);
//使用clazz默认构造器创建对象
return clazz.newInstance();
}
//根据配置文件创建对象
public void initPool() throws Exception {
for (String name : config.stringPropertyNames()) {
if (!name.contains("%")) {
objectPool.put(name, createObject(config.getProperty(name)));
}
}
} //根据配置文件来执行对象对应的set方法
public void initProperty() throws Exception {
for (String name : config.stringPropertyNames()) {
if (name.contains("%")) {
String[] objAndPro = name.split("%");
//获取对象
Object target = getObject(objAndPro[0]);
//构造setter方法名
String mtdName = "set"+ objAndPro[1].substring(0,1).toUpperCase() + objAndPro[1].substring(1);
Class<?> targetClass = target.getClass();
Method mtd = targetClass.getMethod(mtdName, String.class);
mtd.invoke(target, config.getProperty(name));
}
}
} public Object getObject(String name) {
return objectPool.get(name);
} public static void main(String[] args) throws Exception {
ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
epf.init("extObj.txt");
epf.initPool();
epf.initProperty();
System.out.println(epf.getObject("a"));
}
}

上面程序第23行获取Class对象后在第25行使用默认的构造器动态创建出了对象,

如果要使用指定构造器,需要先获取Constructor对象,再使用Cronstructor对象的newInstance创建对象,像下面这样,

 Constructor ctor = clazz.getConstructor(String.class);
return ctor.newInstance("here is parameter for specific constructor");

第45行获取Class对象后,在46行通过Class对象获取指定要执行的方法(带一个参数),用Method对象表示,最后在47行调用Method对象的invoke可以执行类的指定方法

上面的例子使用下面的测试文件进行测试,

extObj.txt

 a=javax.swing.JFrame
b=javax.swing.JLabel
a%title=Test title

输入结果,

javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=Test title,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]

访问成员变量

通过Class对象的getField方法可以访问指定的成员变量,调用继承自AccessableObject的setAccessable方法可以获得private成员变量的访问权限。

以下方法可以访问成员变量,

get(Object obj), 获取成员变量值。  如果是基本类型,直接使用类似 getInt(Object obj),  getChar(Object obj)的方式

set(Object obj), 设置成员变量值。 如果是基本类型,直接使用类似 setInt(Object, int val), setChar(Object obj, char c)的方式

下面演示访问成员变量,

 package jvmTest;

 import java.lang.reflect.Field;

 class Person {
private String name;
private int age;
public String toString() {
return "Person[name: "+name+", age: "+age+"]";
}
}
public class FieldTest {
public static void main(String[] args) throws Exception {
Person p = new Person();
Class<Person> clazz = Person.class;
//getDeclaredFiled可以获取所有访问权限的成员变量
Field nameField = clazz.getDeclaredField("name");
//true表示取消权限限制
nameField.setAccessible(true);
nameField.set(p, "Tom");
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.setInt(p, 18);
System.out.println(p);
}
}

上面程序第20行使用的是set(), 而23行使用的是setInt(), 输出结果,

Person[name: Tom, age: 18]

操作数组

java.lang.reflect还包含一个Array类,可以动态地创建数组,设置元素的值,比较强大,主要方法有,

newInstance(..),创建数组,可以指定数组元素类型, 数组维度, 数组长度

get(...), 获取索引为index的元素,对于基本数据类型的数组,方法为getInt(...),  getChar(...) ...

set(...), 设置索引为index的元素,对于基本数据类型的数组,方法为setInt(...),  setChar(...) ...

下面演示用法,

 package jvmTest;

 import java.lang.reflect.Array;

 public class ArrayTest2 {
public static void main(String[] args) {
// 创建三维数组
Object arr = Array.newInstance(String.class, 3, 4, 10);
// 获取index为2的元素,该元素是一个二维数组
Object arrObj = Array.get(arr, 2);
// 给二维数组index为2的元素赋值
// 二维数组的元素是一维数组,所以赋值也要用数组来赋值
Array.set(arrObj, 2, new String[] { "天王盖地虎", "宝塔镇河妖" });
//获取二维数组指定index的元素(结果是一维数组)
Object anArr = Array.get(arrObj, 3);
Array.set(anArr, 8, "野鸡闷头钻,哪能上天王山");
//将arr强制转换为三维数组
String[][][] cast = (String[][][])arr; System.out.println(cast[2][2][0]);
System.out.println(cast[2][2][1]);
System.out.println(cast[2][3][8]);
}
}

输出如下,

 天王盖地虎
宝塔镇河妖
野鸡闷头钻,哪能上天王山

JAVA基础知识之JVM-——使用反射生成并操作对象的更多相关文章

  1. JAVA基础知识总结18(反射)

    反射技术: 其实就是动态加载一个指定的类,并获取该类中的所有的内容.而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖. 反射的 ...

  2. java 基础知识学习 JVM虚拟机参数配置

    1) 设置-Xms.-Xmx相等: 2) 设置NewSize.MaxNewSize相等: 3) 设置Heap size, PermGen space: Tomcat 的配置示例:修改%TOMCAT_H ...

  3. Java基础知识笔记第四章:类和对象

      编程语言的几个发展阶段 面向机器语言 面向过程语言 面向对象语言:封装.继承.多态 类 类声明 class Person{ ....... } class 植物{ ....... } 类体 类使用 ...

  4. 学习Spring必学的Java基础知识(1)----反射(转)

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...

  5. 学习Spring必学的Java基础知识(1)----反射

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...

  6. JAVA基础知识|java虚拟机(JVM)

    一.JVM简介 java语言是跨平台的,兼容各种操作系统.实现跨平台的基石就是虚拟机(JVM),虚拟机不是跨平台的,所以不同的操作系统需要安装不同的jdk版本(jre=jvm+类库:jdk=jre+开 ...

  7. Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  8. 毕向东—Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  9. 沉淀,再出发:Java基础知识汇总

    沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的 ...

随机推荐

  1. C++Primer 第五章

    //1.表达式语句的作用:执行表达式并丢弃求值结果 ; value + ; //执行,并丢弃结果 //2.复合语句是指用花括号括起来的语句和声明的序列,复合语句称为块.一个块就是一个作用域.块不以分号 ...

  2. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-5-6 踩踏平台是怎么炼成的

    在游戏中,有很多分来飞去的平台,这个平台长短不一.如果每种长度都去创建一张图片那是比较繁琐的事情.实际上,我们只用到3张图.分别是平台的,平台的中间部分,平台的右边.关键是平台的中间部分,两张中间部分 ...

  3. Leetcode: Longest Absolute File Path

    Suppose we abstract our file system by a string in the following manner: The string "dir\n\tsub ...

  4. Python学习总结5:数据类型及转换

    Python提供的基本数据类型主要有:整型.浮点型.字符串.列表.元组.集合.字典.布尔类型等等. Python可以用一些数据类型函数,直接进行转换: 函数                       ...

  5. Android -- 自定义View小Demo(一)

    1,现在要实现下图的简单效果,很简单  ,就是使用paint在canvas上绘制5中不同颜色的圆圈,效果图如下: 这是绘制基本图形一种最简单的方法,下面是它的代码 ,注释写的很详细,也就不去讲解了 M ...

  6. android中影藏状态栏和标题栏的几种方法

    1,在android中,有时候我们想隐藏我们的状态栏和标题栏(如:第一次安装app时候的欢迎界面),实现这些效果有几种方法,随便选取自己喜欢的即可. 2, A:利用代码实现,在我们主Activity中 ...

  7. 夺命雷公狗---DEDECMS----9dedecms单标签

    我们这一节课开始将dedecms的标签了,dedecms里面的标签分好多个的,我们先来看下他的标签长得啥样的先: 随便点击一个修改即可见到标签了: 这里面上面的大文本框里面有标签的用法下面有参数的说明 ...

  8. webpack我遇到的一些坑

    我的第一个用于实验webpack的项目是一个拥有多个版本的项目.什么叫多个版本?这个项目对3个语言版本+3个不同城市版本+(移动端  + PC端),也就是3*3*2,18个版本. 我的第一次想法肯定是 ...

  9. HGE引擎之hgeSprite

    一.hgeSprite类 hgeSprite是一个精灵实体的HGE帮助类. 1.构造函数 创建和初始化一个hgeSprite对象. hgeSprite(HTEXTURE tex, float x, f ...

  10. Eclipse帮助文档配置

    Force Eclipse To Use Local Javadocs For Context-Sensitive Help 转自:http://www.gnostice.com/nl_article ...