张老师高新技术技术学习日志---Part2

来源:互联网 发布:linux 文件管理系统 编辑:程序博客网 时间:2024/04/29 10:34


------- android培训java培训、期待与您交流! ----------

关键字JDK1.5新特性

——————————————————————————————————————————————

二、JDK1.5的新特性

|-------之[枚举](Enum)

 1.为什么要有枚举

     问题:要定义星期几或者性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday=0。

     枚举就是要让某个类型的变量的值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制程序中填写的非法值,普通变量的方式无法在开发阶段实现这一目标。它跟泛型一样,都是把运行期的错误,提前到编译期来控制,提高了安全性。

   注意:可以创建一个enum类,把它看做一个普通的类。除了它不能继承其他类了。(java是单继承,它已经继承了Enum),

2.用普通类 如何实现枚举功能?定义一个WeekDay的类来模拟枚举功能。步骤如下:

      a.私有构造方法。

      b.每个元素分别用一个公有的静态成员变量来表示。

      c.可以有若干公有方法或抽象方法。例如,要提供nextDay()方法必须是抽象的。

    代码如下:

 

public abstract class WeekDay1{private WeekDay1(){}public final static WeekDay1 SUN = new WeekDay1(){//采用抽象方法就是将if else语句转移一个个独立的类public  WeekDay1 nextDay(){return MON;}};public final static WeekDay1 MON = new WeekDay1(){public  WeekDay1 nextDay(){return TUES;}};public final static WeekDay1 TUES = new WeekDay1(){public  WeekDay1 nextDay(){return WES;}};public final static WeekDay1 WES = new WeekDay1(){public  WeekDay1 nextDay(){return THUR;}};public final static WeekDay1 THUR = new WeekDay1(){public  WeekDay1 nextDay(){return FRI;}};public final static WeekDay1 FRI = new WeekDay1(){public  WeekDay1 nextDay(){return SAT;}};public final static WeekDay1 SAT = new WeekDay1(){public  WeekDay1 nextDay(){return SUN;}};public abstract WeekDay1 nextDay();public String toString(){if(this == MON){return "MON";}else if(this == TUES){return "TUES";}else if(this == WES){return "WES";}else if(this == THUR){return "THUR";}else if(this == FRI){return "FRI";}else if(this == SAT){return "SAT";}else{return "SUN";}}}


3.枚举的基本应用

   a.定义一个Weekday的枚举

   b.枚举类的values,valueOf,name,toString,ordinal等方法

   c.枚举是一种特殊的类,其中的每一个元素都是该类的一个实例对象,

      可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()方法。

 

public enum WeekDay{//枚举创建时,调用构造方法SUN(4),MON(),TUES,WES,THUR,FRI,SAT;private WeekDay(){System.out.println("first");}private WeekDay(int x){System.out.println("second");}}

4.带有构造方法和方法的枚举举例

public enum TrafficLamp{//下边的一个代码,可以看出TrafficLamp子类   的一个对象,对象名是RED,子类名未知。RED(30){public  TrafficLamp nextLamp(){return GREEN;}},GREEN(45){public  TrafficLamp nextLamp(){return YELLOW;}},YELLOW(15){public  TrafficLamp nextLamp(){return RED;}};public abstract TrafficLamp nextLamp();@SuppressWarnings("unused")private int time;private TrafficLamp(int time){this.time =time;}}

5.小结

         枚举,预先给对象定义好一些值,在给对象赋值时,如果不是指定的值,就报错,
  不能通过编译。  
         枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法
  枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后边要有分号与其他成员分隔。
         把枚举中的成员方法或变量等放在枚举元素的前边,编译器会报错。
   
    a.带构造方法的枚举的特点:
       构造方法必须定义成私有的;
       枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
    b.带方法的枚举
     
    c.当枚举只有一个成员时,就可以作为一个单例的实现方式。


 

public static void main(String[] args) {WeekDay1 weekDay = WeekDay1.MON;System.out.println(weekDay.nextDay());WeekDay weekDay1 = WeekDay.MON;//枚举的方法System.out.println(weekDay1);System.out.println(weekDay1.name());System.out.println(weekDay1.ordinal());//枚举的静态方法System.out.println(WeekDay.valueOf("SUN"));System.out.println(WeekDay.values().length);}

|-------之[注解](Annotation)

 
 一、 注解基本应用:演示java.lang包中的三个注释类型。 
       |--Deprecated:用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的 代   码中执行重写时,编译器会发出警告。 
       |--SuppressWarnings:指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的 编译器警告
       |--Override:表示一个方法声明打算重写超类中的另一个方法声明。

          注解相当于一种标记,在程序中加了注解就等于给程序打上了某种标记。以后,javac编译器开发工具盒其他程序可以通过反射来了解你的类及各种元素上有无标记,看你有什么样的标记就去做相应的事。
          注解可以加在:类、字段、方法和方法的参数及局部变量上。

import cn.itcast.day1.EnumTest;@ItcastAnnotation(lamp=EnumTest.TrafficLamp.GREEN,color = "GREEN",value="123",arrayAttri={1,5,8},annoAttr=@MetaAnnotation("flx"))public class AnnotationTest {@SuppressWarnings("deprecation")//提示过时了@ItcastAnnotation("123")public static void main(String[] args) {// TODO Auto-generated method stubSystem.runFinalizersOnExit(true);//方法过时了,在dos命令窗口中,如果没有加@SuppressWarnings("deprecation")会提示方法过时,如果有则不提示。if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){ItcastAnnotation annotation = AnnotationTest.class.getAnnotation(ItcastAnnotation.class);System.out.println(annotation);System.out.println(annotation.color());System.out.println(annotation.value());System.out.println(annotation.arrayAttri().length);System.out.println(annotation.lamp().nextLamp());System.out.println(annotation.annoAttr().value());}}@Deprecated//过时了public static void sayHello(){System.out.println("hi,java!");}}

 二、 注解的应用结构:
      1.注解类型。
      2.应用了注解类型的类。
      3.对“应用了注解类型的类”进行反射操作的类
  
 三、元注解:对注解类型进行注解的注解类型。(如元信息,描述信息的信息)
  java的元注解都在java.lang.annotation包中,层次如下:
  Annotation
     |--Documented 指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。
     |--Inherited 指示注释类型被自动继承。
     |--Retention 指示注释类型的注释要保留多久。 (描述注释存在的周期)
     |--Target 指示注释类型所适用的程序元素的种类 (描述注释存在的位置)
 
 四、为注解增加基本属性。 
增加属性的格式: 
 类型  变量名() default 变量实例 ; * 
 1.添加基本属性:类型为8个基本数据类型,String类,Class类,
 2.添加高级属性:枚举,注解类型(注解类型也可以作为基本属性加个注解),
 3.以上类型的数组。
       注意:如果属性中只有一个value属性,或有多个属性,这些属性都用默认值,那么可以简写为:             @Annotation(arg)(arg为value的值)


import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import cn.itcast.day1.EnumTest;/* * .class文件不是字节码文件,class文件通过类加载器,进入内存后,内存中存在的才是字节码文件。 */@Retention(RetentionPolicy.RUNTIME)//Retention是元注解:对注解的注解@Target({ElementType.METHOD,ElementType.TYPE})public @interface ItcastAnnotation {String color() default "red";String value();int[] arrayAttri() default {1,2,3};EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;MetaAnnotation annoAttr()  default @MetaAnnotation("yxf");}

public @interface MetaAnnotation {String value() ;}


 

 

 

|-------之[泛型](Generic)

一.问题的引入:为什么要用泛型?

     引入泛型的原因之一:在使用集合时,可以向定义好的某一集合中存入任意类型的数据,而我们希望整个集合中的 类型都是一样的,当加入的不期望的类型后,只有到运行期才能发现。  而且取出的类型需要强制转换。

请看如下代码(没有使用泛型):

ArrayList collection = new ArrayList();collection.add(1);collection.add(1L);collection.add("abc");//int i = (Integer)collection.get(1);//这句会报错

使用泛型的代码:

//在集合中的应用ArrayList<String> collection1 = new ArrayList<String>();//collection1.add(1);//collection1.add(1L);collection1.add("String");String i = collection1.get(0);//在反射中的应用//用反射实现操作:String str = new String(new StringBuffer("abc"));Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);String str1 = constructor1.newInstance(new StringBuffer("abc"));System.out.println(str1.charAt(2));

    从上面两段代码的对比中,很容易看出使用泛型的好处:1.限定了集合元素的类型;2.省去了强制转换的过程。    

    JDK升级一般可分为三个大的方面:1.简化书写;2.提高效率;3.提高安全性。而泛型就属于其中的第三方面安全,它是一种安全机制。

 

二、    利用反射穿透泛型限制    

泛型能绝对保证集合中存入数据都是它限定的类型吗?先看下边的代码 

ArrayList<Integer> collection2 = new ArrayList<Integer>();System.out.println(collection1.getClass()==collection2.getClass());collection2.add(“123”);//这句会报错collection2.getClass().getMethod("add", Object.class).invoke(collection2, "hello");System.out.println(collection2.get(0)); //结果却为hello

      这段代码让你惊讶吧?已经限制集合中元素的类型为Integer,可用反射却能将String存入,为什么? 这是因为泛型是给编译器用的,运行时就没有这些泛型信息了,这叫做“去泛型化”,所以可以通过反射,获取集合字节码加入非指定的类型。

 

 三、ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:
     1.ArrayList<E>:这个整体称为“泛型类型”,其中的“E”称为 类型变量 或 类型参数 。
     2.ArrayList<Integer>:整体称为“参数化的类型”,“Integer”称为“类型参数的实例”或“实际类型参数”,"<>"读为typeof,ArrayList称为“原始类型”。
    3.参数化类型与原始类型的兼容性:可以互相引用,但编译器会报告警告。 
    4.参数化类型不考虑类型参数的继承关系 
    5.编译器不允许创建类型变量的数组。在创建数组实例时,数组的元素不能使用参数化的类型。

Collection<String> c = new Vector();Collection c1 =  new Vector<String>();//见第4条//错误语句Vector<String> v=new Vector<Object>();//错误语句Vector<Object> v1=new Vector<String>();Vector  v2=new Vector<String>();Vector<Object> v3 = v2;//错误语句Vector <Integer>  [] vectorList = new Vector <Integer>[10];//见第5条。Vector <Integer[]>   vectorList = new Vector <Integer[]>();


四、扩展应用:泛型中的通配符“?”

      1.限定通配符的上边界
         Vector<? extends Number>  x = new Vector<Integer>();正确的
         Vector<? extends Number>  x = new Vector<String>():错误的。
      2.限定通配符的下边界
         Vector<? super Integer>  x = new Vector<Number>();正确的。
         Vector<? super Integer>  x = new Vector<Byte>();错误的。    
    注意:限定通配符总是包括它自己。

printCollection_2(collection2);//Class<Number> x = String.class.asSubclass(Number.class);//错误。//Class x1 = String.class.asSubclass(Number.class);//Class<String> y = Class.forName("java.lang.String");//错误Class y = Class.forName("java.lang.String");//要抛出异常。Class<?> y1;Class<String> y2 = null;y1=y2;//y2=y1;


 五、泛型集合类的综合应用案例

HashMap<String,Integer> hm = new HashMap<String,Integer>();hm.put("zyq", 18);hm.put("zsy", 49);hm.put("zyx", 25);Set<Map.Entry<String,Integer>> entrySet = hm.entrySet();for(Map.Entry<String, Integer> entry:entrySet){System.out.println(entry.getKey() + ":" + entry.getValue());}

六、定义泛型方法

     1.泛型类似C++中的模板,但没有C++中的功能强大。
     2.泛型的实际类型参数只能是引用数据类型,例如:对于HashMap<K,V>,K和V不能是八种基本数据类型。
     3.异常也可以用泛型
     4.类型参数的类型推断

    例子一:模拟C++中的模板实现求和功能(但没有C++中好用)

add(1,2);Number x1 = add(1,1.4);//int 和float的最大公共集是NumberObject x2 = add(1,"abc");//String 和int的最大公共集是Object
private static<T> T add(T x,T y){//取得的T是 x 和  y的最大公共集,其实也是java中多态的体现。return null;}

例子二:实现数组中的元素位置交换


 

swap(new String[]{"abc","123","hello"},0,1);//swap(int[]{1,2,3,4},2,3);//int是基本数据类型,所以不能实现。
private static<T> void swap(T[] t ,int x,int y){T temp = t[x];t[x] = t[y];t[y] = temp;}

例子三:

ArrayList<Integer> al = new ArrayList<Integer>();al.add((Integer)autoConvert(345));System.out.println(al.get(0));String s = autoConvert("123");System.out.println(s);fillArray(new Integer[]{1,3,4},1);copy1(new Vector<String>(), new String[]{"123","5674"});copy2(new Date[20], new String[10]);//这个是两个取交集。//copy1(new Vector<Date>(), new String[]{"123","5674"});//类型推断的传播性,Vector中T已经指定为Date,后边的T也应该是Date,否则报错。
public static<T> void fillArray(T[] t,T obj){for(int x= 0;x<t.length;x++){t[x]= obj;}}public static <T> T autoConvert(Object obj){return (T)obj;}
public static <T>void copy1(Collection<T> des ,T[] src){   } public static <T>void copy2(T[] des ,T[] src){    }

 

七、自定义泛型类

import java.util.Set;//dao data access object:CRUDpublic class GenericDao<E> {//增public void add(E x){}//删public void delete(int id){ }public void delete(E obj){ }//查public E findByID(int id){return null;}public E findByName(String name){return null;}public Set<E> findByConditions(String where){return null;}//改public void update(E obj){}public static<E> void update1(E obj){//静态方法不能用类上定义的泛型参数,但可以自己定义泛型,这里的E和类上的E是两码事。}}
GenericDao<ReflectPoint> dao = new GenericDao<ReflectPoint>();dao.add(new ReflectPoint(5, 7));//String s = dao.findByID(1);//返回的也必须是ReflectPoint


八、通过反射获得泛型的参数化类型

       没办法通过泛型的引用,用反射 获取参数化类型的类型参数。 但可以通过反射获得方法的参数列表,从参数列表中获取参数化类型(ParameterizedType)的原始类型(RawType)和实际类型参数(ActualTypeArguments)

import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.Date;import java.util.Vector; class GenericTest {public static void main(String[] args) throws Exception{Method applyMethod =  GenericTest.class.getMethod("applyVector", Vector.class);Type[] types =applyMethod.getGenericParameterTypes();ParameterizedType pType =(ParameterizedType) types[0];System.out.println(pType.getClass());System.out.println(pType.getOwnerType());System.out.println(pType.getRawType());System.out.println(pType.getActualTypeArguments()[0]);}public static void applyVector(Vector<Date> v){}/*public static void applyVector(Vector<Integer> v){ //这个方法和上边的方法是同一个方法。}*/}


------- android培训、java培训、期待与您交流! ----------    

原创粉丝点击