`

JAVA基础知识之JVM-——反射和泛型

    博客分类:
  • java
 
阅读更多

转自:https://www.cnblogs.com/fysola/p/6112706.html

 

泛型和Class类

在反射中使用泛型Class<T>可以避免强制类型转换,下面是一个简单例子,如果不使用泛型的话,需要显示转换,

复制代码
 1 package aop;
 2 
 3 import java.util.Date;
 4 
 5 import javax.swing.JFrame;
 6 
 7 public class ObjectFactory {
 8     public static Object getInstance(String clsName) {
 9         try {
10             Class cls = Class.forName(clsName);
11             return cls.newInstance();        
12         } catch (Exception e) {
13             e.printStackTrace();
14             return null;
15         }
16     }
17     
18     public static void main(String[] args) {
19         Date d = (Date)ObjectFactory.getInstance("java.util.Date");
20         JFrame f = (JFrame)ObjectFactory.getInstance("java.util.Date");
21     }
22 }
复制代码

上面的例子第19行和20行都需要将Class的newInstance返回的Object结果强制转换成目标类型,这不仅麻烦,更重要的是有些情况下无法发现错误,

例如第20行,强制转换可以通过编译的,但是运行期间可能会报错,原因是强制将Date类型转换成JFrame类型,类型不匹配,下面是执行结果,

1 Exception in thread "main" java.lang.ClassCastException: java.util.Date incompatible with javax.swing.JFrame
2     at aop.ObjectFactory.main(ObjectFactory.java:20)

下面用泛型来实现getInstance,  即  public static <T> T getInstance(Class<T> cls)

复制代码
 1 package aop;
 2 
 3 import java.util.Date;
 4 
 5 import javax.swing.JFrame;
 6 
 7 public class ObjectFactory2 {
 8     public static <T> T getInstance(Class<T> cls) {
 9         try {
10             return cls.newInstance();        
11         } catch (Exception e) {
12             e.printStackTrace();
13             return null;
14         }
15     }
16     
17     public static void main(String[] args) {
18         Date d = ObjectFactory2.getInstance(Date.class);
19         JFrame f = ObjectFactory2.getInstance(JFrame.class);
20     }
21 }
复制代码

上面的第19行如果类型不符,例如写成了JFrame f = ObjectFactory2.getInstance(Date.class); , 则无法通过编译,

必须要修改成匹配的类型才能通过编译, 很好地编码了隐形错误。

泛型和数组

泛型中的数组虽然也使用了泛型编程,但却没有实现泛型功能, 泛型数组的newInstance方法签名是这样的,

1 public static Object newInstance(Class<?> componentType, int... dimensions)

虽然上面的定义也使用了泛型,但是却没有真正实现泛型,所以这个方法返回的对象arr依然是个Object类型,要当成数组使用的话还是需要强制转换成数组类型。

如果将上面的方法签名改成这样,

1 public static <T> T[] newInstance(Class<T> componentType, int length)

这样返回的arr就是个数组类型了,无需强制转换就可以当作数组用。

下面是一个将反射(reflect)中的Array的newInstance包装成泛型之后再使用的例子,

复制代码
 1 package aop;
 2 
 3 import java.lang.reflect.Array;
 4 
 5 public class MyArray {
 6     public static <T> T[] newInstance(Class<T> componentType, int length) {
 7         return (T[])Array.newInstance(componentType, length);
 8     }
 9     
10     public static void main(String[] args) {
11         //使用MyArry的newInstance创建数组
12         String[] arr = MyArray.newInstance(String.class, 10);
13         //使用MyArray的newInstance创建二维数组
14         int[][] intArr = MyArray.newInstance(int[].class, 5);
15         arr[5] = "天王盖地虎";
16         intArr[1] = new int[]{23,12};
17         System.out.println(arr[5]);
18         System.out.println(intArr[1][1]);
19     }
20 }
复制代码

输出结果, 可以看到上面已经刻在无需强制转换成数组的情况下,直接将arr和intArr作为数组来使用了,

1 天王盖地虎
2 12

 使用反射来获取泛型信息

通过反射可以获取指定类的成员变量, 方法是 Field f = clazz.getDeclaredField("成员变量名称");

之后,可以用f对象获取它的类型,对于普通类型的成员变量,可以用Class<?> a = f.getType(); 方式获取

但是对于泛型的成员变量,例如 Map<String, Integer> score; getType()只能获取原始类型,这里是Map

如果要获取泛型类型(即尖括号里面的参数类型),

  1. 首先需要获取成员变量的泛型类型, 通过Type gType = f.getGenericType();
  2. 然后将泛型对象gType强制转换成参数化类型ParameterizedType的对象pType;  (ParameterizedType包含两个方法,getRawType(), 返回原始类型,和上面的getType一样。getActualTypeArguments(), 返回泛型参数的类型,也就是Map<String, Integer> 括号里的类型)
  3. 使用getActualTypeArguments()返回泛型信息

下面来演示一下使用反射来获取泛型信息,

复制代码
 1 package aop;
 2 
 3 
 4 import java.lang.reflect.Field;
 5 import java.lang.reflect.ParameterizedType;
 6 import java.lang.reflect.Type;
 7 import java.util.Map;
 8 
 9 public class GenericTest {
10     private Map<String, Integer> score;
11     public static void main(String[] args) throws Exception {
12         Class<GenericTest> clazz = GenericTest.class;
13         Field f = clazz.getDeclaredField("score");
14         //getType只能取出普通类型,因此下面的a只能得到java.util.Map类型
15         Class<?> a = f.getType();
16         System.out.println("score的类型是: " + a);
17         //获取泛型类型
18         Type gType = f.getGenericType();
19         // 如果gType类型是ParameterizedType对象
20         if (gType instanceof ParameterizedType) {
21             //泛型对象强制转换成参数化类型对象
22             ParameterizedType pType = (ParameterizedType)gType;
23             //获取原始类型,即java.util.Map
24             Type rType = pType.getRawType();     
25             System.out.println("原始类型: "+rType);
26             //获取泛型括号里面参数的类型
27             System.out.println("泛型参数类型:");
28             Type[] tArgs = pType.getActualTypeArguments();
29             for (int i = 0; i < tArgs.length; i++ ) {
30                 System.out.println("第["+i+"]个参数的泛型类型是: "+tArgs[i]);
31             }
32         } else {
33             System.out.println("获取泛型类型错误");
34         }
35     }
36 }
复制代码

输出结果,

1 score的类型是: interface java.util.Map
2 原始类型: interface java.util.Map
3 泛型参数类型:
4 第[0]个参数的泛型类型是: class java.lang.String
5 第[1]个参数的泛型类型是: class java.lang.Integer
分享到:
评论

相关推荐

    java基础——————试题库

    这个“java_test”文件很可能是包含了一系列测试题目的集合,涵盖了以上提到的所有Java基础知识点,通过练习这些题目,你可以检验自己的学习成果,发现并弥补知识盲点,进一步巩固Java基础。在学习过程中,不断实践...

    JAVA核心知识点整理——java自学资料.rar

    这份"JAVA核心知识点整理——java自学资料.rar"包含了一份详细的Java学习资源,旨在帮助已经具备一定Java基础知识的开发者进一步提升技能,深入理解Java的底层机制。以下是这份资料可能涵盖的一些核心知识点和学习...

    java私塾跟我学系列-java篇

    Java私塾跟我学系列是为Java初学者精心编纂的一套教程,旨在系统地介绍Java编程语言的基础知识和实际应用。这个系列涵盖了从语言基础到高级特性的全面内容,是编程爱好者入门和进阶的理想资源。 Java是一种面向对象...

    达内JAVA TTS5.0 PDF----JAVA SE核心2

    这份资料可能是针对已经掌握了Java基础知识的学习者,旨在帮助他们深化对Java语言的理解,提升编程能力。 首先,我们要理解Java SE的主要组成部分。Java SE包括了Java运行时环境(JRE)、Java开发工具集(JDK)以及...

    115个Java面试题和答案——终极列表

    1. **Java基础** - **数据类型**:Java分为基本数据类型(如int, double, boolean等)和引用数据类型(类、接口、数组)。理解它们的区别和用法至关重要。 - **变量**:变量是存储数据的容器,分为实例变量、类...

    java葵花宝典——各种问题详细解答

    1. **Java基础知识** - **Java语法**:Java的基础语法包括变量声明、数据类型、运算符、流程控制语句(如if-else、switch、for、while等)和异常处理机制。了解这些基本元素是编写任何Java程序的前提。 - **类与...

    高级JAVA面试——最全的总结

    1. **JAVA基础** - 类与对象:理解面向对象编程的基础,包括封装、继承和多态。 - 内存管理:理解堆栈内存分配,了解垃圾回收机制(GC)。 - 异常处理:学习如何使用try-catch-finally语句块处理异常,理解检查型...

    JAVA语言学习课件--从零开始

    1. **Java基础知识**:Java的起源与发展,JVM(Java虚拟机)的工作原理,理解“Write Once, Run Anywhere”(一次编写,到处运行)的概念。 2. **环境配置**:安装JDK(Java Development Kit),配置环境变量,设置...

    [Java学习笔记doc]-javase基本知识

    **Java学习笔记——Java SE基本知识** Java是一种广泛使用的面向对象的编程语言,以其跨平台、安全性高和可移植性而闻名。Java Standard Edition(Java SE)是Java平台的基础,它提供了开发和运行桌面应用程序、...

    java面试——杭州-阿里云-Java中级.zip

    1. **基础语法**:了解和掌握Java的基础语法是必要的,包括类、对象、封装、继承、多态等面向对象编程概念。此外,还要熟悉异常处理、数据类型、运算符、流程控制语句。 2. **集合框架**:理解ArrayList、...

    精通JAVA——JDK(高清PDF文件)

    这些基础知识是每个Java程序员必备的。 2. **面向对象编程**:Java是一种强类型、面向对象的语言,书中将详细介绍类的创建、继承、多态性和封装等概念,以及如何设计和实现高效的对象模型。 3. **JDK核心API**:...

    基础知识和Java概述

    Java的成功在于它的设计理念——“一次编写,到处运行”(Write Once, Run Anywhere,WORA),这得益于Java虚拟机(JVM)的广泛支持。 1. **Java简介** Java的设计目标是简洁、健壮和高效。它吸收了C++的优点,如...

    Java语言程序设计A——课件

    9. **泛型**:泛型是Java 5引入的新特性,提高了代码的类型安全性和重用性,学习泛型可以编写更高效、更灵活的代码。 10. **接口与抽象类**:接口和抽象类是实现多态和模块化设计的重要工具,课件会详细讲解它们的...

    Java 笔试题————Java找工作的宝典

    1. **Java基础** - **数据类型**:Java有两大类数据类型,基本类型和引用类型。基本类型包括整型(byte, short, int, long)、浮点型(float, double)、字符型(char)和布尔型(boolean)。引用类型则包括类、...

    115个Java面试题和答案——终极(下)(1).rar

    以上就是文档中可能涉及的一些Java面试知识点,理解并熟练掌握这些内容将有助于你在面试中展现出扎实的Java基础和解决问题的能力。在实际面试中,除了理论知识,面试官还可能关注你的实际项目经验、问题解决能力和...

    八股文知识点汇总——Java面试题指南

    以上只是Java面试题的一部分,涵盖了许多基础知识,对于Java程序员来说,深入理解这些概念和原理对于职业发展至关重要。其他面试题如集合、异常处理、IO/NIO、反射、序列化、注解、多线程并发、JVM优化、数据库技术...

    Java软件开发实战 Java基础与案例开发详解 20-1 项目实战2-网络五子棋与网络版JQ的开发 共17页.pdf

    根据提供的文档信息,我们可以归纳出该文档主要涵盖了Java软件开发的基础知识及项目实战案例,特别是针对网络五子棋和网络版JQ(类似QQ的聊天工具)的开发过程进行了详细介绍。接下来,我们将从文档的标题、描述以及...

    java面试题大全-葵花宝典和面试编程

    Java基础是面试中常常被考察的部分,包括但不限于: 1. Java语言特性:如封装、继承、多态等面向对象概念,以及异常处理、垃圾回收机制。 2. 数据类型:了解基本数据类型和引用类型,包括它们的内存分配和生命周期。...

    BAT 115个Java面试题和答案——终极(下)

    在Java面试中,掌握核心知识点和能够解决实际问题的能力至关重要,特别是对于想在BAT(百度、阿里巴巴、腾讯)这样的顶级互联网公司工作的求职者而言。以下是一些基于标题和描述所暗示的Java面试知识点的详细说明: ...

    java基础反射IO流线程模式

    ### 类加载器 ...通过以上介绍,我们可以看到Java基础中包含了许多重要的知识点和技术,这些技术对于开发高质量的应用程序至关重要。掌握这些基本概念和技术,对于成为一名合格的Java开发者来说是非常重要的。

Global site tag (gtag.js) - Google Analytics