zoukankan      html  css  js  c++  java
  • 泛型&&枚举

    1.枚举类型

      JDk1.5中新增了枚举类型,可以使用该功能取代以往定义常量的方式,同时枚举类型还赋予程序在编译时进行检查的功能。

    1.1 使用枚举类型设置常量

      以往设置常量,通常将常量放在接口中(final static 数据类型  常量名  = 常量值;),这样在程序中就可以直接使用,并且该常量不能被修改,因为在接口中定义常量时,该常量的修饰符为final与static,常规定义如下:

    package enumeration.test;
    
    public interface RuleConstant {
        //接口中声明常量
        final static int Constants_A = 1;
        final static int Constants_B = 12;
    }

      在JDK1.5版本新增枚举类型后就逐渐取代了这种常量声明方式,使用枚举类型定义常量的语法如下:

    package enumeration.test;
    
    public enum Constants {
        Constants_A,
        Constants_B,
        Constants_C
    }

    下面我们通过一个例子来看一下常规类型和枚举类型的使用:

    package enumeration.test;
    
    public class EnumTest {
    
        //使用接口定义常量
        public static void doit(int c){
            switch (c) {
            case RuleConstant.Constants_A:
                System.out.println("接口常量Constants_A : doit()");
                break;
            case RuleConstant.Constants_B:
                System.out.println("接口常量Constants_B : doit()");
                break;
            default:
                System.out.println("default!");
                break;
            }
        }
        
        //使用枚举类型定义常量--枚举类型参数约束了只能传入枚举类中的常量
        public static void doit2(Constants c){
            switch (c) {
            case Constants_A:
                System.out.println("枚举类型_Constants_A");
                break;
            case Constants_B:
                System.out.println("枚举类型_Constants_B");
                break;
            case Constants_C:
                System.out.println("枚举类型_Constants_C");
                break;
            default:
                System.out.println("default!");
                break;
            }
        }
        
        public static void main(String[] args) {
            EnumTest.doit(RuleConstant.Constants_A);//接口常量
            EnumTest.doit2(Constants.Constants_B);//枚举类型
            EnumTest.doit(3);//参数类型不是枚举类型,那么传入参数就没有严格限制,不可以是枚举,可以是接口常量,也可以是变量
    //        EnumTest.doit(Constants.Constants_C);如果一个函数参数类型没有定义为枚举,那么传入枚举,编译不容过
        }
    
    }

    上面代码doit()函数,即便编译器不接受在接口中定义的常量参数,也不会报错,仍然正常运行;但调用doit2()方法,任意传递参数,编译器就会报错,这个函数定义了只接受枚举常量作为参数;

       枚举类型除了可以在类的外部单独进行定义,还可以在类中进行定义,如同内部类一样:

    package enumeration.test;
    
    public class EnumDemo{
        enum Constants{
            Constants_A,
            Constants_B,
            Constatns_C
        }
    }

    1.2 深入理解枚举类型

    1.2.1 操作枚举类型成员的方法

    package enumeration.test;
    
    import org.junit.Test;
    
    public class EnumMethodsTest {
    
        //values()该方法可以将枚举类型成员实例以数组方式返回;
        public static void valuesMethod(){
            for (int i = 0; i < Constants.values().length; i++) {
                System.out.println("Constants枚举成员:"+Constants.values()[i]);
            }
        }
        
        @Test
        public void testValuesMethod(){
            valuesMethod();
        }
        
        //valueOf()将普通字符串转换为枚举实例
        public static void valueOfMethod(String str){
            //将字符串转换为枚举实例,不代表可以把一个字符串变成枚举类型,只是意味着,参数被设置成了枚举类型,等同于与ccalueOfMethod(Constants c)
            Constants constants = Constants.valueOf(str);
            switch (constants) {
            case Constants_A:
                System.out.println("Constants.Constants_A");
                break;
            case Constants_B:
                System.out.println("Constants.Constants_B");
                break;
            case Constants_C:
                System.out.println("Constants.Constants_C");
                break;
            default:
                System.out.println("default");
                break;
            }
        }
        
        @Test
        public void testValueOfMethod(){
            valueOfMethod("Constants_B");
        }
        
        //campareTo(),正数代表之前,负数代表后,0代表位置相同
        public static void compareToMethod(){
            System.out.println("Constants_A与Constants_B相比较:"+Constants.Constants_A.compareTo(Constants.Constants_B));
            System.out.println("Constants_B与Constants_A相比较:"+Constants.Constants_B.compareTo(Constants.Constants_A));
            System.out.println("Constants_A与Constants_A相比较:"+Constants.Constants_A.compareTo(Constants.Constants_A));
        }
        
        @Test
        public void tesCompareToMethod(){
            compareToMethod();
        }
        
        //ordinal()用于获取某个枚举对象的索引位置
        public void ordinalMethod(){
            System.out.println("Constants_A的索引位置:"+Constants.Constants_A.ordinal());
            System.out.println("Constants_B的索引位置:"+Constants.Constants_B.ordinal());
        }
        
        @Test
        public void testordinalMethod(){
            ordinalMethod();
        }
    }

    1.2.2 枚举类型中的构造函数

      在枚举类型中,可以添加构造方法,但是规定构造函数必须为private修饰符所修饰,枚举类型的构造函数的定义如下:

    package enumeration.constructor;
    
    import org.junit.Test;
    
    public class EnumConstructor {
        enum Constants{
            Constants_A("我是枚举类型A"),
            Constants_B("我是枚举类型B"),
            Constants_C("我是枚举类型C"),
            Constants_D(3);
            private String description;
            private int i = 4;
            //无参构造函数
            private Constants(){
                
            }
            //有参构造
            private Constants(String description){
                this.description = description;
            }
            //有参构造
            private Constants(int i){
                this.i = this.i+i;
            }
            //get(),set()
            public String getDescription() {
                return description;
            }
            public void setDescription(String description) {
                this.description = description;
            }
            public int getI() {
                return i;
            }
            public void setI(int i) {
                this.i = i;
            }
            
        }
        //构造函数方法
        public void constructorMethod(){
            for (int i = 0; i < Constants.values().length; i++) {
                System.out.println(Constants.values()[i]+"调用getDescription()"+Constants.values()[i].getDescription());
            }
            System.out.println(Constants.valueOf("Constants_D")+"调用getI()"+Constants.valueOf("Constants_D").getI());
        }
        
        @Test
        public void testConstructorMethod(){
            constructorMethod();
        }
            
    }    

    package enumeration.constructor;
    
    public interface Test {
        public String getDescription();
        public int getI();
    }
    package enumeration.constructor;
    
    public enum AnyEnum implements Test{
        Constants_A{
            public String getDescription() {
                return ("我是枚举类型A");
            }
    
            public int getI() {
                return i;
            }
        },
        Constants_B{
            public String getDescription() {
                return ("我是枚举类型B");
            }
    
            public int getI() {
                return i;
            }
        },
        Constants_C{
            public String getDescription() {
                return ("我是枚举类型C");
            }
    
            public int getI() {
                return i;
            }
        },
        Constants_D{
            public String getDescription() {
                return ("我是枚举类型D");
            }
    
            public int getI() {
                return i;
            }
        };
        private static int i = 5;
        //测试
        public static void constructorMethod(){
            for (int i = 0; i < AnyEnum.values().length; i++) {
                System.out.println(AnyEnum.values()[i]+"调用getDescription()"+AnyEnum.values()[i].getDescription());
                System.out.println(AnyEnum.values()[i]+"调用getI()"+AnyEnum.values()[i].getI());
            }
        }
        public static void main(String[] args) {
            constructorMethod();
        }
    }

    1.3 使用枚举类型的优势

    泛型

    使用泛型避免了ClassCastException异常;

    2.1 回顾"向上转型"和"向下转型"

    例如:我们在数组中只能存储同一类型元素,如果存储了其他类型元素,那么编译器会报错,而集合中则可以存储多种类型元素,我们遍历集合时,会把集合中的元素进行转型(众所周知迭代器遍历集合元素返回Object),此时可能会出现ClassCastException异常,此时是运行时报错,那么我们可不可以让集合中也只存储一种类型元素,当存储其他类型元素时编译器报错,将运行时异常转变为编译时异常呢?此时就引出来了泛型,泛型是JDK1.5版本中出现的, 在类或者接口的后面有一对<> , 用来约束元素的数据类型的泛型的表现形式:

    * <E>
    * <T>
    * <QQ>

    2.2 定义泛型类

    其中T代表一个数据类型的名称;

    利用泛型类将上面的例17.9改写:

    package genericity.test;
    
    import org.junit.Test;
    
    //改写例17.9
    public class OverClass<T> {
    
        private T over;
    
        public T getOver() {
            return over;
        }
    
        public void setOver(T over) {
            this.over = over;
        }
        public static void main(String[] args) {
            //实例一个Boolean型的对象
            OverClass<Boolean> overClass1 = new OverClass<Boolean>();
            //实例化一个Float型的对象
            OverClass<Float> overClass2 = new OverClass<Float>();
            overClass1.setOver(true);//无需进行类型转换
            //泛型会自动检验传入的参数是否符合规矩
            overClass2.setOver(12.3f);
            System.out.println(overClass1.getOver());
            System.out.println(overClass2.getOver());
        }
        
    }

    泛型类中可以设置非泛型的成员变量;

    泛型将运行时的异常转换为了编译时的异常;

     

    2.3 泛型的常规用法

    2.3.1 定义泛型类时声明多个类型

    2.3.2 定义泛型类时声明数组类性

     定义泛型类时也可以声明数组类型:

    package genericity.test;
    
    public class ArrayClass<T> {
        private T[] array;
        
        public T[] getArray() {
            return array;
        }
    
        public void setArray(T[] array) {
            this.array = array;
        }
    
        public static void main(String[] args) {
            ArrayClass<String> a = new ArrayClass<String>();
            String[] array = {"1","2","3","4","5"};
            a.setArray(array);
            for (int i = 0; i < array.length; i++) {
                System.out.println(a.getArray()[i]);
            }
    
        }
    
    }

    1
    2
    3
    4
    5

    2.3.3 集合类声明容器的元素

     

    2.4 泛型的高级用法

     泛型的高级用法包括限制泛型可用类型、使用类型通配符等。

    2.4.1 限制泛型可用的类型

     

    2.4.2 使用类型通配符

     

    2.4.3 继承泛型类和实现泛型接口

     

    2.5 泛型总结

     

    * 泛型的好处:
    * a: 避免 操作隐患ClassCastException 
    * b: 把运行时异常 转换为 编译时异常
    * c: 避免了 强制转换的操作

     2.6 泛型的练习

    package collection.List.genericity;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.ListIterator;
    
    /*
     * 用ArrayList 存储 3个字符串,并遍历
     * 
     * 发现当集合中存储多种数据类型的元素的时候, 可能会有操作隐患ClassCastException(转换异常)
     * 怎么解决该问题呢?
     * 回想以前学习的数组, 数组中存储的都是同一种数据类型的元素,如果存储了 其他类型的数据,会编译错误
     *  String[] arr = new String[4];
     *  arr[0] = "JavaSE";
     *  arr[1] = "JavaEE";
     *  arr[2] = "Android";
     *  arr[3] = 20;
     *  
     *  我们也希望,我们可以将集合也只存储同一种数据类型的数据,如果存储了其他类型的数据,给出编译错误,
     *  这种技术如何来实现呢?  java提供了一个技术, 泛型。
     *  
     *  泛型: 在类或者接口的后面有一对<> , 用来约束元素的数据类型的
     * 
     *  泛型的表现形式:
     *      <E>
     *      <T>
     *      <QQ>
     *  
     *  泛型怎么使用呢?
     *      查看API,发现类或者接口有<>, 如果有泛型,那么必须要使用,可以避免 操作隐患ClassCastException 
     *  
     *      <>里面 用来指定元素的数据类型
     *  
     *  泛型的好处:
     *      a: 避免 操作隐患ClassCastException 
     *       b: 把运行时异常 转换为 编译时异常
     *       c: 避免了 强制转换的操作
     */
    public class ArrayListDemo {
    
        public static void main(String[] args) {
            // 创建ArrayList集合,使用泛型约束集合元素类型为String
            ArrayList<String> arr = new ArrayList<>();
            arr.add("成不成1!");
            arr.add("成不成2!");
            arr.add("成不成3!");
            //arr.add(20);当我们使用泛型后,集合中就只能出现允许的元素,其他类型元素编译时会报错
            //通过所以直接获取指定索引元素
            /*ListIterator<String> liter = arr.listIterator(0);
            Object object = liter.next();
            System.out.println(object.toString());*/
            //遍历
            ListIterator<String> liter = arr.listIterator();
            while (liter.hasNext()) {
                String string = liter.next();
                System.out.println(string);
            }
            //遍历
    //        Iterator<String> litera = arr.iterator();
    //        while (litera.hasNext()) {
    //            //类型转换
    //            String str =  (String) litera.next();
    //            System.out.println(str);
    //        }
        }
    
    }

    package collection.List.genericity;
    
    import java.util.Enumeration;
    import java.util.Vector;
    
    /*
     * 使用Vector集合 存储字符串对象,并遍历 (使用泛型)
     */
    public class VectorDemo {
    
        public static void main(String[] args) {
            // 创建Vector集合并遍历集合
            Vector<String> vec = new Vector<>();
            vec.add("伤不起,");
            vec.add("啊");
            vec.add("真的真的伤不起");
            //将元素添加到指定位置
            vec.add(2, "伤不起");
            Enumeration<String> enu = vec.elements();
            while (enu.hasMoreElements()) {
                String string = (String) enu.nextElement();
                System.out.println(string);
            }
        }
    
    }

    2.7 泛型类与泛型方法

    在上面我们看到了jdk提供的一些泛型,那么在现实开发中,我们可不可以进一步对泛型加以利用呢?答案是肯定的

    package collection.List.genericity;
    /*
     * 泛型类: 类上有泛型修饰, 就是泛型类
     */
    public class Tool<QQ> {
    
        public void show1(){
            System.out.println("haha");
        }
        
        public void show2(String str){
            System.out.println(str);
        }
        
        public void show3(Integer i){
            System.out.println(i);
        }
        
        public void show4(QQ qq){
            System.out.println(qq);
        }
    }
    package collection.List.genericity;
    /*
     * 泛型方法:  把泛型定义在方法上,在Tool类上,我们发现可以把类定义成泛型类,那么可不可以定义泛型方法呢
     */
    //public class Tool2<QQ> {
    //    public void show (QQ qq) {
    //        System.out.println(qq);
    //    }
    //    
    //    //不想是QQ类型
    //    public void method(TT tt){
    //        
    //    }
    //}
    public class ToolMethod {
        //TT类型
        public<TT> void Method(TT tt){
            System.out.println(tt.toString());
        }
    }
    package collection.List.genericity;
    
    public interface ITool<QQ> {
        //接口的方法都是抽象方法,抽象方法没有实现体
        public abstract void method(QQ qq);
    }
    package collection.List.genericity;
    //实现 implements
    /*
    * 泛型接口
    * 
    *  创建实现类的时候,明确泛型的数据类型
    *  创建实现类的时候,没有明确泛型的数据类型的时候,需要在类上也给出泛型
    */
    //public class Tool3Imlp implements Tool3<String>{
    //
    //    @Override
    //    public void show(String qq) {
    //        System.out.println(qq);
    //    }
    //}
    public class ToolImple<QQ> implements ITool<QQ>{
    
        @Override
        public void method(QQ qq) {
            System.out.println(qq.toString());
            
        }
    
    }
    package collection.List.genericity;
    
    public class ToolTest {
    
        public static void main(String[] args) {
            //泛型类
            Tool<String> tool = new Tool<>();
            String str = "左宗棠";
            tool.show1();
            tool.show2(str);
            tool.show3(7);
            tool.show4(str);
            //tool.show4(7);泛型类,约束了参数类型只能是String类型
            //tool.show4(tool);
            //泛型方法
            ToolMethod tm = new ToolMethod();
            tm.<String>Method(str);
            //tm.<String>Method(7);泛型方法决定了实参类型
            //泛型接口
            ITool<String> it = new ToolImple<>();
            it.method(str);
            //it.method(7);泛型决定了传入参数类型
        }
    
    }

    package cn.itcast.demo1;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.junit.Test;
    
    public class Demo1 {
        /*
         * 泛型方法有自己的类型变量
         * 泛型方法中的类型变量声明,必须在返回值之前!
         *   * 通常泛型方法的返回值和参数中都会使用类型变量
         *   * 泛型方法中声明的类型变量只能在当前方法内使用,其他方法不能使用!
         *   * 通过调用泛型方法时,不用显式的传递类型变量,而是通过参数类型隐式传递
         */
        public static <T> T get(T[] array) {
            return array[array.length / 2];
        }
        
        @Test
        public void fun3() {
            String[] strs = {"hello", "world", "java", "zhangSan", "liSi"};
            // 显式为泛型方法的类型变量赋值
            String s1 = Demo1.<String>get(strs);
            System.out.println(s1);
            // 隐式为泛型方法的类型变量赋值
            String s = get(strs);//等同与给T赋值了,赋的是String
            System.out.println(s);
        }
        
        @Test
        public void fun1() {
            List<String> arr = new ArrayList<String>();
            arr.add("hello");
            String s = arr.get(0);
            System.out.println(s);
        }
        
        @Test
        public void fun2() {
            A<String> a = new A<String>();
            A<Integer> a2 = new A<Integer>();
        }
    }
    
    /*
     * 泛型类,又叫参数化类型(A<T>)
     */
    class A<T> {
        private T t;
    
        /*
         * 它是泛型类的方法,不是泛型方法
         */
        public T getT() {
            return t;
        }
    
        public void setT(T t) {
            T bean = t;
            this.t = t;
        }
        
        // 泛型类中,类型变量只有static方法中不能使用
    //    public static void fun() {
    //        T bean1;
    //    }
    }
    package cn.itcast.demo2;
    
    import java.util.Comparator;
    
    /*
     * 泛型的继承
     */
    public class Demo1 {
        public void fun1() {
            AA1 aa1 = new AA1();
            AA2<String> aa2 = new AA2<String>();
            AA3<Long> aa3 = new AA3<Long>();
        }
    }
    
    class A<T> {
        private T bean;
    
        public T getBean() {
            return bean;
        }
    
        public void setBean(T bean) {
            this.bean = bean;
        }
    }
    
    /*
     * 如果父类是泛型类,那么子类需要在继承时给父类传递变量类型!
     */
    class AA1 extends A<String> {
        
    }
    
    class AA2<T> extends A<Integer> {
        
    }
    
    class AA3<T> extends A<T> {
        
    }
    
    class MyComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            // TODO Auto-generated method stub
            return 0;
        }
    }
  • 相关阅读:
    jQuery——能够编辑的表格
    最简单的Windows程序
    数据库分页查询
    Srvctl命令具体解释(10g)
    AT3912 Antennas on Tree
    使用GenericServlet实例
    Servlet接口、GenericServlet类、HttpServlet类
    Servlet简介
    MVC
    为JSP写的一套核心标签
  • 原文地址:https://www.cnblogs.com/lin-jing/p/6926953.html
Copyright © 2011-2022 走看看