美文网首页
Java 内部类和泛型的理解

Java 内部类和泛型的理解

作者: wangdy12 | 来源:发表于2017-12-30 17:12 被阅读0次

Java 内部类

Java非静态内部类持有对外部类的引用,可以访问外部类的状态
使用方法 OuterClass.this.variable
编译结果 OuterClass$InnerClass

内部类访问修饰符可以为private,而普通类的修饰符不能是private,只可以具有包可见性或者公有可见性

实例化一个公有内部类:

Outer_Class outer = new Outer_Class();
Outer_Class.Inner_Class inner = outer.new Inner_Class();
  1. 内部静态类不需要有指向外部类的引用;但非静态内部类需要持有对外部类的引用
  2. 非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员,只能访问外部类的静态成员。
  3. 一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

注意

  1. 内部类的静态域必须是final
  2. 内部类不能有static方法

内部类似C++ 中的嵌套类,方便进行命名控制和访问控制

局部内部类

定义在方法内部,不能用private或public访问说明符修饰,作用域被限定到这个局部类的块中

局部类不仅可以访问外部类,还可以访问final局部变量

原理:
局部内部类有一个实例域(this$0),是外部类的引用
局部内部类对要访问的局部变量对应的备份
final表明初始化后不能再修改数据,保证了局部变量与局部类内部建立的拷贝是一致的

匿名内部类

如果只创建这个类的一个对象,可以不必命名,称为匿名内部类(anonymous inner class)
匿名内部类在声明的同时,进行实例化。用来重载类或者接口的方法

new AnonymousInner(){
      inner class methods and data
}

因为匿名类没有类名,所以也没有构造器,若有需要应该把参数传递给超类构造器
在构造参数的闭小括号后面跟一个开大括号,正在定义的就是匿名内部类

Handler handler = new Handler(Looper.getMainLooper()){
    @Override
    public void handleMessage(Message msg) {
       //处理对应的消息
    }
};

静态内部类

只是为了把一个类隐藏在另一个类的内部,不需要引用外围类的对象

静态内部类可以有静态域和方法
声明在接口中的内部类,自动成为public和static类


接口

接口中可以包含常量,不能包含实例域,
可以包含静态方法,可以包含默认方法(用default修饰符标记)


泛型

泛型编程(generic programming)可以方便代码被不同的类型重用
泛型的本质是参数化类型(Parametersized Type),操作的数据类型被指定为一个参数,这种类型参数可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法

泛型方法的定义:类型变量放在修饰符的后面,返回类型的前面public <T> T getMiddle(T...a)
调用时可以省略类型参数,编译器可以自行推断

Java泛型实现是通过类型擦除实现的,类型参数被替换为原生类型(Raw Type)(或者说是限定类型),代码相应地方被插入类型强制转换,这实际是一种伪泛型
C++的泛型是真实的,例如List<int>List<String>是两种不同的类型,编译生成不同的代码,成为这种泛型会导致类型膨胀

由于类型擦除,可能会影响多态性,引入桥方法(编译器实现的方法,实现对泛型擦除后的方法的覆盖)

注意:

  • 运行时进行泛型类型查询只产生原始类型 ,例如
ArrayList<int> a ;
ArrayList<String> b; 
a.getClass()==b.getClass()//类型都是ArrayList.class
  • 支持可变长度的泛型类型的参数,使用@SafeVarargs抑制警告
@SafeVarargs static <E> E[] array(E... array) {return array; }
  • 不能在静态字段或方法中引用类型变量
private static T field; //错误
  • 不能创建泛型数组,数组会记住元素的类型,如果存入类型不正确应该抛出ArrayStoreException异常,然而类型擦除使得泛型的参数类型消失,在运行中无法进行监测

但是允许创建通配符类型的数组

// Not really allowed.
List<String>[] lsa = new List<String>[10];
// OK, array of unbounded wildcard type.
List<?>[] lsa = new List<?>[10];

声明参数化类型的数组是可行的,所以可以实现如下的泛型数组

//HashMap中的泛型数组
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
//ConcurrentHashMap中的泛型数组
@SuppressWarnings("unchecked")
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

通配符类型

通配符类型允许类型参数变化,通配符,分为子类型限定、超类型限定和无限定。通配符不是类型变量,因此不能在代码中使用"?"作为一种类型

子类型限定
表示类型的上界,格式? extends A
作用:主要用来读取数据,可以访问A及其子类型

超类型限定
表示类型的下界,限定为A和A的超类型,格式是? super A特点:
作用:主要用来写入数据,可以写入A及其子类型

public static void addNumbers(List<? super Number> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i); //可以添加Integer以及它的子类
    }
}

举例:
Collections类中的public static <T extends Comparable<? super T>> void sort(List<T> list)方法的类型声明,可以处理T没有实现Comparable接口,而T的父类实现了的情况,类似于外部提供比较器的方法:
public static <T> void sort(List<T> list, Comparator<? super T> c)

无限定通配符
用法 ,例如List<?>,表示未知类型的list

  • 如果方法可以通过Object类提供的函数实现功能
  • 使用泛型类的方法,不依赖类型参数的情况,例如List.size List.clear

使用场景:

public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

List<Object>List<?> 是不同的 ,List<?>只能插入null

综合理解

//定义 Level3 extends Level2,Level2 extends Level1
    public static void main(String[] args) {
        List<? extends Level2> a = new ArrayList<>();
        List<? super Level2> b = new ArrayList<>();
//        a.add(new Level1(0));
//        a.add(new Level2(0));    // 错误
//        a.add(new Level3(0));
        a.add(null); // works

        Level1 a1 = a.get(0);
        Level2 a2 = a.get(0);
//        Level3 a3 = a.get(0); //错误



//        b.add(new Level1(0));     //错误
        b.add(new Level2(0));
        b.add(new Level3(0));

        Object o = b.get(0);
//        Level1 b1 = b.get(0);
//        Level2 b2 = b.get(0);   // 错误
    }

虚拟机中的泛型类型信息

Class文件实际保留了泛型信息,位于在Signature属性中,类型擦除只是对Code属性中的字节码
可以通过反射读取相关信息,其核心是Type类型,根据其不同的子类型,获取泛型信息,具体方法可以查看API文档

Type的子类

相关文章

  • Java 内部类和泛型的理解

    Java 内部类 Java非静态内部类持有对外部类的引用,可以访问外部类的状态使用方法 OuterClass.th...

  • 2020Android面试学习

    Java String 有多长? 匿名内部类 泛型 获取泛型 onActivityResult使用很麻烦,为什么不...

  • Java 泛型擦除原理

    问:请比较深入的谈谈你对 Java 泛型擦除的理解和带来的问题认识? 答:Java 的泛型是伪泛型,因为在编译期间...

  • 泛型琐碎之泛型上下限

    泛型的命名规范 为了更好地去理解泛型,我们也需要去理解java泛型的命名规范。 为了与java关键字区别开来,ja...

  • Java 泛型

    java 泛型 很多朋友对java的泛型不是很理解,很多文章写的已不是很清楚,这篇博客对java泛型进行 一个总结...

  • java泛型理解及应用

    内容: java泛型理解及应用

  • Java泛型教程

    Java泛型教程导航 Java 泛型概述 Java泛型环境设置 Java泛型通用类 Java泛型类型参数命名约定 ...

  • 泛型

    java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一Java泛型深入理解加泛型面试数组的协变性与范型的不可变性

  • 反射获取泛型类型

    参考:步步理解 JAVA 泛型编程(一)

  • Kotlin 泛型

    Kotlin 支持泛型, 语法和 Java 类似。例如,泛型类: 泛型函数: 类型变异 Java 的泛型中,最难理...

网友评论

      本文标题:Java 内部类和泛型的理解

      本文链接:https://www.haomeiwen.com/subject/ewurrxtx.html