泛型&&枚举

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;
    }
}
原文地址:https://www.cnblogs.com/lin-jing/p/6926953.html