黑马程序员——高新技术总结
2013-04-14 16:30
218 查看
------- android培训、java培训、期待与您交流!
----------
得到类的字节码的方式有三种:
对象.getClass()
类名.class
Class.forName("完整类名“)
Class.forName()的作用:如果有要获得的字节码存在于内存中就直接返回,如果不存在,则通过类加载器将其 .clas文件加载后返回。
九种预定义的Class实例对象:表示八个基本类型和void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即boolean、byte、char、short、int、long、float 和double。
数组的Class实例对象:类型[ ].class,可以用isArray()方法判断一个Class实例是否为数组。
总之,反射就是把java类中的各种成分映射成java类。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,得到这些对象后有什么用?怎么用?是学习和应用的要点。
创建实例对象:参数要用获得构造方法时指定的类型。
Class也提供了newInstance,其内部是利用Constructor的newInstance的无参方法。
对于上边的类ReflectPoint如何获取其字段x,和y的值?
代码如下:
访问public成员变量:
访问private成员变量:
综合应用案例:将RefectPoint中的所有String成员变量的值中的“a”,替换成“w”
java虚拟机中可安装多个类加载器,系统默认三个主要的类加载器,每个类加载器负责加载特定的类:
BootStrap
xitClassLoader
AppClassLoader
类加载器也是java类,因为其他是java类的类加载器也要被类加载器加载,显然必须有第一个类加载器不是java类, 这正是:BootStrap,它是由C++编写的。
java虚拟机中的所有类加载器采用具有 父子关系 的 树形结构 进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象,或者默认采用系统类加载器为其父级类加载器。
|---Extension ClassLoader ->JRE/lib/ext/*.jar
|---ApplicationClassLoader ->ClassPath指定的所有jar或目录。
|--MyClassLoader ->指定的特殊目录
|--itcastClassLoader->指定的特殊目录
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了B类,java虚拟机将使用类A的加载器来加载类B
还可以直接调用ClassLoader.loadClas
4000
s()方法来指定某个类加载器去加载某个类。
类加载器怎样加载:每个类加载器加载类时,又先委托给器上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不再去找发起者类加载器的儿子,因为没有getChild方法。
注意:需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。
loadClass方法与findClass方法:只需重新findClass方法,就会跳出委托机制。
defineClass方法。
编写一个自己的类加载器,可实现对加密的类进行撞在和解码。
编写一个程序调用类加载器加载类,在源程序中不能用该类定义引用变量,因为编程器无法识别这个类。程序中可以除了使用ClassLoader.load方法外,还可以使用使用设置线程的上下文加载器或者系统加载器,然后再使用Class.forName.
注意:这里最好继承一个类,以便于获取其实例时,定义父类的引用,而不是它自己的引用。
编写自己的类加载器代码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);
}
//这时候不用关闭,谁创建资源,谁关闭资源。
}
}
调用自己写的类加载器
使用BeanInfo类和IntroSpector类查看把ReflectPoint当做一个JavaBean看时,显示的信息,并获取"x"属性的值(即用另一种方式,实现3中getProperty方法)
里边的BeanUtil和PropertyUtils类使用示例如下:
------- 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培训、期待与您交流!
----------
相关文章推荐
- 黑马程序员—SQL的学习
- 黑马程序员_内部类
- 黑马程序员--类加载器
- 【黑马程序员】C语言学习笔记之clang指令(二)
- 黑马程序员---异常处理总结
- 黑马程序员_java基础笔记(08)...GUI,网络编程,正则表达式
- 黑马程序员-----Java基础-----Java关键字、抽象类、方法重载、封装
- 黑马程序员—常见API+String类+Random类+Object类
- 黑马程序员_交通灯系统
- 黑马程序员-java反射基础
- 黑马程序员------面向对象(No.2)(封装、构造函数、构造代码块、this)
- 黑马程序员05_正则表达式
- 黑马程序员--反射机制和类加载器--java学习日记12(高新技术)
- 黑马程序员——基础加强——反射
- 黑马程序员——多线程
- 黑马程序员---继承
- 黑马程序员_java初级开发前奏
- 黑马程序员-包 jar包 javadoc
- 黑马程序员_Java高新技术_银行业务调度系统
- 黑马程序员—Java基础学习笔记之数据类型转换(自动转换和强制转换)