java 反射机制之开门见山
引出话题
为何要使用反射,我们做事情往往讲究因果,做什么,为什么。java 反射机制也不例外,为何需要学习它,掌握它也是有原因的,先简单说下什么是反射吧。
举个栗子:一般我们写代码时,写一个类 Hello.java
public class Hello {
public void helloWorld(){
System.out.println("我为自己带盐");
}
}
// 称这段代码为“因”
然后当要使用时创建JAVA类实例对象。
Hello hello = new Hello();
hello.helloWorld();
// 这段代码成为 “果”
一般的写法都是先有“因”后有“果”,而反射是什么呢。反射刚好反过来,它先定义“果”的生产方式,然后等着“因”出现,就会出现相应的果。说道这里可能还是有新手不明觉厉,我再引用一个比较完整的例子。
java 反射简单例子
interface fruit{ // 父类, 水果
public abstract void eat();
}
class Apple implements fruit{ // 子类,苹果
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{ // 子类, 橙子
public void eat(){
System.out.println("Orange");
}
}
// 这是没有使用反射的写法
// 构造工厂类
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
// Factory类 通过上面的“因” 生产“果”
class Factory{
public static fruit getInstance(String fruitName){ // 传递水果名进来
fruit f=null;
if("Apple".equals(fruitName)){
f=new Apple();
}
if("Orange".equals(fruitName)){
f=new Orange();
}
// 如果以后有香蕉,那么需要在这里多加 if 是否香蕉的判断。
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Orange"); // 等价 Fruit fruit = new Fruit();
f.eat();
}
}
上面的代码。可以发现,每当我们要添加一种新的水果的时候,我们将不得不改变Factory中的源码(多加if的判断),而往往改变原有正确代码是一种十分危险的行为。而且随着水果种类的增加,你会发现你的factory类会越来越臃肿,不得不说这是一种十分low的做法。
那有没有什么办法不用修改Factory呢,答案当然是有的啦。解决这个问题的答案就是:反射。
修改后的代码:
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 从这里开始有变化
// 此时没有直接使用“因”, 而仅是定义了果的生产方式
class Factory{
public static fruit getInstance(String ClassName){ // 这里说需要一个名字,究竟是什么水果名字,现在还不知道
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance(); // 不用管来的是什么东东,来什么就返(实例化该对象)什么。
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("cn.lyx.Reflect.Apple"); // 写上完整的包路径
if(f!=null){
f.eat();
}
}
}
完美! perfect!
在出现新品种水果的时候,你完全不用去修改Factory原有代码。从上面的案例中,我们可以清楚的体会到反射的优越性。