java反射的深入(二)

简介: 通过反射调用类的方法在正常情况下一个类的对象功能产生之后,就可以直接调用类中的方法了,若想要调用,则必须知道方法名称,之后用Class类中的 getMethod()方法 ,public Method getMethod(String name ,Class  .

通过反射调用类的方法

在正常情况下一个类的对象功能产生之后,就可以直接调用类中的方法了,若想要调用,则必须知道方法名称,之后用Class类中的 getMethod()方法 ,

public Method getMethod(String name ,Class<?>  ...   parameterTypes)

然后invoke(Method对象)来执行方法, 

接上例:

package com.java.reflect;

import java.lang.reflect.Method;

public class InvokesayChinaDemo {
	public static void main(String[] args) {
		Class<?> c1 = null;
		try {
			c1 = Class.forName("com.java.reflect.PersonDemo1");// 实例化对象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		try {
			Method met = c1.getMethod("sayChina");// 找到sayChina方法
			met.invoke(c1.newInstance());// 调用方法
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

通过Class类的getMethod()方法根据一个类中的方法名称可以取得Method对象,并通过invoke调用指定的方法,但是在使用invoke()方法的时候必须传入一个类的实例化对象,因为在sayChina()方法上没有任何的参数,所以没有设定参数类型和参数内容。


改进后:

package com.java.reflect;

import java.lang.reflect.Method;

public class InvokesayChinaDemo {
	public static void main(String[] args) {
		Class<?> c1 = null;
		try {
			c1 = Class.forName("com.java.reflect.PersonDemo1");// 实例化Class对象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		try {
			Method met = c1.getMethod("sayChina");// 找到sayChina方法
			met.invoke(c1.newInstance());// 调用方法

			Method meth = c1.getMethod("sayHello", String.class, int.class);
			String rv = null;
			rv = (String) meth.invoke(c1.newInstance(), "汪兵", 25);//调用方法
			System.out.println(rv);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


通过反射调用类setter和getter


package com.java.reflect;

import java.lang.reflect.Method;

public class InvokeSetterGetterDemo {
	public static void main(String[] args) {
		Class<?> c1 = null;
		Object obj = null;
		try {
			c1 = Class.forName("com.java.reflect.PersonDemo1");// 实例化Class对象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		try {
			obj = c1.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		setter(obj, "name", "李兴华", String.class);// 设置setter方法
		setter(obj, "age", 25, int.class);// 设置setter方法
		System.out.println("年龄:");
		getter(obj, "age");
		System.out.println("姓名:");
		getter(obj, "name");
	}

	public static void getter(Object obj, String att) {
		try {
			Method met = obj.getClass().getMethod("get" + initStr(att));
			System.out.println(met.invoke(obj));// 调出getter的内容
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Object obj:要操作的对象 String att:要操作的属性 Object value:设置属性值
	 * Class<?>type:设置属性类型
	 */
	public static void setter(Object obj, String att, Object value,
			Class<?> type) {
		Method met = null;
		try {
			met = obj.getClass().getMethod("set" + initStr(att), type);// 得到setter方法
			// 设置setter内容
			met.invoke(obj, value);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static String initStr(String old) {// 将单词的首字母大写
		String str = old.substring(0, 1).toUpperCase() + old.substring(1);
		return str;

	}
}


通过反射调用属性

如果现在假设要操作一个类中的属性,则也可以通过Filed完成,而不必麻烦的通过setter和getter方法

得到公共属性:

public Field getField (String  name )

得到本类属性:

public Field getDeclaredField (String  name )

取得属性内容:

public Object get(Object  obj)

设置属性内容:

public  void  set(object  obj,object  value)

package com.java.reflect;

import java.lang.reflect.Field;

public class InvokeFieldDemo {
    public static void main(String[] args) {
	Class<?> c1 = null;
	Object obj = null;
	try {
	    c1 = Class.forName("com.java.reflect.PersonDemo1");
	} catch (ClassNotFoundException e) {
	    e.printStackTrace();
	}
	try {
	    obj = c1.newInstance();
	} catch (InstantiationException e) {
	    e.printStackTrace();
	} catch (IllegalAccessException e) {
	    e.printStackTrace();
	}
	Field nameField = null;
	Field ageField = null;
	try {
	    nameField = c1.getDeclaredField("name");
	    ageField = c1.getDeclaredField("age");
	    nameField.setAccessible(true);// 设置私有属性可见
	    ageField.setAccessible(true);
	    nameField.set(obj, "sdfsdfsd");
	    ageField.set(obj, 23);
	    System.out.println("姓名:" + nameField.get(obj));
	    System.out.println("年龄" + ageField.get(obj));
	} catch (NoSuchFieldException | SecurityException
		| IllegalArgumentException | IllegalAccessException e) {
	    e.printStackTrace();
	}

    }
}

通过反射操作数组

反射机制不光只使用在类中,也可以应用在任意的引用数据类型上,当然包含了数组,数组使用Array类完成

public Class<?> getComponentType()
得到数组指定下标的内容:

public static Object get(Object array,
         int index)
                  throws IllegalArgumentException,
                         ArrayIndexOutOfBoundsException
public static void set(Object array,
              int index,
              boolean z)
                       throws IllegalArgumentException,
                              ArrayIndexOutOfBoundsException
开辟新的数组:

public static Object newInstance(Class<?> componentType,
                 int... dimensions)
                          throws IllegalArgumentException,
                                 NegativeArraySizeException
取得数组的内容:

package com.java.reflect;

import java.lang.reflect.Array;

public class ClassArrayDemo {
    public static void main(String[] args) {
	int temp[] = { 1, 2, 3 };
	Class<?> c = temp.getClass().getComponentType();// 取得数组的Class对象
	System.out.println("类型:" + c.getName());// 取得数组类型的名称
	System.out.println("长度:" + Array.getLength(temp));
	System.out.println("第一个内容是:" + Array.getInt(temp, 1));// 得到第一个数组的内容
	Array.set(temp, 2, 20);
	System.out.println(temp[2]);
    }
}

使用Array类还可以修改数组的大小:(实际上就是新建一个新的数组,将旧的数据复制进去)

package com.java.reflect;

import java.lang.reflect.Array;

public class ChangeArrayDemo {
    public static void main(String[] args) {
	int temp[] = { 1, 2, 3 };
	int newTemp[] = (int[]) arrayInc(temp, 5);// 重新开辟空间
	print(newTemp);
    }

    public static Object arrayInc(Object obj, int len) {// 建立新的数组并拷贝
	Class<?> c = obj.getClass();
	Class<?> arr = c.getComponentType();// 得到数组的Class
	Object newO = Array.newInstance(arr, len);// 拷贝内容
	int co = Array.getLength(obj);
	System.arraycopy(obj, 0, newO, 0, co);// 拷贝数组
	return newO;
    }

    public static void print(Object obj) {// 数组输出
	Class<?> c = obj.getClass();
	if (!c.isArray()) {// 判断是否是数组
	    return;
	}
	Class<?> arr = c.getComponentType();
	System.out.println(arr.getName() + "数组长度是:" + Array.getLength(obj));
	for (int i = 0; i < Array.getLength(obj); i++) {
	    System.out.print(Array.get(obj, i) + "、");// 通过Array输出

	}
    }
}

代理设计:

一个操作的接口有两个子类,其中一个是真是主题的实现类,另一个是代理类,代理实现类要完成比真实主体实现类更多的内容,而且本身还需要处理一些与具体业务有关的程序代码。

package com.java.reflect;

interface Subject {
    public String say(String name, int age);
}

class RealSubject implements Subject {

    @Override
    public String say(String name, int age) {
	return "姓名:" + name + ",年龄:" + age;
    }
}

class ProxySubject implements Subject {
    private Subject sub = null;

    public ProxySubject(Subject sub) {
	this.sub = sub;
    }

    @Override
    public String say(String name, int age) {
	return this.sub.say(name, age);
    }
}

public class DyProxyDemo {
    public static void main(String[] args) {
	Subject sub = new ProxySubject(new RealSubject());
	String info = sub.say("李兴华", 99);
	System.out.println(info);
    }
}

以上代码称为静态代理,一个代理只能为一个接口服务,


InvocationHandler接口:

public  interface   InvocationHandler{

Object invoke(Object proxy,
              Method method,
              Object[] args)
              throws Throwable
}

Object proxy:被代理的接口

 Method method:要调用的方法

 Object[] args:方法调用时所需要的参数


可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject


Proxy类

 是专门完成代理的操作类,可以通过此类为一个或者多个接口动态地生成实现类,此类提供如下的方法 
 

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException
loader - 定义代理类的类加载器  
interfaces - 代理类要实现的接口列表
h - 得到的InvocationHandle接口子类实例

 类加载器:

图1 图1


工厂设计模式:

实例:

package com.java.reflect;

interface Fruit {
    public void eat();
}

class Apple implements Fruit {
    public void eat() {
	System.out.println("eat apple");
    }
}

class Orange implements Fruit {
    public void eat() {
	System.out.println("eat orange");
    }
}

// 工厂类
class Factory {
    public static Fruit getInstance(String className) {
	Fruit fruit = null;
	fruit = null;
	if ("apple".equals(className)) {
	    fruit = new Apple();
	}

	if ("orange".equals(className)) {
	    fruit = new Apple();
	}
	return fruit;
    }

}

public class FactoryDemo01 {
    public static void main(String[] args) {
	Fruit f = Factory.getInstance("apple");
	if (f != null) {
	    f.eat();
	}
    }

}

如果扩充了一个子类,则肯定要修改工厂类,如果希望扩充子类时不用修改工厂类的话,则必须使用反射完成。

例子:

package com.java.reflect;

interface Fruit {
    public void eat();
}

class Apple implements Fruit {
    public void eat() {
	System.out.println("eat apple");
    }
}

class Orange implements Fruit {
    public void eat() {
	System.out.println("eat orange");
    }
}

// 工厂类
class Factory {
    public static Fruit getInstance(String className) {
	Fruit fruit = null;
	/**
	 * if ("apple".equals(className)) { fruit = new Apple(); }
	 * 
	 * if ("orange".equals(className)) { fruit = new Apple(); } return
	 * fruit; }
	 */
	try {
	    fruit = (Fruit) Class.forName(className).newInstance();
	} catch (Exception e) {
	    e.printStackTrace();
	}
	return fruit;
    }
}

public class FactoryDemo01 {
    public static void main(String[] args) {
	Fruit f = Factory.getInstance("com.java.reflect.Apple");
	if (f != null) {
	    f.eat();
	}
    }

}

以上在扩充子类时,不用修改工厂类,但是输入完整的“包.类”名称,比较麻烦,此时可以通过一些拍之文件的方式保存这些完整的类的路径。

图2图2


package com.java.reflectFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

interface Fruit {
    public void eat();
}

class Apple implements Fruit {
    public void eat() {
	System.out.println("eat apple");
    }
}

class Orange implements Fruit {
    public void eat() {
	System.out.println("eat orange");
    }
}

class Init {
    public static Properties getPro() {
	Properties pro = new Properties();
	File f = new File("F:/JAVA深入学习/fruit.properties");// 找到属性文件
	/**
	 * 配置文件的内容 apple =com.java.reflectFactory.Apple
	 * orange=com.java.reflectFactory.Orange
	 * */
	if (f.exists()) {// 如果文件存在
	    try {
		pro.load(new FileInputStream(f));
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	} else {
	    pro.setProperty("apple", "com.java.reflectFactory.Apple");
	    pro.setProperty("orage", "com.java.reflectFactory.Orange");
	    try {
		pro.store(new FileOutputStream(f), "FRUIT CLASS");
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}
	return pro;

    }
}

// 工厂类
class Factory {
    public static Fruit getInstance(String className) {
	Fruit fruit = null;
	try {
	    fruit = (Fruit) Class.forName(className).newInstance();
	} catch (Exception e) {
	    e.printStackTrace();
	}
	return fruit;
    }
}

public class FactoryDemo02 {
    public static void main(String[] args) {
	Properties pro = Init.getPro();
	Fruit f = Factory.getInstance(pro.getProperty("apple"));
	if (f != null) {
	    f.eat();
	}
    }
}

配置文件与程序相分离的!
相关文章
|
1月前
|
网络协议 算法 Java
|
1月前
|
XML Java 数据库连接
谈谈Java反射:从入门到实践,再到原理
谈谈Java反射:从入门到实践,再到原理
60 0
|
1月前
|
Java 程序员 编译器
认识Java 的反射机制
反射Reflection被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。反射是一种功能强大且复杂的机制。使用它的主要人员是工具构造者,而不是应用程序员。
29 5
|
1月前
|
Java 关系型数据库 MySQL
在Java的反射中,Class.forName和ClassLoader的区别
在Java的反射中,Class.forName和ClassLoader的区别
35 3
|
1天前
|
Java
Java 反射
Java 反射
|
2天前
|
设计模式 Java 索引
由反射引出的Java动态代理与静态代理
由反射引出的Java动态代理与静态代理
10 0
|
2天前
|
存储 Java Shell
深入剖析Java中的反射,由浅入深,层层剥离!
深入剖析Java中的反射,由浅入深,层层剥离!
8 1
|
7天前
|
监控 Java 开发者
掌握 Java 反射和动态代理
【4月更文挑战第19天】Java反射和动态代理提供强大功能和灵活性。反射允许运行时检查和操作类,获取类信息、动态调用方法,但可能带来性能损失和降低代码可读性。动态代理则用于创建代理对象,实现透明性和横切关注点分离,常用于日志、权限检查等。两者结合能实现更复杂功能。掌握这些技术能提升代码的灵活性和可扩展性,但也需注意性能和可读性。通过学习和实践,能更好地构建高效软件系统。
|
13天前
|
Java
代码的魔法师:Java反射工厂模式详解
代码的魔法师:Java反射工厂模式详解
26 0
|
17天前
|
安全 Java
java反射篇
java反射篇