黑马程序员——Java基础知识——泛型、枚举

来源:互联网 发布:下拉通刷词软件 编辑:程序博客网 时间:2024/05/23 13:27

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!

一、泛型

       泛型(Generic):JDK1.5以后出现的新特性,用于解决安全问题,是一个类型安全机制。泛型的出现将运行时期出现的问题如ClassCastException转移到了编译时期,方便于程序员解决问题,让运行时问题减少、安全;还避免了强制转换的麻烦。

       泛型格式:通过<>来定义要操作的引用数据类型。如:ArrayList<String> al=new ArrayList<String>();该集合只能加入String类型的元素。泛型的应用在集合框架中很常见,见到<>就要定义泛型。当使用集合时,将集合中要存储的数据类型作为参数传递给<>中,<>就是用来接收数据类型的。如下:

public static void main(String[] args) {            //定义集合,并加入泛型,只能传入字符串ArrayList<String> al = new ArrayList<String>();            //添加元素al.add("xiaoming");al.add("haha");al.add("nihao");            //迭代器也加入泛型Iterator<String> it = al.iterator();while(it.hasNext()){String s = it.next();System.out.println(s);}}

 
从上面这个程序可以看出,集合加入了泛型之后,可以不用再对元素进行类型的强制转换。

        泛型类:当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在可以定义泛型来完成拓展。泛型类定义的泛型在整个类中有效,如果被方法使用,当泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。要注意这里的具体类型都是引用类型,不能是基本类型。通过一段小代码进行演示:

class Demo  {    public static void main(String[]args)    {         //创建对象,明确要操作的数据类型为String           User<String>user=new User<String>();         //方法操作的参数类型只能是String             user.setObject("你好");   }}//定义一个泛型类class User<AA>{private AA  a;public void setObject(AA a){this.a=a;}public AA getTool(){return a;}}

     如果一个泛型类中的方法,在创建了该类对象后,还想操作不同类型的参数,而且参数的类型还不确定,这时就可以把泛型定义在方法上。定义在方法上的泛型可以与类的泛型不同,可以调用类的泛型数据和其他泛型数据。泛型定义在方法上时,要放在返回值类型的前面,修饰符的后面。如下面这个程序:

class Demo  {    public static void main(String[]args)    {         //创建对象,明确要操作的数据类型为String           Tool<String> tool=new Tool<String>();         //get方法操作的参数类型只能是String             tool.get("你好");         //print方法在方法上定义了泛型,可以调用与类泛型不同的参数         tool.print("再见");         tool.print(12);//向上提升为Integer类型。   }}//定义一个泛型类class Tool<T>{public void get(T t){System.out.println(t);}public<S> void print(S s){System.out.println(s);}}
      当一个泛型类中有静态方法时,静态方法不可以访问类上定义的泛型,如果静态方法操作的数据类型不确定,可以将泛型定义在方法上。

     通配符:用?表示,又叫占位符,当传入的类型不确定时,使用通配符。使用通配符的好处是可以不用明确传入的类型,在使用泛型类或泛型方法时,提高了扩展性。定义的通配符主要做引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。即不能调用对象特有的方法。下面这个程序就应用了通配符,提高了扩展性。

public static void main(String[] args) {//定义一个字符串类型的ArrayList集合ArrayList<String> a1 = new ArrayList<String>();a1.add("abc1");a1.add("abc2");a1.add("abc3");                //定义一个I整数型的ArrayList集合ArrayList<Integer> a2 = new ArrayList<Integer>();a2.add(4);a2.add(7);a2.add(1);                //调用迭代方法print(a1);print(a2);//使用了通配符,可以传入任意参数类型的ArrayList集合public static void printColl(ArrayList<?> al){Iterator<?> it = al.iterator();while(it.hasNext()){System.out.println(it.next().toString());}}

     泛型的限定:对于一个范围内的一类事物,可以通过泛型限定的方式来定义。

      第一种设定上限:?extends E:可以接收E类型或者E的子类型。如:ArrayList<? extends Number> al=new ArrayList<Integer>();

     第二种设定下限:? super E: 可以接收E类型或者E的父类型。   如:ArrayList<? super Integer> al=new ArrayList<Number>(); 

     通过应用泛型限定,可以让具有继承关系或处在同一个继承体系中的对象,能够实现方法的共用,提高代码的复用性。如下面这个程序:

/** 定义学生类、工人类,他们都有年龄属性。 建立他们的具体对象,并放在TreeSet集合中。 按照姓名的自然顺序排序。*/class GenericDemo7 {public static void main(String[] args) {//建立存储学生对象的TreeSet集合,按照传入的比较器排序TreeSet<Student> ts = new TreeSet<Student>(new Comp());ts.add(new Student("孙明"));ts.add(new Student("小新"));ts.add(new Student("陈光"));ts.add(new Student("阿亮"));Iterator<Student> it = ts.iterator();                //获取每个学生while(it.hasNext()){System.out.println(it.next().getName());}                //建立存储工人对象的TreeSet集合,按照传入的比较器排序TreeSet<Worker> ts1 = new TreeSet<Worker>(new Comp());ts1.add(new Worker("王猛"));ts1.add(new Worker("李霞"));ts1.add(new Worker("孙一"));ts1.add(new Worker("霍东"));Iterator<Worker> it1 = ts1.iterator();while(it1.hasNext()){System.out.println(it1.next().getName());}}}//定义比较器,定义泛型为Personclass Comp implements Comparator<Person>{public int compare(Person p1,Person p2){return p2.getName().compareTo(p1.getName());}}//定义Person类class Person{private String name;Person(String name){this.name = name;}public String getName(){return name;}public String toString(){return "person :"+name;}}//定义学生类,继承Personclass Student extends Person{Student(String name){super(name);}}//定义工人类,继承Person类class Worker extends Person{Worker(String name){super(name);}}
      Comparator接口传入参数类型是<? super T>,当我们传入的是工人和学生共同的子类Person时,存储两者的集合都可以调用这个比较器,提高了代码的复用性,简化了代码。

   二、枚举

        就是让一个类对应的引用型变量的取值为若干个固定的值中的一个。例如星期对应的值只能是星期一到星期日。否则编译无法通过。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。下面就通过一个普通类来实现枚举的功能,如下:

<pre name="code" class="java">public abstract class WeekDay{//构造函数私有        private WeekDay(){}//定义变量,表示周日public final static WeekDay SUN = new WeekDay(){public WeekDay nextDay() {return MON;}};//定义变量。表示周一       public final static WeekDay MON = new WeekDay(){               public WeekDay nextDay() {return SUN;}};//定义抽象方法,表示下一天public abstract WeekDay nextDay();//返回字符串表现形式public String toString(){return this==SUN?"SUN":"MON";}}

该类的对象的值只能是固定的SUN、MON。  该类创建时,首先将构造函数私有,所以外部无法创建该类的对象。每一个同类型成员变量用公有静态修饰,其实就是该类的一个实例对象。类中可以定义共有方法或抽象方法,成员变量对象中要复写抽象方法。

      枚举类:通过enum关键字表示,枚举类中每个元素都是类静态常量,都是该类的一个实例对象。枚举类定义的值就是该类中定义的元素。若不是,编译失败。枚举类的构造函数称为构造器,必须私有,保证外部无法创建枚举类的实例。在构造枚举值时被调用。可以定义多个构造器,调用哪个即初始化对应的值。下面通过一段程序演示枚举类及其特有的方法。

public class Demo {public static void main(String[] args) {//获取表示周一的对象WeekDay weekDay = WeekDay.MON;//获取表示周五的对象WeekDay weekDay2 = WeekDay.FRI;//打印枚举常量名        System.out.println(weekDay2);//打印枚举常量名        System.out.println(weekDay2.name());//打印枚举常量的次序        System.out.println(weekDay2.ordinal());//将字符串转为枚举常量        System.out.println(WeekDay.valueOf("SUN"));//获取所有枚举常量        System.out.println(WeekDay.values());}   //定义一个内部枚举类public enum WeekDay{        //定义枚举常量SUN(1),MON(),TUE,WED,THI,FRI,SAT;private WeekDay(){}//定义有参数的构造方法private WeekDay(int day){}}}
         要注意的是枚举中元素必须位于枚举类的最上方,如果后面还有其他成员要用分号隔开。否则编译失败。枚举和普通的类一样,类中也可以有普通成员变量、成员方法等。当枚举类中多个构造方法时,元素需指定构造方法。若选择有参数的构造方法,需要传入参数,否则还是默认的构造方法。枚举也内部类的形式存在比较常见。枚举类中方法返回的类型一般都是本类类型。当枚举类中只有一个成员时,可以看成是一种单例设计模式的体现。下面再通过一个表示交通灯的枚举类,学习内容更丰富的枚举类。如下:

 //定义表示交通灯的枚举类public enum WeekDay{SUN(1),MON(),TUE,WED,THI,FRI,SAT;private WeekDay(){System.out.println("first");}private WeekDay(int day){System.out.println("second");}}public enum TrafficLamp{                //表示红灯,复写换灯方法                RED(30){public  TrafficLamp nextLamp(){return GREEN;}},               //表示绿灯,复写换灯方法               GREEN(45){public  TrafficLamp nextLamp(){return YELLOW;}},      //表示黄灯,复写换灯方法               YELLOW(5){public  TrafficLamp nextLamp(){return RED;}};//定义表示换灯的抽象方法                public abstract TrafficLamp nextLamp();//定义变量,表示亮灯时间                private int time;//定义构造函数,初始化产生亮灯时间                private TrafficLamp(int time){this.time = time;}}}




 -------------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

0 0