java之更快学习反射

反射是什么?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。其实就是对类的解剖。

哪里用到反射机制?

a、JDBC中,利用反射动态加载了数据库驱动程序。
b、Web服务器中利用反射调用了Sevlet的服务方法。
c、Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
d、很多框架都用到反射机制,注入属性,调用方法,如Spring。

反射有什么作用?

如果给定一个类名,就可以通过反射机制来获取类的所有信息,也可以动态的创建对象和编译;
反射的实现主要借助以下四个类:
1、Class:类的对象;
2、Constructor:类的构造方法
3、Field:类中的属性对象
4、Method:类中的方法对象

获取字节码的三种方式

测试对象Person.java

public class Person {
    public String name;
    private int age;
    public Person(){
        System.out.println("无参数构造方法!");
    }
    public Person(String name,int age){
        System.out.println("有参数构造方法!"+name+"--->"+age);
    }
    public Person(String name){
        System.out.println("一个有参数构造方法!"+name);
    }
    public Person(int age){
        System.out.println("一个有参数构造方法--->"+age);
    }
    public void setName(String name){
        System.out.println("传入的是:"+name);
        this.name = name;
    }
    public String getName() {
        System.out.println("调用getName:"+name);
        return name;
    }
    public void setAge(int age) {
        System.out.println("传入的是:"+age);
        this.age = age;
    }
    public int getAge() {
        System.out.println("调用getAge:");
        return age;
    }
    private void show(String name){
        System.out.println("show我的姓名:"+name);
    }
   public void show(){
        System.out.println("show我的姓名null:");
    }
}

方式一

/**
 * 方式一:
 * 使用 .class 获取字节码对象
 *
 */
public void getObject1() throws IllegalAccessException, InstantiationException {
    //原来  new 只能拿到已经知道的  只能是自己
    // .class  没有.java
    //通过反射获取对象  变得高级啦 实现变得复杂啦
    Person person = new Person();
    //反射
    //获取字节码对象
    Class<Person> clazz = Person.class;
    Class<Person> clazz1 = Person.class;

    //判断两个字节码对象是不是同一个
    System.out.println(clazz == clazz1);//true
    //使用字节码的newInstance()方法实例化对象  无参数构造
    //Person person1 = clazz.newInstance();

}

方式二

/**
 * 方式二:
 * 使用Object.getClass()方法 获取字节码对象;
 * 1、通过反射获取shi有的private
 * 2、要使用new 不方便
 */
public void getObject2(){
    //创建对象
    Person person = new Person();
    //获取字节码对象
    Class<? extends Person> aClass = person.getClass();
    //等价上面两步 Class<? extends Person> aClass1 = new Person().getClass();
    Class<? extends Person> bClass = person.getClass();
    //判断两个字节码对象是否相等
    System.out.println(aClass == bClass);//true
}

方式三

/**
 * 方式三:
 * 使用 Class 的forName("") 获取字节码文件
 * @CallerSensitive
 *     public static Class<?> forName(String className)
 *                 throws ClassNotFoundException {
 *         Class<?> caller = Reflection.getCallerClass();
 *         return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
 *     }
 *
 * 这个重点掌握的
 * 只需要知道class的名称就ok了
 */
public void getObject3() throws ClassNotFoundException {
    //早期
    //com.tedu.reflect.Person p = new com.tedu.reflect.Person();
    //定义class名称
    String className = "com.test.reflect.Person";
    //使用class名称获取字节码文件
    Class<?> aClass = Class.forName(className);
    Class<?> bClass = Class.forName(className);
    //判断字节码对象
    System.out.println(aClass==bClass);
    //规范出发  需要有配置文件
}

获取构造方法

获取无参构造方法

/**
 * 功能:获取无参构造方法
 * @throws IllegalAccessException
 * @throws InstantiationException
 * @throws ClassNotFoundException
 */
public void getConstructor1() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
    //定义class名称
    String className = "com.tedu.reflect.Person";
    //使用className获取字节码对象
    Class<Person> aClass = (Class<Person>) Class.forName(className);
    //创建一个对象
    Person person = aClass.newInstance();//打印
    //运行show方法
    person.show();//打印

}

获取有参数构造方法

/**
 * 功能:获取有参数构造方法
 *
 * @throws NoSuchMethodException
 * @throws ClassNotFoundException
 * @throws IllegalAccessException
 * @throws InvocationTargetException
 * @throws InstantiationException
 */
public void getConstructor2() throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //定义class名称
    String className = "com.test.reflect.Person";
    //使用forName(“”)获取字节码对象
    Class<?> aClass = Class.forName(className);
    //获取有参数的构造方法  传入类型的字节码对象
    Constructor<?> constructor = aClass.getConstructor(String.class, int.class);
    //获取实例化对象
    Person instance = (Person) constructor.newInstance("小花", 18);
    //设置name
    instance.setName("小强");

}

/**
 * 功能:自己实现单个的构造方法
 *
 * @throws NoSuchMethodException
 * @throws IllegalAccessException
 * @throws InvocationTargetException
 * @throws InstantiationException
 */
public void getConstructor3() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //使用反射做等同于下面的构造方法
    //Person xiaohu = new Person("xiaohu");
    //获取字节码对象
    Class<Person> personClass = Person.class;//换种方式,换种心情
    //获取一个参数的构造方法 传入一个String的字节码对象 定义类型
    Constructor<Person> constructor =
            personClass.getConstructor(String.class);
    //实例化对象   new Person("xiaohu");
    Person person = constructor.newInstance("xiaohu");
}

获取属性

/**
  * 功能:
  *    获取属性  public的
  *
  * @throws NoSuchFieldException
  * @throws IllegalAccessException
  * @throws InstantiationException
  */
 public void getField1() throws NoSuchFieldException, IllegalAccessException, InstantiationException {

     //获取字节码对象
     Class<Person> personClass = Person.class;//换种方式,换种心情
     Person person = personClass.newInstance();
     //通过名称获取属性
     Field field = personClass.getField("name");//public修饰的
     //不使用setName方法赋值  对象   设置的值
     field.set(person,"huhua");
     //获取name,打印
     person.getName();

     //等同于上面
     Person person1 = new Person();
     person1.name="huhua";
     person1.getName();
 }
	
/**
 * 功能:不知道属性名称  不知道属性类型
 *
 * @throws ClassNotFoundException
 * @throws IllegalAccessException
 * @throws InstantiationException
 */
public void getField3() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    //1、获取字节码对象
    String className = "com.tedu.reflect.Person";
    Class<?> clazz = Class.forName(className);
    Object obj = clazz.newInstance();
    //2、获取字节码的属性 获取所有属性
    Field[] fields = clazz.getDeclaredFields();
    //简单
   /* for (int i=0;i<fields.length;i++){
        Field field = fields[i];
        //3、设置属性的访问权限 暴力访问
        field.setAccessible(true);
        //获取属性的类型
        Class<?> type = field.getType();
        //4、赋值  type要使用包装类型
        setF(obj,field,type,"xioaxiao");
        //5、获取属性值
        System.out.println(field.get(obj));
    }*/
    //增强for循环
    for (Field field:fields) {
        //3、设置属性的访问权限 暴力访问
        field.setAccessible(true);
        //获取属性的类型
        Class<?> type = field.getType();
       setF(obj,field,type,"xioaxiao");
        //5、获取属性值
        System.out.println(field.get(obj));
    }
}
	/**
 * 功能:封装 设置value
 *
 * @param obj
 * @param field
 * @param type
 * @param value
 * @throws IllegalAccessException
 */
public void setF(Object obj,Field field,Class<?> type,Object value) throws IllegalAccessException {
    System.out.println(type);
   //判断类型
    if (type==String.class){
        field.set(obj,value);
    }else if (type==Integer.class){
        //Iinterger cast()强制装换
        field.set(obj,type.cast(value));
    }else if (type==Boolean.class){
        field.set(obj,type.cast(value));
    }else if (type==Short.class){
        field.set(obj,type.cast(value));
    }else if (type == Long.class){
        field.set(obj,type.cast(value));
    }else if (type == Byte.class){
        field.set(obj,type.cast(value));
    }else if (type == Double.class){
        field.set(obj,type.cast(value));
    }else if (type == Float.class){
        field.set(obj,type.cast(value));
    }
}

获取方法

/**
  * 功能:获取一般方法
  * @throws ClassNotFoundException
  * @throws IllegalAccessException
  * @throws InstantiationException
  * @throws NoSuchMethodException
  * @throws InvocationTargetException
  */
 public void getMethod1() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
     //1、获取字节码对象
     String className = "com.tedu.reflect.Person";
     Class<?> clazz = Class.forName(className);
     Object obj = clazz.newInstance();
     //2、获取方法  下面的只能获取public的
    // Method show = clazz.getMethod("show");
    // Method show1 = clazz.getMethod("show", String.class);

     //能够获取所有的方法
     Method show = clazz.getDeclaredMethod("show");
     Method show1 = clazz.getDeclaredMethod("show",String.class);
     //设置访问权限 暴力访问设置  作为黑客专用
     show1.setAccessible(true);
     //3、对方法赋值 传入参数 4、使用方法
     show.invoke(obj);
     show1.invoke(obj,"xiaoxiao");

//---------------******------------------
     String name = show.getName();
     int parameterCount = show1.getParameterCount();
     TypeVariable<Method>[] typeParameters = show.getTypeParameters();

 }

/**
 * 在日志系统使用
 *
 * 这个方法非常重要  login
 *    show(String name)  监控
 *    传入的值
 *    传入的类型
 *    指定我监控的方法
 */
public void getMethod2() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
    System.out.println("GetClassDemo.getMethod2");//soutm
    //1、获取字节码对象
    Class<Person> clazz = Person.class;
    //实例化对象  调用无参构造方法
    Person obj = clazz.newInstance();
    //2、获取字节码对象的方法
    Method show = clazz.getDeclaredMethod("show", String.class);
    show.setAccessible(true);
    //3、赋值和使用
    Object o = show.invoke(obj, "小小");
    //获取方法的名称
    String name = show.getName();
    System.out.println("方法名称:"+name);
    //获取方法的参数数量
    int parameterCount = show.getParameterCount();
    System.out.println("参数列表数量:"+parameterCount);

    //获取参数类型
    Class<?>[] parameterTypes = show.getParameterTypes();
    //show.getDeclaredAnnotations();
    for (Object m:parameterTypes) {
        System.out.println("参数类型:"+m);
    }
    //获取返回值类型
    Class<?> returnType = show.getReturnType();
    System.out.println("获取返回值类型:"+returnType);
}

应用练习1

NetCard.java

public class NetCard implements PCI {

	@Override
	public void open() {
		System.out.println("net open");
	}

	@Override
	public void close() {
		System.out.println("net close");
	}

}

SoundCard.java

public class SoundCard implements PCI {
	public void open(){
		System.out.println("sound open");
	}
	public void close(){
		System.out.println("sound close");
	}

}

Mainboard.java

public class Mainboard {

	public void run() {
		System.out.println("main board run....");
	}

	public void usePCI(PCI p) {//PCI p = new SouncCard();
		if (p != null) {
			p.open();
			p.close();
		}
	}
}

PCI.java

public interface PCI {
	
	public void open();
	public void close();

}

ReflectTest.java

/*
 * 电脑运行。 
 */
public class ReflectTest {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {

		Mainboard mb = new Mainboard();
		mb.run();
		//每次添加一个设备都需要修改代码传递一个新创建的对象
//		mb.usePCI(new SoundCard());
		//能不能不修改代码就可以完成这个动作。 
//		不用new来完成,而是只获取其class文件。在内部实现创建对象的动作。 
		File configFile = new File("pci.properties");
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream(configFile);
		prop.load(fis);
		for(int x=0; x<prop.size(); x++){
			String pciName = prop.getProperty("pci"+(x+1));
			Class clazz = Class.forName(pciName);//用Class去加载这个pci子类。 
			PCI p = (PCI)clazz.newInstance();
			mb.usePCI(p);
		}
		fis.close();
		
	}

}

应用练习2

--反射与工厂设计模式

这时可以发现,利用反射机制实现的工厂设计模式,最大的优势:对于接口子类的扩充将不再影响到工厂类的定义。

JavaApiDemo.java
public class JavaApiDemo {
    public static void main(String[] args) throws Exception {
        IMessage msg=Factory.getInstance("com.mldn.demo.NetMessage",IMessage.class);
        msg.send();//【网络消息发送】www.baidu.com
        msg=Factory.getInstance("com.mldn.demo.CloudMessage",IMessage.class);
        msg.send();//【云消息发送】www.baidu.com
        IService service=Factory.getInstance("com.mldn.demo.HouseService",IService.class);
        service.service();
    }}class Factory{
    private Factory(){}
    /**
     * 获取接实例化对象
     * @param className 接口的子类
     * @param clazz 描述的是一个接口的类型
     * @return 如果子类存在则返回指定接口的实例化对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getInstance(String className,Class<T> clazz){
        T instance=null;
        try {
            instance=(T) Class.forName(className).getDeclaredConstructor().newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }}interface IService{
    void service();}class HouseService implements IService{
    @Override
    public void service() {
        System.out.println("【服务】为您的住宿提供服务");
    }}interface IMessage{
    void send();//消息发送}class NetMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【网络消息发送】www.baidu.com");
    }}class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【云消息发送】www.baidu.com");
    }}

课后作业

1 、写一个方法,此方法可以获取obj对象中名为propertyName(自定义)的属性的值
2.(1)写一个Properties格式的配置文件,配置类的完整名称。
(2) 写一个程序,读取这个Properties配置文件,获得类的完整名称并加载这个类。
3、 写一个方法,此方法可将obj对象中名为propertyName的属性的值设置为value.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值