1.获取类对象

1.1类对象概念

所有的类,都存在一个类对象,这个类对象用于提供类本身的信息,比如有几种构造方法,有多少属性,有哪些普通方法。

在理解类对象之前,先说我们熟悉的对象之间的区别:
garen和teemo都是Hero对象,他们的区别在于,各自有不同的名称,血量,伤害值。

然后说说类之间的区别
Hero和Item都是类,他们的区别在于有不同的方法,不同的属性。

类对象,就是用于描述这种类,都有什么属性,什么方法的

1.2获取类对象Class

一种类,只会有一个类对象存在。所以以下三种方式取出来的类对象,都是一样的。

  • class.forName("com.cxy.Hero")
  • Hero.class
  • Hero hero = new Hero();     hero.getClass()

准确的讲是一个ClassLoader(类加载器)下,一种类,只会有一个类对象存在。通常一个JVM下,只会有一个ClassLoader。

调用Class对象的getConstructor(Class<?>... parameterTypes)获取构造方法对象
调用是构造方法类Constructor的newInstance(Object... initargs)方法新建对象
调用Class对象的getMethod(String name, Class<?>... parameterTypes)获取方法对象
调用方法对象类Method的invoke(Object obj, Object... args)方法,调用对象上相应方法
 

1.3获取类对象的时候,会导致类属性被初始化

通过在Hero类中增加static属性,以及在代码块进行初始化的方式进行验证

static String copyright;

static{

System.out.println("初始化 copyright");

}

除了直接使用 Class c = Hero.class 这种方式,其他途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。

应用在jdbc

 

2.创建对象

import java.lang.reflect.Constructor;
import charactor.Hero;
public class TestReflection {
  
    public static void main(String[] args) {
        //传统的使用new的方式创建对象
        Hero h1 =new Hero();
        h1.name = "teemo";
        System.out.println(h1);
          
        try {
            //使用反射的方式创建对象
            String className = "charactor.Hero";
            //类对象
            Class pClass=Class.forName(className);
            //构造器
            Constructor c= pClass.getConstructor();
            //通过构造器实例化
            Hero h2= (Hero) c.newInstance();
            h2.name="gareen";
            System.out.println(h2);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

3.修改属性

为了访问属性,把name修改为public。
对于private修饰的成员,需要使用setAccessible(true)才能访问和修改。不在此知识点讨论。

public class TestReflection {
  
    public static void main(String[] args) {
            Hero h =new Hero();
            //使用传统方式修改name的值为garen
            h.name = "garen";
            try {
                //获取类Hero的名字叫做name的字段
                Field f1= h.getClass().getDeclaredField("name");
                //修改这个字段的值
                f1.set(h, "teemo");
                //打印被修改后的值
                System.out.println(h.name);
                 
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }
}

getField和getDeclaredField的区别

getField和getDeclaredField的区别
这两个方法都是用于获取字段
getField 只能获取public的,包括从父类继承来的字段。
getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 (注: 获取到private的字段,但还是不能访问该private字段的值,除非加上  f1.setAccessible(true)   )

4.调用方法  

通过反射机制调用Hero的setName

import java.lang.reflect.Method;
 
import charactor.Hero;
 
public class TestReflection {
 
    public static void main(String[] args) {
        Hero h = new Hero();
 
        try {
            // 获取这个名字叫做setName,参数类型是String的方法
            Method m = h.getClass().getMethod("setName", String.class);
            // 对h对象,调用这个方法
            m.invoke(h, "盖伦");
            // 使用传统的方式,调用getName方法
            System.out.println(h.getName());
 
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

4.有什么用?

通常来说,需要在学习了Spring 的依赖注入,反转控制之后,才会对反射有更好的理解,所以在这里举两个例子,来演示一下反射的一种实际运用。

业务类

首先准备两个业务类,这两个业务类很简单,就是各自都有一个业务方法,分别打印不同的字符串

package reflection;

public class Service1 {
	public void doService1() {
		System.out.println("业务方法1");
	}
}
package reflection;

public class Service2 {
	public void doService2() {
		System.out.println("业务方法2");
	}
}

 

场景模拟:当需要从第一个业务方法切换到第二个业务方法的时候

4.1非反射方式  

必须修改代码,并且重新编译运行,才可以达到效果

package reflection;

public class Test {
public static void main(String[] args) {
	//new Service1().doService1(); //修改代码,重新编译
	new Service2().doService2();
}
}

4.2反射方式

首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。 里面存放的是类的名称,和要调用的方法名。

class = reflection.Service2
method = doService2

当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件spring.txt,再运行即可。

这也是Spring框架的最基本的原理,只是它做的更丰富,安全,健壮。

 

package reflection;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test {
	@SuppressWarnings({ "rawtypes", "unchecked" })//屏蔽一些警告
public static void main(String[] args) throws Exception {
	File springConfigFile = new File("D:\\project\\test\\src\\spring.txt");
	Properties pps = new Properties();
	pps.load(new FileInputStream(springConfigFile));
	String className = (String) pps.get("class");
	String methodName = (String) pps.get("method");
	
	//根据类名称获取类对象
	Class clazz = Class.forName(className);
	//根据方法名称,获取方法对象
	Method m = clazz.getMethod(methodName);
	//获取构造器
	Constructor c =clazz.getConstructor();
	//实例化对象
	Object service =c.newInstance();
	m.invoke(service);
}
}