A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

接口:
package zeng;
public interface Operator {
    public void act();
}

具体的两个类:package zeng;
public class Success implements Operator {

    @Override
    public void act() {
        System.out.println("操作成功");
    }
}

package zeng;

public class Load implements Operator {
    @Override
    public void act() {
        System.out.println("等待中");
    }
}

具体实现:package zeng;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class TestReflect {

    // 加载配置文件,查询消息头对应的类名
    private String loadProtocal(String header) {
        String result=null;
        try {
            Properties prop = new Properties();
            InputStream fis=TestReflect.class.getClassLoader().getResourceAsStream("emp.properties");
            prop.load(fis);
            result = prop.getProperty(header);
            fis.close();
        } catch (Exception e) {
            System.out.println(e);
        }
        return result;
    }

    // 针对消息作出响应,利用反射导入对应的类
    public void response(String header) {
        String s =null;
        try {
            /*
             * * 导入属性文件emp.properties,查询header所对应的类的名字   *
             * 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离   *
             * 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议   
             */
            s =this.loadProtocal(header);
            // 加载类
            Class c = Class.forName(s);
            // 创建类的事例
            Operator mo = (Operator) c.newInstance();
            // 查询act方法
            Method m = c.getMethod("act");
            // 调用方法
            m.invoke(mo);
        } catch (Exception e) {
            System.out.println("Handler-response:" + e);
        }
    }
    public static void main(String[] args) {
        TestReflect tr=new TestReflect();
        tr.response("1000");
    }
}

emp.properties文件的代码:
1000=Success
2000=Load

我这里一直报如下图的错误,问题是出在加载类时候报错,但是我不知道为什么错了。




9.png (12.59 KB, 下载次数: 25)

9.png

评分

参与人数 1技术分 +1 收起 理由
岳民喜 + 1

查看全部评分

6 个回复

倒序浏览
// 加载类
     Class c = Class.forName(s);
加载类时有包得加上包名。
改为:
Class c = Class.forName("zeng."+s)
这样就OK了,你试试

评分

参与人数 1技术分 +1 收起 理由
岳民喜 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 黑马我来了 于 2012-4-15 17:45 编辑

兄弟你以后异常别用system打印了,不然只看到出什么错,跟踪不到错误是到哪行爆的。
首先InputStream fis=TestReflect.class.getClassLoader().getResourceAsStream("emp.properties");
这样是获取不到emp.properties得。报的是空指针。你如果是获取emp.properties文件,就用实列化一个FileInputStream 然后传入文件地址。

s =this.loadProtocal(header); 获取反射类的地址,你这里传的是不是类的地址,你传的是tr.response("1000");一个字符串。
所以报找不类。

评分

参与人数 1技术分 +1 收起 理由
贠(yun)靖 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 曾虓 于 2012-4-15 17:57 编辑
黑马我来了 发表于 2012-4-15 17:39
兄弟你以后异常别用system打印了,不然只看到出什么错,跟踪不到错误是到哪行爆的。
首先InputStream fis ...

我只是把异常打印出来看看。
你的解决方法是不对的,具体看我调试截图。
所以错误不是你说的那个。二楼帮我解决了问题,不过还是有个疑问:
为什么这个加载类时候,要带上包名,为什么,这不是同一个包中吗?

最后感谢你和二楼的帮助。
调试结果如图:

10.png (56.64 KB, 下载次数: 21)

10.png
回复 使用道具 举报
曾虓 发表于 2012-4-15 17:47
我只是把异常打印出来看看。
你的解决方法是不对的,具体看我调试截图。
所以错误不是你说的那个。二楼帮 ...

上面那个方法的确是没获取到属性文件,才报空的啊! 下面那个方法的,我以为你是直接传入的就是加载类的地址,没看清楚,所以说错了。下面也是类的地址错误,所以才报找不到类的啊。不好意思啊!
可能要传入绝对路径才能找吧。因为你的类的地址是从文件中取出来的。
回复 使用道具 举报
本帖最后由 如梦初醒 于 2012-4-15 21:39 编辑

为什么这个加载类时候,要带上包名,为什么,这不是同一个包中吗?

我的回答 :我们写的类通常都是由系统类加载器把.class字节码文件加载到内存中的,那么加载器要能够加载这个字节码文件(也就是被编译器所编译后的.class文件),首先加载器要能够找到这个字节码文件吧
那么系统类加载器是怎么找到这个字节码文件的呢,那就是环境变量的问题了,我们用的工具软件比如Eclipse会自动将我们写的源程序编译到工程的bin目录下
(如:这里的package zeng  的java文件Success.java  会被编译器编译到目录bin/zeng/Success.class下)
而环境变量默认的根目录为bin目录,对于你这个程序
package zeng;
public class Success implements Operator {
    @Override
    public void act() {
        System.out.println("操作成功");
    }
}
bin/zeng/Success.class这个字节码文件要被加载到内存中,必须让Class.forName(" ");知道bin/zeng/Success.class这个字节码文件的位置,

那么只能写成Class.forName(" zeng.Success");形式,就是让类加载器知道bin/zeng/Success.class字节码文件所在的位置,然后对这个字节码文件进行加载。




评分

参与人数 1黑马币 +2 收起 理由
曾虓 + 2 很给力!

查看全部评分

回复 使用道具 举报
本帖最后由 如梦初醒 于 2012-4-15 21:36 编辑

InputStream fis=TestReflect.class.getClassLoader().getResourceAsStream("emp.properties");
对于上面这行代码
属性文件emp.properties在这句代码中也是由类加载器加载到内存InputStream流中的,
然后才能通过 prop.load(fis);这句代码把文件emp.properties的数据载入对象
Properties prop = new Properties();进行封装,既然属性文件emp.properties是由类加载器载入内存,那么你也得让类加载器知道这个属性文件emp.properties的位置吧,
系统类加载器根据环境变量所设的目录对文件进行加载,环境变量的根目录在工程下为bin目录,所以我通常在用
InputStream fis=TestReflect.class.getClassLoader().getResourceAsStream("emp.properties");
这样的方式加载文件如这里的emp.properties,我会把文件放在系统类加载器能找到的地方如bin目录下。

评分

参与人数 1技术分 +1 收起 理由
岳民喜 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马