java基础(四)

JAVA内部类

  Java类中不仅可以定义变量和方法,还可以定义类,这样定义在类内部的类就被称为内部类。根据定义的方式不同,内部类分为静态内部类,成员内部类,局部内部类,匿名内部类四种。

静态内部类

  定义在类内部的静态类,就是静态内部类。

  1. 静态内部类可以访问外部类所有的静态变量和方法,即使是private的也一样。
  2. 静态内部类和一般类一致,可以定义静态变量、方法,构造方法等。
  3. 其它类使用静态内部类需要使用”外部类.静态内部类”方式,如下所示:Out.Inner inner =new Out.Inner();inner.print();
  4. Java集合类HashMap内部就有一个静态内部类Entry。Entry是HashMap存放元素的抽象,HashMap内部维护Entry数组用了存放元素,但是Entry对使用者是透明的。像这种和外部类关系密切的,且不依赖外部类实例的,都可以使用静态内部类。

成员内部类

  定义在类内部的非静态类,就是成员内部类。成员内部类不能定义静态方法和变量(final修饰的除外)。这是因为成员内部类是非静态的,类初始化的时候先初始化静态成员,如果允许成员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的。

局部内部类(定义在方法中的类)

  定义在方法中的类,就是局部类。如果一个类只在某个方法中使用,则可以考虑使用局部类。

匿名内部类(要继承一个父类或者实现一个接口,直接使用new来生成一个对象的引用)

  匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。


JAVA泛型

  泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
  泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
  比如我们要写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,我们就可以使用Java泛型。

泛型方法(

  可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

1
2
1. <? extends T>表示该通配符所代表的类型是T类型的子类。
2. <? super T>表示该通配符所代表的类型是T类型的父类。

泛型类

  泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
  出于规范的目的,Java还是建议用单个大写字母来代表类型参数。常见的如:
T 代表一般的任何类。
E 代表Element的意思,或者Exception异常的意思。
K 代表Key的意思。
V 代表Value的意思,通常与K一起配合使用。
S 代表Subtype的意思。

类型通配符?

  通配符的出现是为了指定泛型中的类型范围。
  通配符有3种形式:
<?>被称作无限定的通配符。
<? extends T>被称作有上限的通配符。
<? super T>被称作有下限的通配符。

无限定的通配符

  无限定通配符经常与容器类配合使用,它其中的 ? 其实代表的是未知类型,所以涉及到 ? 时的操作,一定与具体类型无关。
  例如 List<?> 在逻辑上是List,List 等所有 List<具体类型实参>的父类。

类型擦除

  Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的List和 List等类型,在编译之后都会变成 List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般是Object。如果指定了类型参数的上界的话,则使用这个上界。把代码中的类型参数都替换成具体的类。

类型擦除带来的局限性

  类型擦除,是泛型能够与之前的java版本代码兼容共存的原因。但也因为类型擦除,它会抹掉很多继承相关的特性,这是它带来的局限性。
  泛型类或者泛型方法中,不接受8种基本数据类型。
  Java不能创建具体类型的泛型数组。
  但是利用类型擦除的原理,用反射的手段就绕过了正常开发中编译器不允许的操作限制。

泛型好处

  泛型抽离了数据类型与代码逻辑,本意是提高程序代码的简洁性和可读性,并提供可能的编译时类型转换安全检测功能。
  而类型擦除,使泛型能够与之前的java版本代码兼容共存。