Java 常用类库

常用类库

0 泛型

1 Objects

2 Math

3 Arrays

4 BigDecimal

5 Date

6 DateFormat

7 Calendar

8 System

9 String

0 泛型

在说类库之前,首先需要了解一个前置知识,那就是 Java 中的泛型机制。因为很多 Java 的很多类库中都使用了泛型。

”泛型“的含义就像它的字面意思一样,就是”泛化的类型“,或者反过来说更清楚,泛型不代表某个特定的数据类型或者类的类型,而是可以适用于各种不同的类型。比较正式的说法叫做参数化类型

泛型的作用在 Java 的常用类库中可以得到很多的体现。提供常用类库的目的就是为了让其可以在各种不同的环境中使用,具体来说就是可以对不同的类型对象使用同一套工具进行操作。因此,常用类库的工具定义中就不能指定某个特定的类型,不然它就没法通用了。这个时候就需要泛型登场了。

泛型可以使用在类、接口或者方法之上,它使用尖括号并在其中指定一个类型的占位符,表示不确定的“某种”类型,所以它被叫做参数化类型。下面是几个栗子:

  1. 泛型类

    public class GenericClassName<T> {
        private T a;
        public GenericClassName() {}
        public void setA(T a) {
            this.a = a;
        }
        public T getA() {
            return a;
        }
    
        public static void main(String[] args) {
            GenericClassName<Integer> c = new GenericClassName<>();
            c.setA(3);
            System.out.println(c.getA());
            // c.setA(3.14); // 报错: 不兼容的类型
        }
    }
    

    上面的GenericClassName是一个简单的泛型类,在使用时我们再通过尖括号指定具体的类型,比如上面main()方法中的Integer类型,当然也可以指定其它在环境中存在类型。c对象的定义处,等号右边的尖括号可以是空的,它被默认设定为与c前前括号中同样的Integer类型,这是从 Java 7 开始的一个新特性(称为“钻石语法”)。当给定了类型后,它就被确定下来了,我们只能进行满足指定类型的操作,否则就会报错,就像上面一样 ,setA()不能输入非整型的数据 。

  2. 泛型接口

     public interface GenericInterfaceName<T> {
         T get();
     }
    

    泛型接口的使用时,可以根据需要选择要不要指定泛型类型,就是说我们可以在其实现类中直接指定具体类型,也可以保留泛型类型。就像下面这样:

     // 指定泛型类型的实现
        public class GenericInterfaceImplOne<String> {
      @Override
      String get() {
             return "hello";
         }
        }
        // 保留泛型类型的实现
     public class GenericInterfaceImplOne<T> {
      private T a;
      @Override
         T get() {
             return a;
         }
        }
    
  3. 泛型方法

    泛型方法的定义中,将泛型的参数列表放在返回值类型前面。

    public staic <T> T methodName(T a) {}
    

    我们也可以在尖括号中使用多个泛型参数,它们之间使用逗号隔开,如<A, B, C>。这对泛型类/接口/方法都适用。

  4. 泛型限制类型

    当我们使用泛型时,可以对泛型可以限定代表的类型范围。就像下面这样:

    interface Fruit{}
     class Apple implements Fruit{}
     class Pear implements Fruit{}
     class Basket<T extends Fruit> {
         T something;
     }
     public class Test {
         public static void main(String[] args) {
             Basket<Apple> b1 = new Basket<>();
             Basket<Pear> b2 = new Basket<>();
             // 错误:类型参数java.lang.String不在类型变量T的范围内
             // Basket<String> b1 = new Basket<>();
         }
     }
    

    在定义Basket类时我们使用extends限定了泛型T只能是Fruit的实现类型,因此,在使用Basket创建对象时,必须在尖括号中传入Fruit的实现类型(Apple/Pear),如果传入不在这个范围内的类型(String)就无法通过编译。注意:无论是限定某个接口的实现还是某个类的子类型,都是使用extends连接。并且可以限定泛型继承(实现)多个类型(接口),类型(接口)之间使用&隔开,如<T extends class1 & class2 & interface1>

  5. 泛型中的通配符?

    当我们在使用含有泛型类/接口/方法时,可以通过传入通配符(而不是具体的某个类型)的方式,指定可传入类型的范围。请看栗子🌰:

    interface Fruit{}
    class Apple implements Fruit{}
    class Pear implements Fruit{}
    class Basket<T> {
        T something;
    }
    public class Test {
        public static void main(String[] args) {
            // Basket<Fruit> b1 = new Basket<Apple>(); // 错误:非法的类型
            Basket<? extends Fruit> b2 = new Basket<Apple>();
        }
    }
    

    可以看到,main()中第一行语句是不合法的定义方式,从代码的意思上看就是说“不能将一个装有苹果的篮子堪称装有水果的篮子”,这好像是不合常理的。但是这告诉我们泛型是不支持直接向上转型的。想要实现这样的需求,就需要用到通配符?,就像main()中第二行那样 。通过<? extends Fruit>我们限定了输入类型的上界为Fruit。我们还可以通过? super 子类来限定输入类型的下界,当然还可以直接使用<?>表示没有任何限制的输入类型。

泛型可以使得代码的复用率进一步地提高,特别是对于像是 Java 的常用类库这种基础性的代码库来说。而且,我们是在使用泛型类/接口/方法的时候,才将泛型参数指定为我们想要的特定类型的,这样也就不需要强制类型转换。注意:Java 中的泛型只在编译阶段有效,编译过程就是去泛型化的过程。具体来说就是,在编译过程中,在正确检验反省结果后,泛型的相关信息会被擦除掉,并在对象进入和离开方法的边界处添加类型检查和类型转换的方法。所以,泛型信息是不会进入到运行阶段的,运行阶段使用的是传入的特定类型。

1 Objects

请看 Java 常用类库之 Objects

2 Math

请看 Java 常用类库之 Math

3 Arrays

请看 Java 常用类库之 Arrays

4 BigDecimal

请看 Java 常用类库之 BigDecimal

5 Date、DateFormat和Calendar

三者都是用在时间处理上的,具体请看 Java 常用类库之 Date、DateFormat和Calendar

6 System

整理中...

7 String

整理中...

posted @ 2021-08-23 16:34  alterwl  阅读(335)  评论(0)    收藏  举报