内容简介:动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如JavaScript便是一个典型的动态语言。除此之外如Ruby、Python、OC等也都属于动态语言,而C、C++、Java等语言则不属于动态语言。动态类型语言,就是类型的检查是在运行时做的,是不是合法的要到运行时才判断,例如JavaScript就没有编译错误,只有运行错误。
Java是一门准动态语言,是因为存在反射机制,如果你不会是不是就等于白学了?
看完不会,请评论,我亲自给你解释,嘻嘻!
什么是动态语言?
动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如JavaScript便是一个典型的动态语言。
除此之外如 Ruby 、 Python 、OC等也都属于动态语言,而C、C++、 Java 等语言则不属于动态语言。
动态类型语言,就是类型的检查是在运行时做的,是不是合法的要到运行时才判断,例如JavaScript就没有编译错误,只有运行错误。
静态语言
而静态类型语言的类型判断是在运行前判断(如编译阶段),比如java就是静态类型语言,静态类型语言为了达到多态会采取一些类型鉴别手段,如继承、接口,而动态类型语言却不需要,
Java的反射机制被视为Java为准动态语言的主要的一个关键性质,这个机制允许程序在运行时透过反射取得任何一个已知名称的class的内部信息,包括:
正在运行中的类的属性信息,正在运行中的类的方法信息,正在运行中的类的构造信息,正在运行中的类的访问修饰符,注解等等。
动态语言无时不刻在体现动态性,而静态语言也在通过其他方法来趋近于去弥补静态语言的缺陷。
为什么么要使用反射:
- 反射是框架设计的灵魂
框架: 半成品软件。可以在框架的基础上进行软件开发,简化编码。学习框架并不需要了解反射,但是要是想自己写一个框架,那么就要对反射机制有很深入的了解。 - 解耦,提高程序的可扩展性
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
什么是反射:
定义:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
简单来说:将类的各个组成部分封装成其他对象
反射机制的实现原理
Java代码在计算机中经历的三个阶段
- Source源代码阶段: .java被编译成 .class字节码文件。
- Class类对象阶段:*.class字节码文件被类加载器加载进内存,并将其封装成Class对象(用于在内存中描述字节码文件),Class对象将原字节码文件中的成员变量抽取出来封装成数组Field[],将原字节码文件中的构造函数抽取出来封装成数组Construction[],在将成员方法封装成Method[]。当然Class类内不止这三个,还封装了很多,我们常用的就这三个。
- RunTime运行时阶段:创建对象的过程new。
获取Class对象的方式:
- Class.forname("类全名"):
将字节码加载进内存,返回Class对象。
一般用于: 配置文件,将类名定义在配置文件中,读取文件,加载类。 - 类名.class:
通过类名的属性Class获取
一般用于: 参数传递 - 对象.getclass()获取:
getclass()方法在Object类中定义
一般用于: 对象获取字节码的方式
补充:
同一个字节码文件(*.class)在一次程序运行中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
举例:
public void Main() throws ClassNotFoundException {
//方式一:Class.forName("全类名");
Class cls1 = Class.forName("com.test.domain.Person"); //Person自定义实体类
System.out.println("cls1 = " + cls1);
//方式二:类名.class
Class cls2 = Person.class;
System.out.println("cls2 = " + cls2);
//方式三:对象.getClass();
Person person = new Person();
Class cls3 = person.getClass();
System.out.println("cls3 = " + cls3);
// == 比较三个对象
System.out.println("cls1 == cls2 : " + (cls1 == cls2)); //true
System.out.println("cls1 == cls3 : " + (cls1 == cls3)); //true
//结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。
}
Class对象功能:
获取功能:
1 获取成员变量们
Field[] getFields() :获取所有public修饰的成员变量 Field getField(String name) 获取指定名称的 public修饰的成员变量 Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符 Field getDeclaredField(String name) //需要忽略访问权限修饰符的安全检查 setAccessible(true):暴力反射,不然会报错
具体测试看下文!
2.获取构造方法们
Constructor<?>[] getConstructors() Constructor<T> getConstructor(类<?>... parameterTypes) Constructor<?>[] getDeclaredConstructors() Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
具体测试看下文!
3.获取成员方法们:
Method[] getMethods() Method getMethod(String name, 类<?>... parameterTypes) Method[] getDeclaredMethods() Method getDeclaredMethod(String name, 类<?>... parameterTypes) //需要忽略访问权限修饰符的安全检查 setAccessible(true):暴力反射,不然会报错
具体测试看下文!
4.获取全类名
String getName()
getClass() 方法是Object类的方法,需要注意一点获取的类名是全类名(带有路径)
举例:
package Test;
public class Reflect {
public static void main(String[] args) throws Exception {
Class Tst = Test.class;
String s=Tst.getName();
System.out.println(s);
}
}
运行结果:

Field:成员变量
void set(Object obj, Object value) get(Object obj)
举例:
package Test;
public class Test {
public String a;
protected String b;
private String c;
String d;
}
package Test;
import java.lang.reflect.Field;
public class Reflect {
public static void main(String[] args) throws Exception {
Class Tst = Test.class;
Test tst=new Test();
System.out.println("-------------------测试getField--------------------");
Field[] fields=Tst.getFields();
for(Field f:fields)
{
System.out.println(f);
}
Field a=Tst.getField("a");
a.set(tst, "我是设置值");
System.out.println(a.get(tst));
System.out.println("\n-------------测试getDeclaredField------------------");
Field[] fields2=Tst.getDeclaredFields();
for(Field f:fields2)
{
f.setAccessible(true);//不加出不来,详情请看上文
System.out.println(f);
}
Field b=Tst.getDeclaredField("b");
b.set(tst, "我是私有的设置值");
System.out.println(b.get(tst));
}
}
测试结果:
Constructor:构造方法
创建对象:T newInstance(Object... initargs)
注意:如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
作用就是用它来创建对象
举例:
package Test;
public class Test {
public String a;
//构造方法
public Test( ) {}
public Test(String a) {
this.a = a;
}
}
package Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Reflect {
public static void main(String[] args) throws Exception {
Class Tst = Test.class;
Constructor[] constructors = Tst.getConstructors();
for (Constructor constructor : constructors) { // Constructor 对象reflect包下的 import java.lang.reflect.Constructor;
System.out.println(constructor);
}
System.out.println("------------------无参构造函数创建对象----------------------");
Constructor cst=Tst.getConstructor(); //获得无参构造函数
System.out.println(cst);
Object test=cst.newInstance(); //利用无参构造函数创建对象
System.out.println(test);
System.out.println("------------------有参构造函数创建对象----------------------");
Constructor cst2=Tst.getConstructor(String.class); //获得有参构造函数
System.out.println(cst2);
Object test2=cst2.newInstance("张3");//利用有参构造函数创建对象
System.out.println(test2);
System.out.println("------------------基于Class创建对象----------------------");
Object test3=Tst.newInstance();
//只能用于无参构函数,而且已经被弃用,不建议使用
System.out.println(test3);
}
}
喜欢问问题的小朋友要来了?
为什么没有getDeclaredConstructor方法和getDeclaredConstructors方法?
为什么?为什么?
有啊!!
getDeclaredConstructor方法可以获取到任何访问权限的构造器,而getConstructor方法只能获取public修饰的构造器。具体不再测试。此外在构造器的对象内也有setAccessible(true);方法,并设置成true就可以操作了。
关于为什么要使用private访问权限的构造器,使用这个构造器不就不能外部访问了嘛,不也就无法进行实例化对象了吗?无法在类的外部实例化对象正是私有构造器的意义所在,在单例模式下经常使用,整个项目只有一个对象,外部无法实例化对象,可以在类内的进行实例化并通过静态方法返回,由于实例化的对象是静态的,故只有一个对象,也就是单例的,这就是单例模式中的饿汉模式,不管是否调用,都创建一个对象。
Method:方法对象
执行方法:Object invoke(Object obj, Object... args)
获取方法名称:String getName();
举例:
package Test;
public class Test {
public String a;
// 构造方法
public Test() {
}
public Test(String a) {
this.a = a;
}
public void do_Something() {
System.out.println("吃饭睡觉打豆豆");
}
public String do_Something(String s) {
System.out.println("吃饭睡觉打"+s);
return "爽";
}
}
package Test;
import java.lang.reflect.Method;
public class Reflect {
public static void main(String[] args) throws Exception {
Class Tst = Test.class;
Method[] mtd=Tst.getMethods();
for(Method m:mtd) System.out.println(m);
}
}
运行结果:
举例2.0:
package Test;
public class Test {
public String a;
// 构造方法
public Test() {
}
public Test(String a) {
this.a = a;
}
public void do_Something() {
System.out.println("吃饭睡觉打豆豆");
}
public String do_Something(String s) {
System.out.println("吃饭睡觉打"+s);
return "爽";
}
}
package Test;
import java.lang.reflect.Method;
public class Reflect {
public static void main(String[] args) throws Exception {
Class Tst = Test.class;
Test test = new Test();
System.out.println("-----------------无参测试----------------------");
Method mtd1 = Tst.getMethod("do_Something");// 获得无参的方法
Object return_Value = mtd1.invoke(test); // 调用方法
// 有返回值就得到一个值,没有就得到一个null
System.out.println(return_Value);
System.out.println("-----------------含参测试----------------------");
Method mtd2 = Tst.getMethod("do_Something", String.class);// 获得无参的方法
Object return_Value2 = mtd2.invoke(test, "张三"); // 调用方法
// 有返回值就得到一个值,没有就得到一个null
System.out.println(return_Value2);
}
}
运行结果:
总结
这时候又会有小朋友问:
为什么要这么麻烦,我直接调用不就好了?
不知你是否发现,从类的创建的方法的使用,所有的一切都是用的字符串,那么也就是说,我可以通过读入数据,或者配置文件的方式,创建类,调用方法。
举个简单点的例子:
就拿英雄联盟这款游戏来说,这游戏三天两头的轮换一个娱乐模式,难道每次上线都要对源代码进行修改,今天在Client调用“无限活力”,明天就要调用"魄罗大乱斗”,每天就对着源码改?几万行的代码就这么放心让你改?除非你老板想做空公司,故意的!必然不可能,这时候我们就算哪一个txt文件,就放一行字符串,用反射之后,只用改txt文件不就完了!不用反射,是做不到用字符串创建类,和运行方法(别抬杠,写个if-else 或者 switch啥的)。
举例可能不太恰当,一般不会使用txt,一般使用XML或者java配置文件。
写在最后:
我叫风骨散人,名字的意思是我多想可以 不低头的自由生活 ,可现实却不是这样。家境贫寒,总得向这个世界低头,所以我一直在奋斗,想 改变我的命运 给亲人好的生活,希望 同样被生活绑架的你 可以通过自己的努力改变现状,深知成年人的世界里没有容易二字。目前是一名在校大学生,预计考研,热爱编程,热爱技术,喜欢分享,知识无界,希望我的分享可以帮到你!
如果有什么想看的,可以私信我,如果在能力范围内,我会发布相应的博文!
感谢大家的阅读!:kissing_heart:你的点赞、收藏、关注是对我最大的鼓励!
以上所述就是小编给大家介绍的《反射,反射程序员的快乐!为什么我老是加班?为什么我工资不如他多?原来是我不懂反射!》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Caching
Duane Wessels / O'Reilly Media, Inc. / 2001-6 / 39.95美元
On the World Wide Web, speed and efficiency are vital. Users have little patience for slow web pages, while network administrators want to make the most of their available bandwidth. A properly design......一起来看看 《Web Caching》 这本书的介绍吧!