您的位置:首页 > 职场人生

黑马程序员——高新技术总结

2013-04-14 16:30 218 查看
------- android培训java培训、期待与您交流!
----------


反射

 

Class类

class类是对对象的抽象,而Class是对class的抽象,或者说类是对对象的共性的描述,而Class又是对类的共性的描述,但它本身又是一个类,它的具体实例是内存中某个类的字节码。

得到类的字节码的方式有三种:

对象.getClass()
类名.class
Class.forName("完整类名“)
Class.forName()的作用:如果有要获得的字节码存在于内存中就直接返回,如果不存在,则通过类加载器将其 .clas文件加载后返回。

九种预定义的Class实例对象:表示八个基本类型和void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即boolean、byte、char、short、int、long、float 和double。

数组的Class实例对象:类型[ ].class,可以用isArray()方法判断一个Class实例是否为数组。

String str = "abc";
Class cls1 = str.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");

System.out.println(cls1 == cls2);
System.out.println(cls1 == cls3);

System.out.println(cls1.isPrimitive());
System.out.println(int.class.isPrimitive());
System.out.println(Integer.class.isPrimitive());
System.out.println(Integer.TYPE.isPrimitive());
System.out.println(int[].class.isArray());

 

总之,反射就是把java类中的各种成分映射成java类。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,得到这些对象后有什么用?怎么用?是学习和应用的要点。

部分反射API

 

Construtcor类

得到某个类的所有构造方法:

Constructor[] constructors=String.class.getConstructors();
Constructor[] constructors=String.class.getDeclaredConstructors();//包括私有的得到某个类的某个构造方法:会用到参数类型的Class对象
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);

创建实例对象:参数要用获得构造方法时指定的类型。

普通方式:String str = new String(new StringBuffer("abc"));
反射方式:String str1 =(String) constructor1.newInstance(new StringBuffer("abc"));

Class也提供了newInstance,其内部是利用Constructor的newInstance的无参方法。

Field类

类的成员变量,它的具体实例代表的的是类中某个字段的定义,而非具体的变量。

public class ReflectPoint{
private int x;
public  int y;
public String str1 = "Master";
public String str2 = "Basketball";
public String str3 = "itcast";

public ReflectPoint(int x ,int y){
super();
this.x=x;
this.y = y;
}
}


对于上边的类ReflectPoint如何获取其字段x,和y的值?
代码如下:
访问public成员变量:
ReflectPoint ref = new ReflectPoint(4,8);
Field fieldY =ref.getClass().getField("y");
System.out.println(fieldY.get(ref));


访问private成员变量:

//暴力反射,用getDeclaredField()取出包括私有在内的所有变量
Field fieldX =ref.getClass().getDeclaredField("x");
//将私有变量设为可访问的
fieldX.setAccessible(true);
System.out.println(fieldX.get(ref));

 

综合应用案例:将RefectPoint中的所有String成员变量的值中的“a”,替换成“w”

private static void changeStringValue(Object obj) throws Exception {
Field [] fields = obj.getClass().getFields();
for(Field field:fields){
if(field.getType()==String.class){//字节码的比较用==更精确
String str =(String) field.get(obj);
String str1 = str.replace('a','w');
field.set(obj, str1);

}

}
}

 

 

类加载器

 

类加载器特点

类加载器是加载类的工具,它的作用是将硬盘上的.class文件加进内存,并对之进行一些处理。
java虚拟机中可安装多个类加载器,系统默认三个主要的类加载器,每个类加载器负责加载特定的类:
BootStrap
xitClassLoader
AppClassLoader

类加载器也是java类,因为其他是java类的类加载器也要被类加载器加载,显然必须有第一个类加载器不是java类, 这正是:BootStrap,它是由C++编写的。
java虚拟机中的所有类加载器采用具有  父子关系   的  树形结构  进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象,或者默认采用系统类加载器为其父级类加载器。
System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
System.out.println(System.class.getClassLoader());

体系结构

    |---Bootstrap ClassLoader   ->JRE/lib/rt.jar

       |---Extension ClassLoader ->JRE/lib/ext/*.jar

          |---ApplicationClassLoader ->ClassPath指定的所有jar或目录。

             |--MyClassLoader ->指定的特殊目录

             |--itcastClassLoader->指定的特殊目录

ClassLoader loader=ClassLoaderTest.class.getClassLoader();
while(loader!=null){
System.out.println(loader.getClass().getName());
loader=loader.getParent();
}
System.out.println(loader);


 

委托机制 

委托机制的过程

类加载器的选择:当java虚拟机要加载一个类时,到底派出那个类加载器去加载?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了B类,java虚拟机将使用类A的加载器来加载类B
还可以直接调用ClassLoader.loadClas
4000
s()方法来指定某个类加载器去加载某个类。

类加载器怎样加载:每个类加载器加载类时,又先委托给器上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不再去找发起者类加载器的儿子,因为没有getChild方法。

    
注意:需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。

编写自己的类加载器

知识点

自定义的类加载器必须继承ClassLoader。
loadClass方法与findClass方法:只需重新findClass方法,就会跳出委托机制。
defineClass方法。

编写步骤

编写一个队文件内容进行监督加密的程序
编写一个自己的类加载器,可实现对加密的类进行撞在和解码。
编写一个程序调用类加载器加载类,在源程序中不能用该类定义引用变量,因为编程器无法识别这个类。程序中可以除了使用ClassLoader.load方法外,还可以使用使用设置线程的上下文加载器或者系统加载器,然后再使用Class.forName.

代码部分

要加载的测试类代码

import java.util.Date;
public class ClassLoaderAttachments extends Date {
@Override
public String toString() {
return "hello,java";
}
}

注意:这里最好继承一个类,以便于获取其实例时,定义父类的引用,而不是它自己的引用。

编写自己的类加载器代码import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class MyClassLoader extends ClassLoader {

public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName =srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir+"\\"+destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis, fos);
System.out.println("xxxxx");
fis.close();
fos.close();

}

private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
String classFileName = classDir+"\\"+name+".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
byte[] b = bos.toByteArray();
return defineClass(b, 0, b.length);

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("aaaa");

return super.findClass(name);
}

public MyClassLoader(){

}
public MyClassLoader(String classDir){
this.classDir = classDir;

}

public static void cypher(InputStream ips,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b^0xff);
}
//这时候不用关闭,谁创建资源,谁关闭资源。
}

}
调用自己写的类加载器

Class clazz = new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachments");
Date d = (Date)clazz.newInstance();
System.out.println(d.toString());


 

 

JavaBean内省与beanutils工具包

JavaBean

JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

特点

JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。去掉set和get前缀,剩余部分就是属性名。如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。JavaBean必须有一个不带参数的构造方法。

用途

如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。

好处

一个符合JavaBean特点的类可以当作普通类一样进行使用,但如果把它当做JavaBean,那么就可以调用JDK提供的对专门对JavaBean进行操作的API,以实现对一些对普通类来说比较复杂的功能。

对JavaBean的简单内省操作 

用java.beans包中的PropertyDescriptor类把ReflectPoint当做JavaBean进行操作。

public static void setProperty(Object pt1, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException
{
PropertyDescriptor dp1 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = dp1.getWriteMethod();
methodSetX.invoke(pt1,value);
}
public static Object getProperty(Object pt1, String propertyName) throws IntrospectionException, IllegalAccessException,InvocationTargetException
{
PropertyDescriptor dp = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = dp.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
return retVal;
}
ReflectPoint pt1 = new ReflectPoint(1,1);
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println("getX:"+retVal);
Object value = 7;

setProperty(pt1, propertyName, value);
System.out.println("setX:"+pt1.getX());


 

使用BeanInfo类和IntroSpector类查看把ReflectPoint当做一个JavaBean看时,显示的信息,并获取"x"属性的值(即用另一种方式,实现3中getProperty方法)
public static Object getProperty(Object pt1, String propertyName) throws IntrospectionException, IllegalAccessException,InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] dps = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor dp:dps)
{
if(dp.getName().equals(propertyName)){
retVal = dp.getReadMethod().invoke(pt1);
break;
}
}
return retVal;


BeanUtils工具包

Apache提供的开源的操作JavaBean的工具包,它要和Apache的logging工具包导入到Project中,然后Build Path才可以使用。

里边的BeanUtil和PropertyUtils类使用示例如下:
ReflectPoint pt1 = new ReflectPoint(1,1);
BeanUtils.setProperty(pt1, "x", 25);
System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());
//BeanUtils可以实现属性链操作
BeanUtils.setProperty(pt1, "date.time", "111");//time不一定在类中存在,只是说明date有getTime和setTime方法。
System.out.println(BeanUtils.getProperty(pt1, "date.time"));
PropertyUtils.setProperty(pt1, "x", 160);
                  System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());

 

 

 

------- android培训java培训、期待与您交流!
----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 基础加强