能够分析类能力的程序被称为反射(reflective)。
反射是一种功能强大且复杂的机制,使用它的主要对象是工具构造者。如果你编写的程序必须要与编译时未知的类一起工作,如有可能,就应该仅仅使用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类。(读者:比如在抽象工厂设计模式中,在编译的时候你并不知道将来要用到哪一个类,所以应该使用反射机制根据输入条件或者配置文件来实例化对象,但是在代码的其余部分中,你并不需要直接和这个类打交道,而是可以访问这个类的超类或者是这个类实现的某个接口,这样就使得代码具有相当的灵活性)比如你要实例化类java.util.TreeSet,你可以这样使用:
- Set<String> s = (Set<String>) Class.forName("java.util.TreeSet")
- .newInstance();
先说Class类,获得Class对象三种方法,一是Class e1 = e.getClass(); 二是Class.forName("java.util.Date"), 括号中的类名是完整名(包括包名), 三是Class cl1 = Date.class; Class cl2 = int.class;
一个Class对象实际上表示的是一个类型,而这个类型未必是一种类,如它可以是一个int类型,int.class代表一个Class类型的对象。比如:
- int[] ia = new int[3];
- int[] ib = new int[6];
-
- System.out.println(ia.getClass() == ib.getClass());
因为ia和ib都是int类型,所以它们返回相同的Class类型。
我们一般使用JDBC连接mysql数据库时,代码是这样的
- Class.forName("com.mysql.jdbc.Driver");
- Connection conn = DriverManager.getConnection(
- "jdbc:mysql://localhost:3306/test", "root", "pass"); // 获得连接对象
-
那么Class.forName("")到底做了什么呢?返回与带有给定字符串名的类或接口相关联的 Class
对象。调用此方法等效于
- Class.forName(className, true, currentLoader)
其中 currentLoader
表示当前类的定义类加载器,调用 forName("X") 将导致命名为 X 的类被初始化。接着我们看看com.mysql.jdbc.Driver的代码:
- public class Driver extends NonRegisteringDriver implements java.sql.Driver {
-
-
- static { (这是静态初始化代码)
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch (SQLException E) {
- throw new RuntimeException("Can't register driver!");
- }
- }
-
-
-
-
-
-
-
- public Driver() throws SQLException {
-
- }
- }
在初始化类Driver时,静态块中的代码会被执行
- java.sql.DriverManager.registerDriver(new Driver());
于是Driver类被注册到DriverManager中,接着就可以建立连接。
Class类还有一个很有用的方法newInstance(),可以用来快速的创建一个类的实例。newInstance()方法需要一个默认的构造器来初始化创建的对象。可以参考一个例子(取自effective java 2):
- import java.util.Arrays;
- import java.util.Set;
-
-
-
-
-
-
-
-
-
-
-
-
- public class SetTest {
- @SuppressWarnings("unchecked")
- public static void main(String[] args) {
- Class<?> cl = null;
- try {
- cl = Class.forName(args[0]);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- System.exit(1);
- }
- Set<String> s = null;
- try {
- s = (Set<String>) cl.newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- System.exit(1);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- System.exit(1);
- }
- s.addAll(Arrays.asList(args).subList(1, args.length));
- System.out.println(s);
- }
- }
-
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
Class类:代表一个类。
Field 类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor 类:代表类的构造器。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
在core java卷一种介绍了反射的几种用法:
1、利用反射分析类的能力
2、在运行时使用反射分析对象
3、使用反射编写泛型数组代码
这里不贴代码了,事实上看看书也就基本了解反射的基础了,要熟悉一些常用的API运用。
假设有一个某一类型的数组已经填满,现在希望扩展它的长度,自动扩展。
- Class cl = a.getClass();
- if (!cl.isArray()) return null;
- Class componentType = cl.getComponentType();
- int length = Array.getLength(a);
-
- int newLength = length * 11 / 10 + 10;
-
- Object newArray = Array.newInstance(componentType, newLength);
- System.arraycopy(a, 0, newArray, 0, length);
- return newArray;
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。