Java最详细的反射的理解

JAVA中的反射是运行中的程序检查自己和软件运行环境的能力,它可以根据它发现的情况进行改变。通俗的讲就是反射可以在运行时根据指定的类名获得类的信息。

首先我们先明确两个概念,静态编译和动态编译。

静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。

我们可以明确的看出动态编译的好处,而反射就是运用了动态编译创建对象。往往对比能更加直观的向我们展示两者的不同。
此处为代码操作…

若不用反射,它是这样的代码
public interface Fruit {
void eat();
}
public class Apple implements Fruit{
@Override
public void eat() {
System.out.println(“吃苹果…”);
}
}
public class Orange implements Fruit{
@Override
public void eat() {
System.out.println(“吃橘子…”);
}
}
//水果工厂类, 生产水果
public class FruitFactory {
/**
* 根据水果名 ,得到水果对象
* @param fname
* @return
*/
public static Fruit getInstance(String fname) {
Fruit f = null;
if(“apple”.equals(fname)) {
f = new Apple();
}
if(“orange”.equals(fname)){
f = new Orange();
}
return f;
}
}

public class TestFruit {
public static void main(String[] args) {
//根据水果工厂生产出1种水果
Fruit f = FruitFactory.getInstance(“apple”);
f.eat();
}
}
10 1public interface Fruit {2 void eat();3}4public class Apple implements Fruit{5 @Override6 public void eat() {7 System.out.println(“吃苹果…”);8 }9}10public class Orange implements Fruit{11 @Override12 public void eat() {13 System.out.println(“吃橘子…”);14 }15}16//水果工厂类, 生产水果17public class FruitFactory {18 /*19 * 根据水果名 ,得到水果对象20 * @param fname21 * @return22 /23 public static Fruit getInstance(String fname) {24 Fruit f = null;25 if(“apple”.equals(fname)) {26 f = new Apple();27 }28 if(“orange”.equals(fname)){29 f = new Orange();30 }31 return f;32 }33}34​35public class TestFruit {36 public static void main(String[] args) {37 //根据水果工厂生产出1种水果38 Fruit f = FruitFactory.getInstance(“apple”);39 f.eat();40 }41}
可以发现,每当我们要添加一种新的水果的时候,我们将不得不改变Factory中的源码,而往往改变原有正确代码是一种十分危险的行为。而且随着水果种类的增加,你会发现你的factory类会越来越臃肿,不得不说这是一种比较low的做法。(初学者可能会问,为什么不直接在main方法中new水果,这是因为我们可能会在getInstance方法中做一些别的事情。。。所以不直接new)
使用反射的代码及优势(除了工厂类和测试类需要改变) 其他不用更换
public class FruitFactory {
/

* 根据水果名 ,得到水果对象
* @param className 传入的类名
* @return
*/
public static Fruit getInstance(String className) {
Fruit f = null;
try {
//根据传入的类名 得到 水果对象 – 是一种聪明的做法
f = (Fruit) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}

public class TestFruit {
public static void main(String[] args) {
//根据水果工厂生产出1种水果
Fruit f = FruitFactory.getInstance(“com.hp.reflex.Orange”);
f.eat();
}
}
17 1public class FruitFactory {2 /**3 * 根据水果名 ,得到水果对象4 * @param className 传入的类名5 * @return6 */7 public static Fruit getInstance(String className) {8 Fruit f = null;9 try {10 //根据传入的类名 得到 水果对象 – 是一种聪明的做法11 f = (Fruit) Class.forName(className).newInstance();12 } catch (Exception e) {13 e.printStackTrace();14 }15 return f;16 }17}18​19public class TestFruit {20 public static void main(String[] args) {21 //根据水果工厂生产出1种水果22 Fruit f = FruitFactory.getInstance(“com.hp.reflex.Orange”);23 f.eat();24 }25}
在出现新品种水果的时候,完全不用去修改原有代码。从上面的案例中,我们可以清楚的体会到反射的优越性。

那么有的人又会问,这个例子能完全明白,但是如果放到实际的编程,应用中,我们又会在什么情况下用到反射那?

举一个看到过的例子,在实际开发中,我们需要把一个包中的class new出来,但是这个包中的类总是需要变动,那么怎么办,难道总是修改main方法中xxx=new xxx()吗。这样无疑是麻烦的。而运用反射。

我们可以相应的增加一个配置文件,在里面记录包中所有的类名,包中类增加时就加一个类名,删除时就删除一个类名。让main方法去读取这个配置文件中的类名,通过反射获得实例,完全不用我们去修改main方法中的代码。(Spring的IOC就是这个原理)

他甚至可以修改其他类中的私有属性。android开发中,我们需要改变一个私有标志位的时候,android源码并没有提供set方法,我们又不能改变源码,怎么办,反射可以完美解决这个问题。

说了这么多,那么我们的开发中,为什么不全部都用反射那?一个原因,开销,它的开销是比较昂贵的,所以尽量在最需要的地方使用反射,而不要在任意一个地方都是用反射。

说完是什么,为什么,我们必然需要掌握如何使用反射,先看反射中涉及了哪些方法。
Class c=Class.forName(“className”);注明:className必须为全名,也就是得包含包名,比如,cn.zz.pojo.UserInfo;
Object obj=c.newInstance();//创建对象的实例
OK,有了对象就什么都好办了,想要什么信息就有什么信息了。

获得类的构造函数
Constructor getConstructor(Class[] params)//根据指定参数获得public构造器
Constructor[] getConstructors()//获得public的所有构造器
Constructor getDeclaredConstructor(Class[] params)//根据指定参数获得public和非public的构造器
Constructor[] getDeclaredConstructors()//获得public的所有构造器

获得类中的方法
Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法
Method[] getMethods()//获得所有的public方法
Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public的方法
Method[] getDeclaredMethods()//获得所以的public和非public方法

获得类中属性
Field getField(String name)//根据变量名得到相应的public变量
Field[] getFields()//获得类中所以public的方法
Field getDeclaredField(String name)//根据方法名获得public和非public变量
Field[] getDeclaredFields()//获得类中所有的public和非public方法
看到这些,你就明白,反射是多么的强大了,当你正确使用这些方法的时候,基本上是掌握了反射的技巧。

还有 反射操作数组:
String[] str = (String[]) Array.newInstance(String.class, 5);
//反射调用sleep方法
Object invoke = method.invoke(obj, 5);//obj.sleep(5);
System.out.println(invoke);
在这里插入图片描述

扩展资料:
如果不知道某个对象的确切类型,RTTI可以告诉你,但是有一个前提:这个类型在编译时必须已知,这样才能使用RTTI来识别它。Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含Field、Method和Constructor类,这些类的对象由JVM在启动时创建,用以表示未知类里对应的成员。

这样的话就可以使用Contructor创建新的对象,用get()和set()方法获取和修改类中与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。另外,还可以调用getFields()、getMethods()和getConstructors()等许多便利的方法,以返回表示字段、方法、以及构造器对象的数组,这样,对象信息可以在运行时被完全确定下来,而在编译时不需要知道关于类的任何事情。

反射机制并没有什么神奇之处,当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类。因此,那个类的.class对于JVM来说必须是可获取的,要么在本地机器上,要么从网络获取。所以对于

RTTI和反射之间的真正区别只在于:
RTTI,编译器在编译时打开和检查.class文件
反射,运行时打开和检查.class文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值