黑马程序员_Java基础:反射机制(Reflection)总结

时间:2022-12-31 11:26:07

  ------- android培训java培训、期待与您交流! ----------

反射在java中有非常重大的意义,它是一种动态的相关机制,可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods具体定义),并生成其对象实体、或对其fields设值、或使用其methods。反射是框架的基础,而框架能大大节省java程序的开发成本,是日后工作中经常会碰到的技术。所以,学习好反射的重要性就不言而喻了。

一、概念

java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射的动态特性极大地体现了java的灵活性。

很多人刚接触反射的时候,可能觉得不大好理解,那是因为对反射的过程了解得不够清楚。我们要知道,反射都是通过传递class来间接完成目的。

比如想通过反射调用一个类的构造方法来创建对象,那么就要先得到那个类的字节码对象(class)。而类的字节码对象是属于Class类,Class类有提供获取class对象中包括构造方法,成员方法,以及字段所属类(Constructor,Methods,Field)的方法。那么我们只要使用字节码对象调用Class中的getConstructor()方法,即可获取对象中的构造方法的所属类,最后通过构造方法的所属类获取构造方法。当我们最终获取构造方法后,就能成功创建对象。

如果文字表达的不够清楚,可以看以下图解:

黑马程序员_Java基础:反射机制(Reflection)总结

二、反射机制的优点与缺点

首先要弄清楚为什么要用反射,这涉及到了动态与静态的概念。

  静态编译:在编译时确定类型,绑定对象,即通过。
  动态编译:运行时确定类型,绑定对象。

反射的优点就是:它的动态创建对象和编译,最大限度发挥了java的灵活性,体现了多态的应用,又可以降低类之间的藕合性。
      它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM虚拟机,我们希望做什么并且它满足我们的要求,但这类操作总是慢于只直接执行相同的操作。

三、使用方法

首先需要了解一下,java.lang.reflect包中的一些类来的含义。
      常用的类有:
      Class:包含某个类的全部信息,包括属性、方法、构造方法等。(java.lang包)
      Construtor:代表类中的构造方法。
      Method:代表类中的方法。
      Field:代表类中的属性。

步骤(结合图解):
      (1)取得对象的class字节码对象。
      根据字符串全类名:Class cls=Class.forName(String className);
      根据对象:Class cls=obj.getClass(); //获取当前对象所属的类
      根据类:Class cls=Person.class; 

(2)取得对象成员所属的类
      取得所有字段的所属类的数组:Field[] field=cls.getDeclaredFields();
      取得所有公共字段的所属类的数组:Field[] field=cls.getFields();
      取得指定的字段的所属类:Field fields=cls.getDeclaredField (String name);
      取得指定的公共字段的所属类:Field fields=cls.getField (String name);

取得所有方法的所属类的数组:Method[] methods=cls.getDeclaredMethods();
      取得指定方法的所属类:Method method = cls.getJMethod();

取得所有构造方法的所属类的数组:Constructor[] con = cls.getConstructors();
      取得指定构造方法的所属类:Constructor con = cls.getConstructor(Class... parameterTypes) ;

(3)使用对象成员所属类获取对象成员
      获取指定字段:Object objField = field.get();

获取指定方法:Object objMethod = method.invoke(Object obj, Object... args) ;

获取指定构造方法:Object objCon = con.newInstance(Object... initargs) ;

四、应用

1.例子一(通过反射获取类的构造方法):(以下例子为了方便阅读,异常都做抛处理)

 import java.lang.reflect.Constructor;

 public class ReflectTest {

     public static void main(String[] args) throws Exception {
// 通过反射获取一个类的构造方法。注意反射比较消耗资源,会影响程序性能。
Constructor<String> cons = String.class.getConstructor(StringBuffer.class);
// 也可通过获取到的构造方法反过来获取构造方法所属的类。
Class<String> cls4 = cons.getDeclaringClass();
System.out.println(cls4);
}
}

运行结果为:

class java.lang.String

2.例子二(通过反射获取类中字段、改变字段的值):

 public class Student {
private int high;
public int wight;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "hello"; public ReflectPiont(int high, int wight) {
super();
this.high = high;
this.wight = wight;
}
}
 import java.lang.reflect.Field;

 import com.gzjzone.jul262015.ReflectPiont;

 public class ReflectTest {

     public static void main(String[] args) throws Exception {
Student s1 = new Student(3, 5);
// getField方法返回的不是具体的变量y,而是一个类,通过这个类调用get方法才能获取具体对象上变量。
Field fieldW = s1.getClass().getField("wight");
System.out.println(fieldW.get(s1)); // 因为s1上的x变量是私有的,所以要用getDeclaredField,只要是声明的变量都能提取成类。
Field fieldH = s1.getClass().getDeclaredField("high");
// 同理s1上的x变量是私有的,所以只能通过暴力反射的方法获取x。
fieldH.setAccessible(true);
System.out.println(fieldH.get(s1)); changeStringValue(s1);
System.out.println(s1);
} private static void changeStringValue(Object obj) throws Exception {
// 通过反射获取对象上的所有变量对应的类。
Field[] fields = obj.getClass().getFields();
for (Field field : fields) {
if (field.getType() == String.class) {
String oldValue = (String)field.get(obj);
//修改类上的字段值。
String newValue = oldValue.replace('b', 'a');
field.set(obj, newValue);
}
}
}
}

运行结果:

5
3
aall:aasketaall:hello

3.例子三(通过反射,获取类中的方法):

import java.lang.reflect.Method;

public class ReflectTest {

    public static void main(String[] args) throws Exception {
// 使用反射调用main方法。
// 先假设本类运行时会接收到TestArguments的名称。
String className = args[0];
Method mainMethod = Class.forName(className).getMethod("main", String[].class);
// 在jdk1.4中invoke方法的参数列表是(Object,Object[]),invoke方法接收到Object[]后会拆开。
// 而jdk1.5以后invoke方法的参数列表是可变参数列表(Object,...arg)。
// 因为1.5是兼容1.4的,所以如果把String[]传进invoke方法,会被拆开,这不符合要求。
// 解决方法为:1.把String[]作为一个元素装进一个Object[]中;2.把String[]强制转成Object。
// 如果invoke方法第一个参数为null,表示调用的是静态方法。
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
}
} class TestArguments{
public static void main(String[] args){
for (String arg : args) {
System.out.println(arg);
}
}
}

运行结果:

111
222
333

4.例子四(通过反射,获取数据元素):

import java.lang.reflect.Array;

public class ReflectTest {

    public static void main(String[] args) throws Exception {
// 通过反射获取数组,Array。
int[] arr = {1,2,3};
printObject(arr);
printObject("xyz");
} private static void printObject(Object obj) {
if (obj.getClass().isArray()) {
int len = Array.getLength(obj);
for (int x = 0; x < len; x++) {
System.out.println(Array.get(obj, x));
}
}
else{
System.out.println(obj);
}
}
}

运行结果为:

1
2
3
xyz

5.例子五(基础框架):

 public class Student {
private int high;
public int wight; public ReflectPiont(int high, int wight) {
super();
this.high = high;
this.wight = wight;
} @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPiont other = (ReflectPiont) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
} @Override
public String toString(){
return str1+":"+str2+":"+str3;
}
}
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties; public class ReflectTest {
public static void main(String[] args) throws Exception { // 运用框架的方式创建对象,好处就是可以先做框架,后再创建对象对应类,从而增强程序的适用性。
// 框架完成后,创建对象是,只要先通过配置文件的方式获取对象对应的类名即可。
InputStream ips = new FileInputStream("config.properties"); //内容为className=java.util.HashSet
Properties pro = new Properties();
pro.load(ips);
ips.close();
String className = pro.getProperty("className");
//Class类中本身也有newInstance()方法,它实际是调用Constructor类中的newInstance(),只能获取类的空参数构造函数。
Collection col = (Collection)Class.forName(className).newInstance(); Student s1 = new Student(2, 4);
Student s2 = new Student(3, 6);
Student s3 = new Student(2, 4); col.add(s1);
col.add(s1);
col.add(s2);
col.add(s3); /* 注意,在hashSet集合中,因为y的值有参与hashCode值的运算,所以修改y后,
pt1指向的对象内存hashCode地址已变,而pt1指向的还是原来对象的地址。
最后删除的是pt1指向的原对象地址,而变更后的对象地址则还存在,造成内存溢出。*/
pt1.y = 6;
col.remove(pt1); System.out.println(col.size());
}
}

运行结果为:

2

以上就是本人现阶段所学习到的反射知识总结,若以后对反射有更加深的见解或建议,再继续完善文章。

黑马程序员_Java基础:反射机制(Reflection)总结的更多相关文章

  1. 黑马程序员&lowbar;Java基础视频-深入浅出精华版--PPT 文件列表

    \day01\code\第一章_Java概述.ppt;\day01\resource\资料\50道编程题(有精力的同学看看).doc;\day01\resource\资料\Sun_Java程序员认证考 ...

  2. 黑马程序员&lowbar;Java基础:网络编程总结

    ------- android培训.java培训.期待与您交流! ---------- Java语言是在网络环境下诞生的,它是第一个完全融入网络的语言,虽然不能说它是对支持网络编程做得最好的语言,但是 ...

  3. 黑马程序员&lowbar;Java基础组成

    Java语言基础组成 2.1关键字 main不是关键字,但被JVM所识别的名称. 关键字的定义和特点 定义:被Java语言赋予了特殊含义的单词. 特点:关键字中所有字母都为小写. 用于定义数据类型的关 ...

  4. 黑马程序员&lowbar;java基础笔记&lpar;12&rpar;&period;&period;&period;内省(IntroSpector)

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流!—————————— 1,了解JavaBean.2,BeanUtils工具包. 1,了解JavaBean. ...

  5. 黑马程序员&lowbar;java基础笔记&lpar;11&rpar;&period;&period;&period;反射

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流! —————————— 1,字节码.2,Constructor类.3,Field类.4,Method类.5 ...

  6. 黑马程序员&lowbar;Java基础视频-深入浅出精华版--视频列表

    \day01\avi\01.01_计算机基础(计算机概述).avi; \day01\avi\01.02_计算机基础(计算机硬件和软件概述).avi; \day01\avi\01.03_计算机基础(软件 ...

  7. 课程2:《黑马程序员&lowbar;Java基础视频-深入浅出精华版》-视频列表-

    \day01\avi\01.01_计算机基础(计算机概述).avi; \day01\avi\01.02_计算机基础(计算机硬件和软件概述).avi; \day01\avi\01.03_计算机基础(软件 ...

  8. 黑马程序员&lowbar;JAVA基础知识总结3

    ------- android培训.java培训.期待与您交流! ---------- Java源文件的扩展名是.java,编译之后生成.class的文件.所有的类都有一个共同的继承祖先Object类 ...

  9. 黑马程序员&lowbar;JAVA基础知识总结2

    ------- android培训.java培训.期待与您交流! ---------- IDE ---> Itegrity Development Environment Java EE --- ...

随机推荐

  1. FPS

    游戏的FPS跟什么有关 http://zhidao.baidu.com/link?url=jZJoN_-MTC9fWCBSBaL5vezBp13MRSv8PdCcQMbwX5tiFGzxNEHe7UB ...

  2. NDK学习三&colon; 纯手工编译Hello World

      1.配置环境变量 添加make工具path环境变量: E:\Android\android-ndk-r10b\prebuilt\windows-x86_64\bin     2.编写Hello W ...

  3. ActiveMQ学习笔记

    关键接口和类: ConnectionFactory connectionFactory;//连接工厂 Connection connection;//连接 Session session; Desti ...

  4. swift GCD使用指南

    swift GCD使用指南 Grand Central Dispatch(GCD)是异步执行任务的技术之一.一般将应用程序中记述的线程管理用的代码在系统级中实现.开发者只需要定义想执行的任务并追加到适 ...

  5. JS常用验证方法

    1.验证必须为数字(可有小数点) if(isNaN(value))execCommand('undo') 说明:1.isNaN()方法用于验证value值是否为非法数字,返回值true或者false. ...

  6. 一个轻量级rest服务器

    RestServer直接发布数据库为json格式提供方法 RestSerRestServer直接发布数据库为json格式 支持MySQL,SqlServer,Oracle直接发布为Rest服务, 返回 ...

  7. 树莓派控制HC-SR04超声波模块测距(新手向&plus;C语言向)

    因为作业要求使用c语言代码,这里先附上一段摘自网上的代码 感谢KalaerSun的c语言代码,摘自https://blog.csdn.net/qq_25247589/article/details/6 ...

  8. SpringBoot&plus;Mybatis&plus;Maven&plus;MySQL逆向工程实现增删改查

    SpringBoot+Mybatis+MySQL+MAVEN逆向工程实现增删改查 这两天简单学习了下SpringBoot,发现这玩意配置起来是真的方便,相比于SpringMVC+Spring的配置简直 ...

  9. Qt网络应用开发初步

      应用层的网络协议,如HTTP/FTP/SMTP等简称"应用协议",他们运行在TCP/UDP之上,从Qt5开始,已经不再分别提供QHttp类,QFtp类,应用层的编程使用QNet ...

  10. Spring AOP详解和实现方式

    一.什么是AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善. ...