25、创建并使用自己的类加载器
JVM中除了根加载器之外都是ClassLoader子类的实例,程序员可以通过扩展(extends)ClassLoader子类并重写它的方法来实现自定义的类加载器。
通过Class对象获取对应类的详细信息
public class ClassTest {
private ClassTest(){
}
public ClassTest(String s){
System.out.println("有参构造器");
}
public void info(){
System.out.println("无参方法");
}
public void info(String s){
System.out.println("有参方法,参数为:"+s);
}
static class Inner{
static{
System.out.println("Inner被加载");
}
}
public static void main(String[] args) throws Exception {
Class<ClassTest> clazz=ClassTest.class;
Constructor[] costors=clazz.getConstructors();
System.out.println("Class对象所对应类的全部public构造器");
for(Constructor c:costors){
System.out.println(c);
}
Constructor[] allcostors=clazz.getDeclaredConstructors();
System.out.println("Class对象所对应类的全部构造器");
for(Constructor c:allcostors){
System.out.println(c);
}
Method mtds[]=clazz.getDeclaredMethods();
System.out.println("Class对象所对应类的全部方法");
for(Method c:mtds){
System.out.println(c);
}
Class inClazz=Class.forName("ClassTest$Inner");
System.out.print("inClazz对应的外部类:"+inClazz.getDeclaringClass());
}
}
26、使用反射生成并操作对象
Class对象可以获得的该类里的成分包括方法(由Method对象表示)、构造器(由Constructor对象表示)、Field(由field对象表示),这三个类都定义在java.lang.reflect包下。程序可以通过Method对象来执行对应的方法,通过Constructor对象来调用对应的构造器创建对象,能通过Field对象来直接访问并修改对象的属性值。
每个类加载之后,系统会为该类生成一个Class对象,通过Class对象就可以访问到JVM中的这个类了,Java中通常有三种方式获得Class对象:
Class.forName():使用Class类的static方法forName("XXX")
Person.class:调用某个类的class属性来获取该类对应的Class对象。
调用某个对象的getClass()方法,该方法是java.lang.Object类中的一个方法,它返回该对象所属类对应的Class对象
例程:
import java.io.FileInputStream;
import java.util.*;
public class ObjectPoolFactory {
//定义一个对象池,前面是对象名,后面是实际对象
private Map<String,Object> objectPool=new HashMap<String,Object>();
//定义一个创建对象的方法,该方法只要传入一个字符串类名,程序就可以根据类名来生成java对象
private Object creatObjet(String clazzName) throws ClassNotFoundException, InstantiationException,
IllegalAccessException{
Class<?> clazz=Class.forName(clazzName);//使用反射来创建某个类或接口对应的java.lang.Class对象
return clazz.newInstance();
}
//该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象
public void initPool(String fileName){
FileInputStream fis=null;
try {
fis=new FileInputStream(fileName);
Properties prop=new Properties();
prop.load(fis);
System.out.println("prop.stringPropertyNames():"+prop.stringPropertyNames());
for(String name:prop.stringPropertyNames()){
objectPool.put(name, creatObjet(prop.getProperty(name)));
}
} catch (Exception e) {
System.out.println("读取"+fileName+"异常!");
}
finally{
try {
if(fis!=null){
fis.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
//从object中取出指定name对应的对象
public Object getObject(String name){
return objectPool.get(name);
}
public static void main(String[] args) {
ObjectPoolFactory ofy=new ObjectPoolFactory();
ofy.initPool("obj.txt");
System.out.println(ofy.getObject("a"));
System.out.println(ofy.getObject("c"));
}
}
/*输出
prop.stringPropertyNames():[b, a, c]
Mon Apr 28 22:15:50 CST 2014
[]
*/
配置文件obj.txt
a=java.util.Date
b=javax.swing.JFrame
c=java.util.ArrayList
加强版的 ObjectPoolFactory例程(可以使用方法来改变属性值)
配置文件改为extObj.txt
a=javax.swing.JFrame
b=javax.swing.JLabel
#set the title of a
a%title=Test Title
import java.io.FileInputStream;
import java.lang.reflect.*;
import java.util.*;
public class ExtendObjectPoolFactory {
//定义一个对象池,前面是对象名,后面是实际对象
private Map<String,Object> objectPool=new HashMap<String,Object>();
//定义一个创建对象的方法,该方法只要传入一个字符串类名,程序就可以根据类名来生成java对象
private Object creatObjet(String clazzName) throws ClassNotFoundException, InstantiationException,
IllegalAccessException{
Class<?> clazz=Class.forName(clazzName);
return clazz.newInstance();
}
private Properties config=new Properties();
//该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象
public void initPool(String fileName){
FileInputStream fis=null;
try {
fis=new FileInputStream(fileName);
config.load(fis);
//System.out.println("prop.stringPropertyNames():"+prop.stringPropertyNames());
//对于每取出的属性名、属性值对,如果属性名中不包含%,就根据属性值创建一个对象,并将对象放入对象池中
for(String name:config.stringPropertyNames()){
if(!name.contains("%")){
objectPool.put(name, creatObjet(config.getProperty(name)));
}
}
} catch (Exception e) {
System.out.println("读取"+fileName+"异常!");
}
finally{
try {
if(fis!=null){
fis.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
//每取出一对属性名-属性值对,如果属性名中包含百分号(%),即可认为该属性是用于为对象设置属性值
//程序将调用对应的setter方法来为对应的属性设置属性值
public void initPropertyByMethodReflect() throws SecurityException, NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException{
for(String name:config.stringPropertyNames()){
if(name.contains("%")){
String[] keyAndValue=name.split("%");
Object target=getObject(keyAndValue[0]);
//String mtdName="set"+keyAndValue[1].substring(0,1).toUpperCase()+keyAndValue[1].substring(1);
String mtdName="setTitle";//与上面的语句功能相同
//通过对象的getClass方法获取他的实现类对应的Class对象
Class<?> clazz=target.getClass();
Method mtd=clazz.getMethod(mtdName,String.class);
mtd.invoke(target, config.getProperty(name));
}
}
}
//从object中取出指定name对应的对象
public Object getObject(String name){
return objectPool.get(name);
}
public static void main(String[] args) throws Exception {
ExtendObjectPoolFactory ofy=new ExtendObjectPoolFactory();
ofy.initPool("extObj.txt");
ofy.initPropertyByMethodReflect();
System.out.println(ofy.getObject("a"));
}
}
27、通过反射访问属性值
import java.lang.reflect.*;
import static java.lang.System.*;
public class FieldTest {
public static void main(String[] args) throws Exception {
Person p=new Person();
Class<Person> personClass=Person.class;
// 使用getDeclaredField方法获取各种控制符的field
Field namefield=personClass.getDeclaredField("name");
//设置通过反射来访问Field时取消访问权限检查
namefield.setAccessible(true);
namefield.set(p, "zpc周");
Field agefield=personClass.getDeclaredField("age");
agefield.setAccessible(true);
agefield.set(p, 22);
out.println(p);
}
}
class Person{
private String name;
private int age;
public String toString(){
return "Person[name="+name+",age="+age+"]";
}
}
//输出:Person[name=zpc周,age=0]
28、泛型与反射
import java.util.Date;
import javax.swing.JFrame;
public class ReflectAndGeneric {
public static <T> T getInstance(Class<T> cls){
try {
return cls.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Date d=ReflectAndGeneric.getInstance(Date.class);
JFrame jfm=ReflectAndGeneric.getInstance(JFrame.class);
}
}