黑马程序员—JAVA高新技术视频笔记


枚举

1) 为什么要有枚举
   -- 枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则编译器就会报错。枚举可以在编译器编译时就可以控制原程序中填写的非法制,普通变量的方式在开发这一阶段无法实现这一目标。
2) 用普通类如何实现枚举功能,定义一个weekday的类来模拟枚举功能。
  -- (1)私有构造方法
     (2)每个元素分别用一个共有的静态成员变量表示。
     (3)可以有若干共有方法或抽象方法,例如要提供nextDay方法必须是抽象的。
3) 枚举的基本应用
   举例:定义一个Weekay的枚举
   扩展:枚举类的values,valueOf,name,toString,ordinal等发方法。

总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,例如可以调用WeekDay.SUN.getClas().getName和WeekDay.class.getName().

先学习一下Enum的简单应用,以下简洁的代码已经包括Enum所提供的绝大部分功能。

1.Enum的应用,包括定义,遍历,switch,Enumset,Enummap等

import java.util.EnumMap;
import java.util.EnumSet;

/**

 * Java枚举类型Enum使用详解 

 * MyEnum可以存放多个枚举类型

 * 枚举类型也可以直接以类的形式声明,可以跟类、接口同级别

 * public enum State{ON,OFF } 单独可以作为一个java文件

 * @author heqingfei

 *
 */

public class MyEnum {

//定义一个enum枚举类型,包括实例ON,OFF

public enum State{

ON,OFF

}

public enum country{

China,Japan
}

//测试方法

public static void main(String[] args) {

//直接变量enum

for(State s:State.values()){

System.out.println(s.name());

}

//switch与enum的结合使用

State switchState=State.OFF;

switch(switchState){

case OFF:

  System.out.println("OFF");
  break;

case ON:

  System.out.println("ON");

  break;

}

//EnumSet的使用 

EnumSet stateSet = EnumSet.allOf(State.class); 

for (State s : stateSet) { 

System.out.println(s); 


//EnumMap的使用 

EnumMap stateMap = new EnumMap( 

State.class); 

stateMap.put(State.ON, "is On"); 

stateMap.put(State.OFF, "is off"); 

for (State s : State.values()) { 

System.out.println(s.name() + ":" + stateMap.get(s)); 

System.out.println("===================");
//枚举可以这样被调用

State state1=MyEnum.State.OFF;

System.out.println(state1.name());
System.out.println("===================");
State[] state2=MyEnum.State.values();
for(State state:state2){
System.out.println(state.name());
}

}

}

重点
1.可以创建一个enum类,把它看做一个普通的类。除了它不能继承其他类了。(java是单继承,它已经继承了Enum),
可以添加其他方法,覆盖它本身的方法
2.switch()参数可以使用enum
3.values()方法是编译器插入到enum定义中的static方法,所以,当你将enum实例向上转型为父类Enum是,values()就不可访问了。解决办法:在Class中有一个getEnumConstants()方法,所以即便Enum接口中没有values()方法,我们仍然可以通过Class对象取得所有的enum实例
4.无法从enum继承子类,如果需要扩展enum中的元素,在一个接口的内部,创建实现该接口的枚举,以此将元素进行分组。达到将枚举元素进行分组。
5.使用EnumSet代替标志。enum要求其成员都是唯一的,但是enum中不能删除添加元素。
6.EnumMap的key是enum,value是任何其他Object对象。
7.enum允许程序员为eunm实例编写方法。所以可以为每个enum实例赋予各自不同的行为。
8.使用enum的职责链(Chain of Responsibility) .这个关系到设计模式的职责链模式。以多种不同的方法来解决一个问题。然后将他们链接在一起。当一个请求到来时,遍历这个链,直到链中的某个解决方案能够处理该请求。
9.使用enum的状态机
10.使用enum多路分发
总结
枚举就相当于一个类,其中也可以定义构造方法,成员变量,普通方法和抽象方法。枚举元素必须位于枚举体中最开始部分,枚举元素列表的后面要有分号与其他元素分割。把枚举中的成员方法或变量放在枚举元素的前面,编译器报告错误。
    带构造方法的的枚举
构造方法必须定义成私有的,如果有多个构造方法,该如何选择哪个构造方法?枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
   带方法的枚举
定义枚举TrafficLamp,实现普通的next方法,实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式定义。增加上表示时间的构造方法。
    枚举只有一个成员时,就可以作为一种单立的实现方式
反射
 反射概念:就是把java类中的各种成分映射成相应的java类,一个类中的组成部分:方法,成员变量,构造方法包等等信息也是用一个java类来表示。
 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些这些实例对象后那么得到这些实例对象后有什么用呢?怎么用,就是学习反射内容中讲到的。
1. 构造方法的反射
  通过class对象的getConstructors()方法可获取该class对象对应的实体的所有public构造方法。如果要获取所有的构造方法,可以使用getDeclaredConstructors()方法。该方法返回的是java.lang.reflect.Constructors类的对象数组。Constructors类用来代表类的构造方法的相关信息。通过调用Constructors类提供的相应方法也可以获取该构造方法的修饰符,构造方法名,参数列表等信息。
2 .用反射方式来执行某个类中的main方法
    使用反射可以获得指定类的制定方法的对象代表,方法的对象代表是java.lang.reflect.Method类的实例,通过Method类的invoke方法可以动态调用这个方法。
注意:若要通过反射调用某个类的私有方法,可以在这个私有方法对应的Method对象上,先调用setAccessible(true)来消除java语言对本方法的访问检查,然后再调用invoke方法来真正执行这个私有方法。
反射的作用:-》实现框架功能
javaBean

  javaBean是一种特殊的java类主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。一个类被当做javaBean使用时,javaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

java的注解
  注解被用来为程序元素设置元数据,它并不影响程序代码的执行,即无论增加什么注释,程序执行都不受影响,java的注解采用@标记形式,后跟上注解类型名称,在JDK中java.lang包中预定义了三种注解,分别是:Override,Deprecated和SuppressWarnings.
重写Override
  Override是一个限定重写方法的注解类型,用来指明被注解的方法必须是重写超类方法的方法,这个注解只能用于方法上,编译器在编译源代码时会检查用@Override标注的方法是否有重写父类的方法
警告Deprecated
  Deprecated是用来标记已过时成员的注解类型,用来指明被注解的方法是一个过时的方法,不建议使用了,当编译调用到被标注为Deprecated的方法的类时,编译器就会产生警告。
抑制警告SuppressWarnings
  SuppressWarnings是抑制编译器警告的注解类型,用来指明被注解的方法,变量或类在编译时如果有警告信息,就阻止警告。
 泛型

  泛型是提供给JDBC编译器使用的,可以限定集合中的输入类型让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉"类型"信息,是程序运行效率不受影响,对于参数化的泛型类型 getClass()方法的返回值和原始类型完全一样由于编译生成的字节码会议去掉泛型的类型信息,只要能跳过编译器就可以往某个泛型集合中加入其它类型的数据。
  泛型的思想是消除取用集合元素时代码中的强制类型转换,比如事先规定好一个集合中允许加入的具体元素类型,然后在编译环节实现集合中添加元素的类型检查,以防止有人将非预期类型的元素保存到集合中。
优点是类型错误可以在编译时暴露出来,而不是在运行时才发作(抛ClassCastException),这有助于早期错误排查,并提高程序的可靠性。
注意
(1)JDK5.0后集合类定义像Vector一样都进行了泛型化改造,还有泛型类带有多个类型参数,如Map<K, V>就有两个类型参数,表示键-值映射。
(2)Java语言中的泛型是维护向后兼容的,即我们完全可以不采用泛型,而继续沿用过去的做法。
(3)在高版本开发环境中编译未启用泛型机制的集合类应用代码时,会输出编译提示信息。
AOP
AOP:aspect oriented program.不改变源代码,还给类增加新的功能.(代理)
Session s = SessionFactory.openSession();
Transaction tx = s.beginTransaction();
s.save(..);
tx.commit();
s.close();
切面:aspect,要实现的交叉功能.
通知:切面的实际实现,比较具体(细化).
连接点:可以将通知应用到目标程序中的地点.(方法调用,异常抛出,要修改的字段)
切入点:真正的将通知应用到目标程序中的地点.
引入:为类增加新的方法和属性.
目标对象:被通知的对象.
代理:把通知应用给目标对象以后,创建暂新的对象,该对象即为代理对象.
织入:把通知应用给目标对象以后,创建暂新的对象的过程即为织入.
1.编译期织入:当把java源代码编译成字节码class文件时,将通知织入.需要特殊的编译器.
2.类装载期织入:当把class文件载入到jvm时,将通知织入.
3.运行期(runtime)织入:
spring代理方式
1.接口代理(jdk的动态代理):
2.对类代理(cglib代理):
aop联盟:
使用spring开发aop:
1.引入aop联盟类库.(spring.jar已经内置了该包)
2.引入cglib类库实现对类代理.${spring解压目录}/lib/cglib/*.jar

PointCut{
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}

interface ClassFilter{
boolean isMatch(Class clazz);
}

interface Methodmatcher{
boolean matches(Method m,Class targetClass);1.
    boolean isRuntime();2.
    boolean matchers(Method m,Class target,Object[] args);3.
}

MethodBeforeAdvice|AfterReturningAdvice|MethodInterceptor
Advisor{

}
使用aspectj进行aop开发
1.引入aspectj类库
${spring解压目录}/lib/aspectj/*.jar
2.pojo:plain old java object.
使用pojo + xml
dao:data access object.(数据访问对象)

<!-- 创建目标对象bean -->
<bean id="welcomeServiceTarget" class="cn.csdn.spring.service.WelcomeServiceImpl">
  <property name="name" value="tom"/>
</bean>
<!-- 创建通知内容的bean -->
<bean id="myMethodBeforeAdvice" class="cn.csdn.spring.advice.MyMethodBeforeAdvice"/>
<!-- 创建代理bean
  注意创建代理Bean需要有三个Property要设置,代理的接口(proxyInterfaces)也可以不写
 -->
<bean id="welcomeService" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 接口 -->
<property name="proxyInterfaces">
 <list> 
    <value>cn.csdn.spring.service.WelcomeService</value>
 </list>
</property>

<!-- 要切入的通知内容 -->
<property name="interceptorNames">
  <list>
   <value>myMethodBeforeAdvice</value>
  </list>
</property>

<!-- 选择目标对象 -->
<property name="target" ref="welcomeServiceTarget"/>
</bean>
//
配置后置通知
1)定义通知  
public class MyMethodAfterAdvice implements AfterReturningAdvice {
}
2)
        <!-- 要切入的通知内容 -->
<property name="interceptorNames">
  <list>
   <value>myMethodBeforeAdvice</value>
   <value>myMethodAfterAdvice</value>
  </list>
</property>
/
基于CGLIB的类代理
以前我们都是基于接口代理的:
得到对象的方式是:
WelcomeService ww=(WelcomeService) ac.getBean("welcomeService");
而现在我们将基于类进行代理
方法如下:
1)获得类对象的方式
WelcomeServiceImpl ww=(WelcomeServiceImpl) ac.getBean("welcomeService");
2)修改配置文件
    <!-- 设置基于类的代理 -->
    <property name="proxyTargetClass" value="true"/>
///
环绕通知
  环绕通知使用
 1)定义自己的异常处理类 MyAroundMethodAdvice
 2)实现 ThrowsAdvice 接口 implements MethodInterceptor
 3)添加方法环绕通知方法:
    
    public Object invoke(MethodInvocation Invocation) throws Throwable {
// TODO Auto-generated method stub

System.out.println("Around Start!");
//调用目标方法
Invocation.proceed();

System.out.println("Around End!");
return Invocation;
}

 4)配置文件:
    添加bean
    <!-- 创建环绕通知 -->
<bean id="myAroundMethodAdvice" class="cn.csdn.spring.advice.MyAroundMethodAdvice"/>
    代理通知:
    <property name="interceptorNames">
  <list>  
   <value>myAroundMethodAdvice</value>
  </list>
</property>
异常通知使用
 1)定义自己的异常处理类 MyMethodException 
 2)实现 ThrowsAdvice 接口 implements ThrowsAdvice 
 3)添加方法异常通知方法:
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
System.out.println("当前方法:"+method+",参数个数:"+args.length+",目标对象:"+target.getClass().getName()+",异常类型:"+ex.getMessage());
}

 4)配置文件:
    添加bean
    <!-- 创建异常通知类型 -->
<bean id="myMethodException" class="cn.csdn.spring.advice.MyMethodException"/>
    代理通知:
    <property name="interceptorNames">
  <list>   
   <value>myMethodException</value>
  </list>
</property>
    代理通知:
    <property name="interceptorNames">
  <list>   
   <value>myMethodException</value>
  </list>
</property>
  5)在实际业务逻辑中产生一个异常
静态切入点:
切入点(advisor)包括:通知+要过滤的方法
1)配置步骤
  在打招呼的接口中(GreetingService)定义方法eat()
  并在实现类中,我们实现该方法,并且我们测试只给这个方法加上前置通知
2)修改配置文件
 <!-- 配置静态切入点 -->
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
  <!-- 配置通知  -->
   <property name="advice" ref="myMethodBeforeAdvice"/>
  <!-- 增加要过滤的方法 -->
   <property name="mappedNames">
     <list>
       <value>eat</value>
     </list>
   </property>
</bean>
3)修改代理的通知
<!-- 要切入的通知内容 -->
<property name="interceptorNames">
  <list>
   <!--
   <value>myMethodBeforeAdvice</value>
   -->
   <value>beforeAdvisor</value>   
   <value>myMethodAfterAdvice</value>
   <value>myAroundMethodAdvice</value>
   <value>myMethodException</value>
  </list>
</property>
引入:为已经存在的类增加属性和方法
目标:
   1)为目标对象添加属性
   2)为目标对象添加方法
添加步骤:
   1)定义ModifyDate接口(get、set方法)
   2)实现接口,定义变量 重写get、set方法,继承 DelegatingIntroductionInterceptor类
      public class ModifyDateImpl extends DelegatingIntroductionInterceptor implements ModifyDate {
private static final long serialVersionUID = 1L;
      .......
   3)修改配置文件
    1)增加引入通知(ModifyDateImpl)
         <!-- 定义一个引入bean -->
         <bean id="modifyDateImpl" class="cn.csdn.spring.service.ModifyDateImpl"/>
      2)添加针对引入通知的默认的切入点()
         <!-- 定义一个用于执行引入通知的默认切入点 -->
         <bean id="defaultIntroductionAdvisor"                    class="org.springframework.aop.support.DefaultIntroductionAdvisor">
             <constructor-arg ref="modifyDateImpl"/>
         </bean>
      3)在代理通知(通知拦截)中增加
         <value>defaultIntroductionAdvisor</value>  使之代理默认的切入点
      4)调试、测试 
             //获得修改类的对象
              ModifyDate md=(ModifyDate)ww;
               md.setModDate(Date.valueOf("2011-05-22"));    
                 System.out.println(md.getModDate());        

什么叫Aop?
  Aspect Oriented Programming  面向方面编程
特点:
OOP(面向对象编程)
基于面向对象,进行高度封装,但是重复代码太多
举例 我有 20 类,每个类 5个方法。
     需求:每个方法打印HelloWorld
     OOP思想
        1)每个方法都要 加System.out.println("HelloWorld");
        2)肯定得修改源代码
        3)代码重复量大
     AOP思想 (能够实现不改变源代码,增加类新的功能)
        1)能不能不改变 源代码 实现打印? 
        2)通过 切入点 完成 代理
        3)重复劳动少了
AOP 常见术语
切面:需要实现的交叉功能
连接点:应用程序执行的过程中插入切面的地点(可以是方法,异常,修改字段)
通知:交叉功能(切面)的具体实现,通知是在“连接点”插入系统
切入点:已经被通知切入的连接点
引入:允许为已经存在的类添加新的方法或者属性
目标对象:被通知的类,它既可以是自己编写的类,也可以是添加定制的第三方的类。
代理:将通知应用到目标对象后产生的新的对象(代理对象)
织入:将切面应用到目标对象后产生的新的对象的“过程”,切面是在指定的连接点被织入到目标对象中
      织入可以发生在对象生命周期的多个点(方法、异常)上
     织入发生的时期:
     编译期:切面在目标对象编译的时候织入
     装载期:切面在目标对象被转载进JVM 的时候织入
     运行期:切面在应用系统运行时织入(AOP将在织入切面时动态的产生委托代理对象)
AOP 的具体实现
1)Java编写Spring的通知
2)Spring运行的时候通知对象
3)Spring实现了AOP联盟的接口
4)只支持方法连接点
AOP 创建代理的方式
1)通过接口创建代理
2)通过类(cglib)创建代理 
   使用接口方式创建代理优于使用类创建代理
   使用final的方法不能被通知

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值