Java核心技术卷I:基础知识(原书第8版):12.9 反射和泛型

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

铁文整理

12.9 反射和泛型

    现在,Class类是泛型的。例如,String.class实际上是一个Class<String>类的对象(事实上是惟一的对象)。

    类型参数十分有用,这是因为它允许Class<T>方法的返回类型更加具有针对性。下面Class<T>中的方法就使用了类型参数:

    T newInstance()

    T cast(Object obj)

    T[] getEnumConstants()

    Class<? super T> getSuperclass()

    Constructor<T> getConstructor(Class... parameterTypes)

    Constructor<T> getDeclaredConstructor(Class... parameterTypes)

    newInstance方法返回一个实例,这个实例所属的类由默认的构造器获得。它的返回类型目前被声明为T,其类型与Class<T>描述的类相间,这样就免除了类型转换。

    如果给定的类型确实是T的一个子类型,cast方法就会返回一个现在声明为类型T的对象,否则,抛出一个BadCastException异常。

    如果这个类不是enum类或类型T的枚举值的数组,getEnumConstants方法将返回null

    最后,getConstructorgetDeclaredConstructor方法返回一个Constructor<T>对象。Constructor类也已经变成泛型,以便newInstance方法有一个正确的返回类型。

APIjava.lang.Class<T> 1.0

  • T newInstance() 5.0:返回默认构造器构造的一个新实例。

  • T cast(Object obj) 5.0:如果obj为null或有可能转换成类型T,则返回obj;否则抛出BadCastException异常。

  • T[] getEnumConstants() 5.0:如果T是枚举类型,则返回所有值组成的数组,否则返回null。

  • Class<? super T> getSuperclass() 5.0:返回这个类的超类,如果T不是一个类或Object类,则返回null。

  • Constructor<T> getConstructor(Class... parameterTypes) 5.0

  • Constructor<T> getDeclaredConstructor(Class... parameterTypes) 5.0:获得公有的构造器,或带有给定参数类型的构造器。

APIjava.lang.reflect.Constructor<T> 1.1

  • T newInstanca(Object... parameterTypes) 5.0:返回用指定参数构造的新实例。

12.9.1 使用Class<T>参数进行类型匹配

    有时,匹配泛型方法中的Class<T>参数的类型变量很有实用价值。下面是一个具有一定权威的示例:

    public static <T> Pair<T> makePair(Class<T> c)

            throws InstantiationException, IllegalAccessException {

        return new Pair<T>(c.newInstance(), c.newInstance());

    }

    如果调用makePair(Employee.class)Employee.class是类型Class<Employee>的一个对象。makePair方法的类型参数TEmployee匹配,并且编译器可以推断出这个方法将返回一个Pair<Employee>

12.9.2 虚拟机中的泛型类型信息

    Java泛型的卓越特性之一是在虚拟机中泛型类型的擦除。令人感到奇怪的是,擦除的类仍然保留一些泛型祖先的微弱记忆。例如,原始的Pair类知道源于泛型类Pair<T>,即使一个Pair类型的对象无法区分是由Pair<String>构造的还是由Pair<Employee>构造的。

    类似地,看一下方法

    public static Comparable min(Comparable[] a)

    这是一个泛型方法的擦除

    public static <T extends Comparable<? super T>> min(T[] a)

    可以使用Java SE 5.0增加的反射API来确定:

  • 这个泛型方法有一个叫做T的类型参数。

  • 这个类型参数有一个子类型限定,其自身又是一个泛型类型。

  • 这个限定类型有一个通配符参数。

  • 这个通配符参数有一个超类型限定。

  • 这个泛型方法有一个泛型数组参数。

    换句话说,需要重新构造实现者声明的泛型类以及方法中的所有内容。但是,不会知道对于特定的对象或方法调用,如何解释类型参数。

    注释:包含在类文件中,让泛型反射可用的类型信息与旧的虚拟机不兼容。

    为了表达泛型类型声明,Java SE 5.0java.lang.reflect包中提供了一个新的接口Type。这个接口包含下列子类型:

  • Class类,描述具体类型。

  • TypeVariable接口,描述类型变量(如T extends Comparable<? super T>)。

  • WildcardType接口,描述通配符(如? super T)。

  • ParameterizedType接口,描述泛型类或接口类型(如Comparable<? super T>)。

  • GenericArrayType接口,描述泛型数组(如T[] p)。

    12-5给出了继承层次。注意,最后4个子类型是接口,虚拟机将实例化实现这些接口的适当的类。

    12-4使用泛型反射API打印出给定类的有关内容。如果用Pair类运行,将会得到下列报告:

class Pair<T> extends java.lang.Object

    public T getFirst()

    public T getSecond()

    public void setFirst(T)

    public void setSecond(T)

    如果使用PairTest2目录下的ArrayAlg运行,将会得到下列报告

    public static <T extends java.lang.Comparable> Pair<T> minmax(T[])

    本节末尾的API注释描述了示例程序中使用的这些方法。

12-4 GenericReflectionTest.java

import java.lang.reflect.*;

import java.util.*;

 

/**

 * @version 1.10 2007-05-15

 * @author Cay Horstmann

 */

public class GenericReflectionTest {

      public static void main(String[] args) {

           // read class name from command line args or user input

           String name;

           if (args.length > 0)

                 name = args[0];

           else {

                 Scanner in = new Scanner(System.in);

                 System.out.println("Enter class name (e.g. java.util.Collections): ");

                 name = in.next();

           }

 

           try {

                 // print generic info for class and public methods

                 Class<?> cl = Class.forName(name);

                 printClass(cl);

                 for (Method m : cl.getDeclaredMethods())

                      printMethod(m);

           } catch (ClassNotFoundException e) {

                 e.printStackTrace();

           }

      }

 

      public static void printClass(Class<?> cl) {

           System.out.print(cl);

           printTypes(cl.getTypeParameters(), "<", ", ", ">", true);

           Type sc = cl.getGenericSuperclass();

           if (sc != null) {

                 System.out.print(" extends ");

                 printType(sc, false);

           }

           printTypes(cl.getGenericInterfaces(), " implements ", ", ", "", false);

           System.out.println();

      }

 

      public static void printMethod(Method m) {

           String name = m.getName();

           System.out.print(Modifier.toString(m.getModifiers()));

           System.out.print(" ");

           printTypes(m.getTypeParameters(), "<", ", ", "> ", true);

 

           printType(m.getGenericReturnType(), false);

           System.out.print(" ");

           System.out.print(name);

           System.out.print("(");

           printTypes(m.getGenericParameterTypes(), "", ", ", "", false);

           System.out.println(")");

      }

 

      public static void printTypes(Type[] types, String pre, String sep,

                 String suf, boolean isDefinition) {

           if (pre.equals(" extends ") && Arrays.equals(types, new Type[] { Object.class }))

                 return;

           if (types.length > 0)

                 System.out.print(pre);

           for (int i = 0; i < types.length; i++) {

                 if (i > 0)

                      System.out.print(sep);

                 printType(types[i], isDefinition);

           }

           if (types.length > 0)

                 System.out.print(suf);

      }

 

      public static void printType(Type type, boolean isDefinition) {

           if (type instanceof Class) {

                 Class<?> t = (Class<?>) type;

                 System.out.print(t.getName());

           } else if (type instanceof TypeVariable) {

                 TypeVariable<?> t = (TypeVariable<?>) type;

                 System.out.print(t.getName());

                 if (isDefinition)

                      printTypes(t.getBounds(), " extends ", " & ", "", false);

           } else if (type instanceof WildcardType) {

                 WildcardType t = (WildcardType) type;

                 System.out.print("?");

                 printTypes(t.getUpperBounds(), " extends ", " & ", "", false);

                 printTypes(t.getLowerBounds(), " super ", " & ", "", false);

           } else if (type instanceof ParameterizedType) {

                 ParameterizedType t = (ParameterizedType) type;

                 Type owner = t.getOwnerType();

                 if (owner != null) {

                      printType(owner, false);

                      System.out.print(".");

                 }

                 printType(t.getRawType(), false);

                 printTypes(t.getActualTypeArguments(), "<", ", ", ">", false);

           } else if (type instanceof GenericArrayType) {

                 GenericArrayType t = (GenericArrayType) type;

                 System.out.print("");

                 printType(t.getGenericComponentType(), isDefinition);

                 System.out.print("[]");

           }

      }

}

APIjava.lang.Class<T> 1.0

  • TypeVariable[] getTypeParameters() 5.0:如果这个类型被声明为泛型类型,则获得泛型类型变量,否则获得一个长度为0的数组。

  • Type getGenericSuperclass() 5.0:获得被声明为这一类型的超类的泛型类型,如果这个类型是Object或不是一个类类型,则返回null。

  • Type[] getGenericInterfaces() 5.0:获得被声明为这个类型的接口的泛型类型(以声明的次序),否则,如果这个类型没有实现接口,返回长度为0的数组。

APIjava.lang.reflect.Method 1.1

  • TypeVariable[] getTypeParameters() 5.0:如果这个方法被声明为泛型方法,则获得泛型类型变量,否则返回长度为0的数组。

  • Type getGenericReturnType() 5.0:获得这个方法被声明的泛型返回类型。

  • Type[] getGenericParameterTypes() 5.0:获得这个方法被声明的泛型参数类型。如果这个方法没有参数,返回长度为0的数组。

APIjava.lang.reflect.TypeVariable 5.0

  • String getName():获得类型变量的名字。

  • Type[] getBounds():获得类型变量的子类限定,否则,如果该变量无限定,则返回长度为0的数组。

APIjava.lang.reflect.WildcardType 5.0

  • Type[] getLowerBounds():获得这个类型变量的子类(extends)限定,否则,如果没有子类限定,则返回长度为0的数组。

  • Type[] getUpperBounds():获得这个类型变量的超类(super)限定,否则,如果没有超类限定,则返回长度为0的数组。

APIjava.lang.reflect.ParameterType 5.0

  • Type getRawType():获得这个参数化类型的原始类型。

  • Type[] getActualTypeArguments():获得这个参数化类型声明时所使用的类型参数。

  • Type getOwnerType():如果是内部类型,则返回其外部类型,如果是一个顶级类型,则返回null。

APIjava.lang.reflect.GenericArrayType 5.0

  • Type getGenericComponentType():获得声明该数组类型的泛型组合类型。

    现在已经学习了如何使用泛型类以及在必要时如何自定义泛型类和泛型方法。同样重要的是,学习了如何解译在API文档和错误消息中遇到的泛型类型声明。要想了解有关Java泛型更加详尽的信息,可以到http://angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html上求助。那里有一个很好的常见问题解答列表(也有一些不太常见的)。

    在下一章中,将学习Java集合框架如何使用泛型。


Java核心技术基础知识 - 原书9深入解析 本文还有配套的精品资源,点击获取 简介:《Java核心技术 1 基础知识》第9详细介绍了Java的核心概念编程实践,包括面向对象、异常处理、字符串处理等基础知识,以及I/O、多线程、反射等高级特性。本书为读者提供了全面的知识体系,从初学者到有经验的开发者均适用。 1. Java语言核心概念介绍 Java语言自1995年问世以来,因其"一次编写,到... 阅读详情

相关推荐

Java反射上使用

Java 中 我们可以用类名.Calss or 对象名.getClass()去获得一个Class。而这个Class本身也是一个类,而且是1个类。....所以在反射中, 我们也可以使用的。这里只介绍两个常用的类Class>

nvd11的专栏 1716

Java核心技术I》java接口 笔记

写在最前:本笔记全程参考《Java核心技术I》,添加了一些个人的思考整理 接口 1、接口的概念 接口用来描述类应该做什么,而不指定他们应该怎么做。 接口不是类,而是对希望符合这个接口的类的一组需求。不可以实例化(new)一个接口 一个类可以实现零或多个接口 接口的所有方法都是public抽象方法,所以可以省略关键字public abstract(例外:默认方法)   让类实现接口通常需要下面两个步骤: 使用关键字implements实现接口:public class Employee impl.

mrhanzhou5273的博客 4838

Java核心技术 1》

<1>静态字段静态方法 class Employee{ private static int nextId= 1; private int id; .... } 每一个Employee对象都有一个自己的id字段,但是这个类的所有实例将共享一个nextId字段,换句话说,如果有1000个Employee类对象,则有1000个实例字段id,分别对应一个对象,但是只有一个静态字段nextId,即使没有Employee对象,静态字段nextId也存在,它属于类,...

早起吃虫的博客 5459

java核心技术——反射

一、什么是反射? 1. Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性方法,不受访问修饰符的限制。本质是JVM得到类对象之后,再通过类对象进行反编译,从而获取对象的各种信息。 2. Java属于先编译再运行的语言,程序中对象的类在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁能够分析类能力的程序称为反射(re...

qq_45251343的博客 542

Java 核心技术 I —— 第1章 Java 程序设计概述

Sun 公司使用 Java 开发新的浏览器 HotJava,能够在网页中执行内嵌的 Java 代码,用来展示 Java 语言的强势能力,并于 1995 年在 SunWorld’95 大会上展示,引发了人们对 Java 的狂热追逐。​ 1996 年,Sun 公司发布了 Java 第 1 个本,但 Java 1.0 并不能很好地用来完成应用开发,后来推出的 Java 1.1 弥补了第 1 的大部分缺陷,大大改进了反射能力,并为 GUI 编程添加了新内容,但仍有很大的局限性。运行 Java 字节码的虚拟机。

zheliku的博客 411

Java核心技术·I(原书12

他是《Java核心技术》两本的作者,也是《重要的,第二(Addison-Wesley,2018)的Core Java SE 9《重要的,第二(Addison-Wesley,2017)的作者。读者应在充分理解Java语言Java类库的基础上,灵活应用Java提供的高级特性,包括面向对象编程、反射代理、接口内部类、异常处理、编程、集合框架、事件监听器模、图形用户界面设计并发。☉第四章介绍了面向对象的两大基石——封装的重要概念,以及Java语言实现封装的机制——类方法;

jascl的博客 1万+

Java编程的终极导航:《Java核心技术》系列全面解读

在编程世界中,Java的位置无可替代,无论是企业级应用、移动应用开发,还是大数据处理,Java都扮演着重要的角色。对于刚刚踏入这个领域的新手来说,有一条清晰的路线图是非常必要的;而对于经验丰富的开发者而言,及时更新知识库、了解新技术同样重要。这时,`《Java核心技术 I:开发基础(原书12)》`与`《Java核心技术 II:高级特性(原书12)》`便是你的灯塔,为你的Java学习之旅指引方向

hacker707的博客 2万+

Java 核心技术 1》 笔记 第12程序设计(9反射中的

反射中,怎么获取

yu_duan_hun的博客 878

Java核心技术I》篇笔记() 反射

写在最前:本笔记全程参考《Java核心技术I》,添加了一些个人的思考整理 反射 1. Class类 Class类是的,例如,String.class是一个Class<String>的对象(且是唯一的对象) 这个类参数分词有用,它允许Class<T>的方法返回特定的数据类。 newInstance方法返回一个这个类的实例对象,由无参数构造器获取。它的返回值类被声明为T,与CLass中声明的参数相同,这样就避免了类转换。   2. 使用Class&lt.

mrhanzhou5273的博客 286

java核心技术 1 基础知识 原书8

1995年底,Java语言在Internet舞台一亮相便名声大噪。其原因在于它将有望成为连接用户 与信息的万能胶,而不论这些信息来自于Web服务器、数据库、信息提供商,还是任何其他渠 道。事实上,就发展前景而言,Java的地位是独一无二的。它是一种完全可信赖的程序设计语 言,得到了除微软之外的所有厂家的认可。其固有的可靠性与安全性不仅令Java程序员放心, 也令使用Java程序的用户放心。Java...

qq_27934465的博客 579

Java 核心技术 I 基础知识8程序设计

8.1 为什么要使用程序设计 8.1.1 类参数的好处 8.1.2 谁想成为程序员 8.2 定义简单类 package pair1; /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ public class Pair<T> { private T first; privat...

dldldl1994的博客 449

Java核心技术I》篇笔记() 的特性局限

写在最前:本笔记全程参考《Java核心技术I》,添加了一些个人的思考整理 的特性、限制局限性 1. 不能用基本数据类实例化参数 例如,没有ArrayList<int>,或者Pair<double>,而只有ArrayList<Integer>以及Pair<Double> 因为在类擦除之后,所有的都将转换为限定类或者Object,但是基本数据类不能转换为Object   2. 运行时类查询只适用于原始类 例如,对于代码if (a in.

mrhanzhou5273的博客 509

Java 核心技术 I 学习记录十三

一个()就是具有一个或多个类变量的类。接下来使用一个简单的Pairpublic class Pair<T> { // pair类引入一个类变量T,用尖括号<>括起来,并放在类名的后面。类可以有多个类变量// 域局部变量的类} // 类定义中的类变量指定方法的返回类用具体的类替代类变量就可以实例化类。可以想象成带有构造器的普通类。// 使用构造// 无参构造// 带参构造// 方法。

2401_87797168的博客 827

Java核心技术(原书第10) Ⅰ》个人心得与总结

2019.3.20《 Java核心技术1)》 总结 《 Java核心技术1)》 总结 拖了这么久,终于来了。我发现在学习上很多时候我真是拖延患者。一给自己安排的任务重,学习效率低下,二是计划总赶不上变化。 大概花了有2,3个月的时间吧,从1月份到3.5号,完整地看完了这本书,中间断断续续。整体看完后的几个感受吧。 基础知识讲得很细,很全面,但这样也导致了不太容易阅读,也会比较枯燥。所以我...

qq_38689900的博客 1057

Java[6] 程序

类(接口) 方法 类限定 类擦除 通配符 子类通配符限定 超类通配符限定 限制与局限

DO_Lee的博客 1023

Java核心技术 I》学习笔记29程序设计

Java程序设计

qq_48814205的博客 709

Java】 第八章 程序设计 Java核心技术1基础知识原书第10 读书笔记

第八章 程序设计8.程序设计8.1 为什么要使用程序设计8.1.1 类参数的好处8.1.2 谁想成为程序员8.2 定义简单8.3 方法8.4 类变量的限定8.5 代码虚拟机8.5.1 类擦除8.5.2 翻译表达式8.5.3 翻译方法8.5.4 调用遗留代码8.6 约束与局限性8.6.1 不能用基本类实例化类参数8.6.2 运行时类查询只适用于原始类8.6.3 不能创建参数化类的数组8.6.4 Varargs 警告8.6.5 不能实例化类变置8.6.6

Evelyn的博客 274

Java基础疑难点梳理(反射9章内容)

Java基础疑难点梳理(反射9章内容)

CodePanda@GPF的博客 980

Java核心技术I》java反射 笔记

写在最前:本笔记全程参考《Java核心技术I》,添加了本人对反射的一些使用心得 反射 1、反射概述 反射机制的作用 能够分析类能力的程序称为反射(reflective),它可以用来: 在运行时分析类 在运行时检查对象 实现数组操作代码 利用Method对象调用方法   反射机制重要的相关的类 java.lang.Class代表整个字节码,代表一个类 java.lang.reflect.Method代表字节码中的方法字节码, java.lang.reflect.Constructor方便字节码.

mrhanzhou5273的博客 389
上一篇: Java核心技术卷I:基础知识(原书第8版):12.8 通配符类型
下一篇: Java核心技术卷I:基础知识(原书第8版):13.1 集合接口
铁文
博客等级 码龄22年 441粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值