1、Java基础 J2SE(3),新一站开发部 孟凡军,目录,Java语言,Java语法,Java进阶,2,内容大纲,程序员应知破窗与童子军军规 代码规范 设计模式 中文编码 泛型、反射 线程池 正则表达式 加解密,程序员应知破窗与童子军军规,程序员应知破窗与童子军军规,代码规范,Java 编码规范: 是常用代码习惯 不是语法要求但是需要严格遵守,代码规范,写干净整洁的代码删除没有使用的类引用(Ctrl+Shilft+O)格式化代码(Ctrl+Shilft+F)删除废弃的老代码(Ctrl+D)请不要在两个地方出现完全相同的代码(重用)命名类,方法,变量慎用简写拆分大的类,大的方法(500, 50)
2、2、注释使用注释来解释代码的意图,它们不应作为代码的翻译,编写高质量的代码从命名入手,编写高质量的代码从命名入手,设计模式,设计模式(Design pattern):是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式和框架,设计模式-要素,模式是一条由三个部分组成的通用规则: 它表示了一个特定环境、一类问题和一个解决方案之间的关系。设计模式要素 名称:助记、交流 问题:先决条件 解决方案:了解设计的组成成分 效果:应用的效果、权衡、影响,为什么要提倡“Design Pattern“呢?,根本原因是为
3、了代码复用,增加可维护性。那么怎么才能实现代码复用呢?OO界有前辈的几个原则:“开闭“原则(Open Closed Principal)、里氏代换原则、合成复用原则。设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。,设计模式-原则,1、“开闭“原则 2、里氏代换原则 3、合成复用原则 4、依赖倒转原则 5、接口隔离原则 6、抽象类 7、迪米特法则,常用的设计模式,单例模式 简单工厂模式 代理模式 策略模式 观察者模式 模板方法模式 职责链模式 装饰模式 工厂方法模式,设计模式-书,中文编码,为什么要编码? 常见的有 ASCII、ISO-8859-1、GB2312、GBK、U
4、TF-8、UTF-16几种编码格式的比较 GB2312 与 GBK UTF-16 与 UTF-8,编码转换,I/O 操作中存在的编码 InputStreamReader 、OutputStreamWriter内存中操作中的编码:字符到字节的数据类型的转换,常见问题分析,中文变成了看不懂的字符 字符串在解码与编码字符集不一致导致汉字变成了看不懂的乱码,而且是一个汉字字符变成两个乱码字符。一个汉字变成一个问号 将中文和中文符号经过不支持中文的ISO-8859-1编码后,所有字符变成了“?”,这是因为用 ISO-8859-1 进行编解码时遇到不在码值范围内的字符时统一用 3f 表示,这也就是通常所说
5、的“黑洞”,所有 ISO-8859-1 不认识的字符都变成了“?”。一个汉字变成两个问号 中文经过多次编码,但是其中有一次编码或者解码不对仍然会出现中文字符变成“?”现象。,内容回顾,程序员应知破窗与童子军军规 代码规范 设计模式 中文编码,泛型、反射,Java泛型 理解Java泛型 应用Java泛型编程Java反射机制 理解Java反射机制 理解Java的动态代理,自学内容,熟悉设计模式应用场景 编码规范 中文编码转换,Java泛型,在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”;泛型是Java SE 1.5的新特性,泛型的本质是参数化类
6、型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。,Java泛型:规则和限制,Java泛型:泛型类语法,泛型类的语法说明: 使用来声明一个类型持有者名称,就可以把T当作一个类型代表来声明成员、参数和返回值类型。T仅仅是个名字,这个名字可以自定义。 声明class GenericsFoo 声明了一个泛型类,这个T没有任何限制,实际上相当于Object类型,实际上相当于 class GenericsFoo。 使用与Object泛型类相比,使用泛型所定义的类在声明和构造实例的时候,可以使用“”来一并指定泛型类型持有者的真实类
7、型。比如 GenericsFoo douFoo=new GenericsFoo(new Double(“33“); 当然,也可以在构造对象的时候不使用尖括号指定泛型类型的真实类型,但是你在使用该对象的时候,就需要强制转换了。比如:GenericsFoo douFoo=new GenericsFoo(new Double(“33“); 实际上,当构造对象时不指定类型信息的时候,默认会使用Object类型,这也是要强制转换的原因。,Java泛型应用示例,/* * DAO操作基类 : 本DAO层实现了通用的数据操作 * param POJO实体对象 * param ID*/ public class
8、 BaseHibernateDAOImpl extends HibernateDaoSupport implements BaseHibernateDao private Class entityClass;public void setEntityClass(Class entityClass) this.entityClass = entityClass; ,Java语言的反射机制,在 Java 运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态调用对象的方法的功能来自于Java 语言的反射
9、(Reflection)机制。 Java 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法; 生成动态代理。,Java Reflection API,在 JDK 中,主要由以下类来实现Java 反射机制,这些类都位于java.lang.reflect包中: Java.lang.Class类:代表一个类。 Field类:代表类的成员变量(成员变量也称为类的属性)。 Method类:代表类的方法。 Constructor 类:代表类的构造方法。 Array类:提供了动态创
10、建数组,以及访问数组元素的静态方法。,Java Reflection API,Java Reflection API,Method类的invoke(Object obj, Object args)方法用于动态执行一个对象的特定方法。第一个obj 参数指定具有该方法的对象; 第二个args 参数指定向该方法传递的参数,该参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象;invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。,代理模式,代理模式是常用的Java 设计模式,它的特
11、征是代理类与委托类有同样的接口。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。按照代理类的创建时期,代理类可分为两种。 静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 动态代理类:在程序运行时,运用反射机制动态创建而成。图: 代理模式,静态代理类,如图a所示,HelloServiceProxy 类是代理类,HelloServ
12、iceImpl类是委托类,这两个类都实现了HelloService接口。其中HelloServiceImpl类是HelloService接口的真正实现者,而HelloServiceProxy类是通过调用HelloServiceImpl 类的相关方法来提供特定服务的。HelloServiceProxy类的echo()方法和getTime()方法会分别调用被代理的HelloServiceImpl 对象的echo()方法和getTime()方法,并且在方法调用前后都会执行一些简单的打印操作。由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。图a:HelloServicePr
13、oxy是HelloService的代理类 图b:调用时序图,动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。Proxy类提供了创建动态代理类及其实例的静态方法: public static Class getProxyClass(ClassLoader loader, Class interfaces) thr
14、ows IllegalArgumentException 该静态方法负责创建动态代理类。参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口。public static Object newProxyInstance(ClassLoader loader, Class interfaces,InvocationHandler handler) throws IllegalArgumentException 该静态方法负责创建动态代理类的实例。参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口,
15、参数handler 指定与动态代理类关联的InvocationHandler 对象。,动态代理类,以下两种方式都创建了实现Foo接口的动态代理类的实例: /* 方式一*/ /创建InvocationHandler对象 InvocationHandler handler = new MyInvocationHandler(.); /创建动态代理类 Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class Foo.class ); /创建动态代理类的实例 Foo foo = (Foo) proxyCla
16、ss.getConstructor(new Class InvocationHandler.class ).newInstance(new Object handler );/* 方式二*/ /创建InvocationHandler对象 InvocationHandler handler = new MyInvocationHandler(.); /直接创建动态代理类的实例 Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class Foo.class ,handler);,动态代理类,由Proxy类的
17、静态方法创建的动态代理类具有以下特点: 动态代理类是public、final和非抽象类型的; 动态代理类继承了java.lang.reflect.Proxy类; 动态代理类的名字以“$Proxy”开头; 动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口; Proxy 类的isProxyClass(Class cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类; 动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数
18、。InvocationHandler 接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法: Object invoke(Object proxy,Method method,Object args) throws Throwable 参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args 指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。,动态代理类,图1: HelloServiceProxyFactory创建动态代理类实例 图2: 动态类实例调用时序图,内置的高效的线程池,JDK1.5已经内置了高效的通用的线程池。一
19、段示范代码: ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 1000, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(3), new ThreadPoolExecutor.DiscardOldestPolicy(); while(接收请求) threadPool.execute(new WorkerThread(XXX); 上面这段代码首先生成一个初始化为10个,最大为1000个线程的线程池,每次接收请求的时候,都从线程程中抽出一个线程来运行,内置的高效的线程池,对于一个并发程序
20、来说,线程池可说是其中一个比较重要的部分。尤其是对各种Socket Server来讲,其流程一般都是:接收客户端请求处理逻辑将结果返回给客户端。处理逻辑那段,经常要用到多线程(或多进程)。一般有以下两种实现: 1、每次请求都生成一个新的线程(或进程)去处理。 2、每次请求到来,从线程池(进程池)中取出一个,然后让其处理。在以前,线程池只能是自己重新发明车轮去写,或者从网上找第三方的线程池(质量很难得到保证),内置的高效的线程池,Runnable,Callable和FutureRunnable这个接口我们已经非常熟悉,它代表线程的执行,里面有一个run方法。但是它是没办法返回线程的执行结果的(当
21、然,通过间接的方法可以)。JDK1.5新增了一个Callable接口,和Runnable类似,只是里面的call方法是可以返回线程的执行结果的。Future这个接口则是描述异步运算的结果,里面的方法: cancel(boolean mayInterruptIfRunning): 取消该次执行 get():等待并获取运算结果 get(long timeout, TimeUnit unit):等待一定时间获取运算结果 isCancelled():判断任务是否已经取消 isDone():判断任务是否已经完成这三个接口构成了线程池的基础。,内置的高效的线程池,一个具体的例子: class MatchC
22、ounter implements Callable public MatchCounter(File directory, String keyword) . . . public Integer call() . . . / returns the number of matching files FutureTask task = new FutureTask(counter); Thread t = new Thread(task); t.start();System.out.println(task.get() + “ matching files.“);,内置的高效的线程池,线程池
23、的一个实现:ThreadPoolExecutor,它实现了线程池的各方面的功能,如: 执行某个任务(返回或不返回结果)。 初始化一定数量的线程,随着负荷的增大而新建线程,并控制线程池的最大容量。 在线程执行之前和之后执行一段代码。 删除某个任务。 关闭整个线程池。 获取线程池运行的各个运行期参数 ,非常齐备,从此不再需要每次都重新发明车轮。,内置的高效的线程池,ThreadPoolExecutor的一些常用方法: ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit
24、, BlockingQueue workQueue, RejectedExecutionHandler handler) 这是其中一个构造函数,第一个参数是常驻的线程数,第二个参数为线程池的最大容量,第三个为清除空闲线程的最长时间,第四个为时间的单位。第五个为线程池内部队列,第六个为清除空闲线程的策略,内置的高效的线程池,ThreadPoolExecutor的一些常用方法: void execute(Runnable command)运行某个任务(不返回结果) Future submit(Callable task)将某个任务放进线程池,并获取其运行结果 int getActiveCount(
25、)获取线程池中活跃线程的数量 long getCompletedTaskCount() 获取已执行完的任务的数量 shutdown和shutdownNow()关闭线程池。类似于kill和kill 9。_,正则表达式,是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。自学: http:/ 非对称,推荐的JAVA常用参考资料,1、最重要的,JDK的manual。 2、Core JAVA和Thinking in JAVA两本书。 3、IBM的developerWorks网站: http:/ 4、Apache开源社区http:/www.apache.org/ BeanUtils、Codec、DBCP、IO、Lang、Logging、Net Apache HttpComponents,习题,1、对象属性值拷贝的实现void copy (Object dest, Object orig) ,谢谢!,