黑马程序员:Java高新技术2
来源:互联网 发布:新东方网络在线课堂 编辑:程序博客网 时间:2024/04/29 16:55
---------- android培训、java培训、期待与您交流! ----------
1.反射
反射就是将java中的各成分映射成相应的Java类
如何得到各个字节码对应的实例对象( Class类型)
类名.class,例如,System.class
对象.getClass(),例如,new Date().getClass()
Class.forName("类名"),例如,Class.forName("java.util.Date"); 反射中用的最多,因为可以根据字符串,直接返回该类的字节码。
九个预定义Class实例对象:
8个基本数据类型:即 boolean、byte、char、short、int、long、float 、double和void
参看Class.isPrimitive方法的帮助
Int.class == Integer.class 返回的false
Int.class == Integer.TYPE 返回是true èInteger.TYPE是返回该对应的基本数据类型的字节码
数组类型的Class实例对象
Class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
Constructor是操作类中构造函数的
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
例子: Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
//获得方法时要用到类型
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法:
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
Field是操作类中成员变量的
Field类代表某个类中的一个成员变量
演示用eclipse自动生成Java类的构造方法
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。
示例代码:
ReflectPoint point = new ReflectPoint(1,7);//x为私有的 Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y"); System.out.println(y.get(point)); //Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");//NoSuchFieldException Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");//IllegalAccessException x.setAccessible(true); System.out.println(x.get(point));
注意:
比较字节码是用 == 而不是equals
此时就会显得你很专业
要加上注释,不然人家就不会知道你很专业
//这里应该用 == ,这里是同一份字节码
作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
private static void changeStringValue(Object obj) throws Exception{Field[] fields = obj.getClass().getFields();for(Field field : fields){//这里应该用 == ,这里是同一份字节码if(field.getType() == String.class){String oldValue = (String)field.get(obj);String newValue = oldValue.replace('b', 'a');field.set(obj, newValue);}}}
Method 是操作类中成员方法的
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
jdk1.4和jdk1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
用反射方式执行某个类中的main方法
目标: 写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大家要明白为什么要用反射方式去调啊?
因为可以直接用forName通过一个字符串来调用该对应的类
问题:
启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
解决方法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"});,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
Int.class的getSuperclass的父类为nullInt[].class的getSuperclass的父类是Object
Arrays.asList()方法处理int[]和String[]时的差异。
Jdk 1.5:Arrays.asList(T… t)Jdl 1.4:Arrays.asList(Object[] obj)1.5为了兼容1.4,可以传递数据进去String[]传递进去可以当作Object[]去处理打印结果为:[a,b,c]Int[]传递进去的时候却不能转化为Object[]所以1.4处理不了,返回去给1.5进行处理打印结果为:[ [I (hashcode) ]
int[] a = new int[3];Object obj = a;//Object[] obj1 = a //有错!
Array工具类用于完成对数组的反射操作。
private static void printObject(Object obj) {if(obj.getClass().isArray()){int len = Array.getLength(obj);for(int i=0;i<len;i++) {System.out.println(Array.get(obj, i));}} else {System.out.println(obj);}}
思考题:怎么得到数组中的元素类型?
一些面试题
Class.forName(“java.lang.String”);
得到这个类的字节码
1.此类的字节码已经加载到内存中去,不需要去加载了,直接去内存中找到即可
2.虚拟机中还没此类的字节码,就用类加载器去加载,加载以后就把字节码缓存起来,返回此类的字节码
面试题:forName的作用
作用:返回字节码:返回的方式有两种:1.这份字节码曾经被加载过,直接返回;2.Java虚拟机中还没有这份字节码,就用类类加载器去加载,加载完成就缓存起来,以后再用就不需要去加载了。
hashCode的作用
hashCode的作用必须是在hash存储结构中才有用,hashCode可以提高在hash存储结构中的查找效率,比如有1W个对象存储在hash中,我们查找最坏的是要查找1W次,当有了hashCode的时候,我们就可以将这1W个对象根据hashCode分成若干个区域,当要查找某个对象时,先根据hashCode判断出该对象在哪个区域里,再在那个区域中去查找,这样子就可以提高查询效率!所以,为了让相等的对象放在同一个区域,如果两个对象equals相等,那么也必须要让他们的hashCode相等(要复写equals方法和hashCodefanfa),但是如果存储结构不是hash的时候,就没有必要去Override hashCode.
还有一个作用,那就是会引起内存泄漏
内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
2.JavaBean内省
内省对应的英文单词为IntroSpector,它主要用于对JavaBean进行操作,JavaBean是一种特殊的Java类,其中的某些方法符合某种命名规则,如果一个Java类中的一些方法符合某种命名规则,则可以把它当作JavaBean来使用
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
3.beanutils工具包
用struts的迭代标签不能迭代出枚举元素的属性,而用jstl的迭代标签则可以。采用BeanUtils去获取带有抽象方法的枚举类的成员对象的属性时,会出现错误,要自己用内省加暴力反射方式才可以获取。主要原因是枚举类的抽象子类不是public类型的。public static void main(String[] args) {// TODO Auto-generated method stub/*System.out.println(PropertyUtils.getProperty(Sex.NONE, "title"));*/Object bean = Sex.NONE;BeanInfo beanInfo = null;try {beanInfo = Introspector.getBeanInfo(bean.getClass());} catch (Exception e1) {// TODO Auto-generated catch blocke1.printStackTrace();}PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();for(PropertyDescriptor property:properties){if(property.getName().equals("title")){Method method = property.getReadMethod();method.setAccessible(true);Object retVal;try {retVal = method.invoke(bean, null); System.out.println(retVal);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
4.类加载器
类加载器就是把类加载到JVM中去
Java中可以安装多个类加载器,系统默认三个主要的类加载器,每个负责加载特定位置的类:
BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap(C++编写的一段二进制代码,镶嵌在JVM中)
类加载器的委托机制
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。
当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。
面试题:我们可不可以自己写一个类也叫java.lang.System?
答:一般是不可以的,Java中有委托加载机制,会通过BootStrap加载器加载rt.jar中的System,而不会找到你自己的写的System,但不是不可以的,你可以自己去写一个类加载器去加载自己写的System
自定义类加载器的原理
class MyClassLoader extends ClassLoader {//实现findClass方法即可 public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } }
package cn.itcast.day2;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.util.Properties;public class MyClassLoader extends ClassLoader {public static void main(String[] args) throws Exception{String srcPath = "D:\\Users\\pphdsny\\Workspaces\\MyEclipse 8.5\\javaenhance\\bin\\cn\\itcast\\day2\\ClassLoaderAttachment.class";String destDir = "itcastlib";System.out.println(srcPath);FileInputStream fis = new FileInputStream(new File(srcPath));String destFileName = srcPath.substring(srcPath.lastIndexOf("\\")+1);String destPath = destDir + System.getProperty("file.separator") + destFileName;FileOutputStream fos = new FileOutputStream(new File(destPath));cypher(fis, fos);}public static void cypher(InputStream ips,OutputStream ops) throws Exception{int b = -1; while((b = ips.read()) != -1){ops.write(b ^ 0xff);}}private String classDir;@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// TODO Auto-generated method stubString classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";System.out.println("aaa");try {FileInputStream fis = new FileInputStream(classFileName);ByteArrayOutputStream bos = new ByteArrayOutputStream();cypher(fis, bos);fis.close();byte[] bytes = bos.toByteArray();return defineClass(bytes, 0, bytes.length);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return super.findClass(name);}public MyClassLoader() {// TODO Auto-generated constructor stub}public MyClassLoader(String classDir){this.classDir = classDir;}}
ClassLoaderAttachment
package cn.itcast.day2;import java.util.Date;public class ClassLoaderAttachment extends Date {@Overridepublic String toString() {// TODO Auto-generated method stubreturn "hello u!";}}
用于测试
package cn.itcast.day2;import java.util.Date;public class ClassLoaderTest {/** * @param args * @throws ClassNotFoundException */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubSystem.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());System.out.println(System.class.getClassLoader());ClassLoader loader = AnnotationTest.class.getClassLoader();while(loader != null){System.out.println(loader.getClass().getName());loader = loader.getParent();}/*System.out.println(loader);System.out.println(new ClassLoaderAttachment().toString());*/Class clazz = new MyClassLoader("itcastlib").loadClass("cn.itcast.day2.ClassLoaderAttachment");Date d = (Date)clazz.newInstance();System.out.println(d);System.out.println(d.getClass().getClassLoader().getParent().getClass().getName());}}
5.代理
代理架构图
AOP
安全 事务 日志
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService ------|----------|------------|-------------
method1 method2 method3
{ { {
------------------------------------------------------切面
.... .... ......
------------------------------------------------------切面
} } }
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
动态代理技术
动态代理的工作原理图
实现AOP功能的封装与配置
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice
源代码
AopFrameworkTest主要用于测试
package cn.itcast.day3.aopframework;import java.io.InputStream;public class AopFrameworkTest {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubInputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");Object bean = new BeanFactory(ips).getBean("xxx");System.out.println(bean.getClass().getName());}}
BeanFactory
package cn.itcast.day3.aopframework;import java.io.InputStream;import java.util.Properties;import cn.itcast.day3.Advice;public class BeanFactory {Properties props = new Properties();public BeanFactory(InputStream ips) throws Exception{props.load(ips);}public Object getBean(String name){String clazzName = props.getProperty(name);Object bean = null;try {Class clazz = Class.forName(clazzName);bean = clazz.newInstance();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}if(bean instanceof ProxyFactoryBean){Object proxy = null;ProxyFactoryBean proxyBean = (ProxyFactoryBean)bean;try {Advice advice = (Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();Object target = Class.forName(props.getProperty(name + ".target")).newInstance();proxyBean.setAdvice(advice);proxyBean.setTarget(target);proxy = proxyBean.getProxy();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}return proxy;}return bean;}}
ProxyFactoryBean
package cn.itcast.day3.aopframework;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import cn.itcast.day3.Advice;public class ProxyFactoryBean {private Object target;private Advice advice;public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}public Advice getAdvice() {return advice;}public void setAdvice(Advice advice) {this.advice = advice;}public Object getProxy() {// TODO Auto-generated method stubObject proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), /*new Class[]{Object.class}, */target.getClass().getInterfaces(),new InvocationHandler(){public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stub//ArrayList target = new ArrayList();/*long beginTime = System.currentTimeMillis();Object retVal = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println(method.getName() + " run time is " + (endTime - beginTime));return retVal;*/advice.beforeMethod(method);Object retVal = method.invoke(target, args);advice.afterMethod(method);return retVal;}});return proxy;}}
config.properties配置文件
#xxx=java.util.ArrayListxxx=cn.itcast.day3.aopframework.ProxyFactoryBeanxxx.advice=cn.itcast.day3.MyAdvicexxx.target=java.util.ArrayList
---------- android培训、java培训、期待与您交流! ----------
详情请查看:http://edu.csdn.net/heima/
- 黑马程序员 - Java 高新技术2
- 黑马程序员----Java高新技术2
- 黑马程序员:Java高新技术2
- 黑马程序员 Java高新技术2
- 黑马程序员--java高新技术
- 黑马程序员-java高新技术
- 黑马程序员----Java高新技术
- 黑马程序员--Java高新技术
- 黑马程序员--java高新技术--
- 黑马程序员--JAVA高新技术
- 黑马程序员:Java高新技术
- 黑马程序员-----java高新技术
- 黑马程序员-Java高新技术
- 黑马程序员 (8)JAVA高新技术 2
- 黑马程序员—Java高新技术2
- 黑马程序员-Java高新技术笔记2
- 黑马程序员---Java高新技术学习笔记-2
- 黑马程序员—java高新技术(2)
- Java5泛型的用法,T.class的获取和为擦拭法站台
- SQL2005自动备份,定期删除的维护计划及自动定期清除日志
- 火狐
- StarUML使用说明-指导手册 .
- HDU 1009 FatMouse' Trade
- 黑马程序员:Java高新技术2
- Spring 2.5.6新特性之packagesToScan
- 用c.vim插件打造C/C++集成编辑器
- @Override 报错问题
- 从几个sample来学习Java堆,方法区,Java栈和本地方法栈
- Ubuntu 12.04 安装离线词典
- Jena使用教程—RDF数据的读取
- 一个javascript滑动标签的例子
- Linux shell第二讲