廖雪峰Java4反射与泛型-1反射-1Class类
1.Class类与反射定义
Class类本身是一种数据类型(Type),class/interface的数据类型是Class,JVM为每个加载的class创建了唯一的Class实例。
Class实例包含该class的所有信息,通过Class实例获取class的信息的方法称为反射(Reflection)
Java除基本类型外,其他都是class(包括interface)。如String、Object、Runnable、Exception...
- class(包括interface)的本质是数据类型。我们把一个对象实例赋值给一种数据类型变量时,必须严格按照数据类型赋值。
- 没有继承关系的数据类型是无法赋值的。Java定义了一种强数据类型关系,并且编译器会检查数据类型,不符合数据类型要求的,在赋值时,编译器就会报错。
String s = new String("Hello");
Object o = new Double(123.456);
Runnable r = new Thread();
Exception e = new RuntimeException();
class/interface的数据类型是Class。
每加载一个class,JVM就为其创建一个Class类型的实例,并关联起来。Class实例是JVM内部创建的。
JVM持有的每个Class实例都指向一个数据类型(class或interface)
Class实例 | |
---|---|
name | java.lang.String --> String |
name | java.util.Randome --> Random |
name | java.lang.Runnable --> Runnable |
一个Class实例包含了该class的完整信息。如String的Class实例持有name,package,super,interface,field,method
Class实例 | |
---|---|
name | java.lang.String |
package | java.lang |
super | java.lang.Object |
interface | CharSequence, ... |
field | value[], hash, ... |
method | indexOf, valueOf, ... |
所以Java定义的Class类是:
- JVM为每个加载的class创建对应的Class实例,并在实例中保存该class的所有信息
- 如果获取了某个Class实例,则可以获取到该实例对应的class的所有信息。
- 通过Class实例获取class信息的方法成为反射(Reflection )
2.获取一个class的Class实例
方法1:通过Type.class
Class cls = String.class;
方法2:通过实例getClass()
String s = "Hello";
Class cls1 = s.getClass();
Class cls2 = "Hello".getClass();
方法3:Class.forName(完整类名)
try{
Class cls = Class.forName("java.lang.String");
}catch (Exception e){
System.out.println(e);
}
Class实例在JVM中是唯一的:
- 因此可以用 == 来比较两个Class实例
public class Main {
public static void main(String[] args){
Class cls1 = String.class;
String s = "Hello";
Class cls2 = s.getClass();
System.out.println("cls1 == cls2: " + (cls1 == cls2));
Class cls3;
try{
cls3 = Class.forName("java.lang.String");
System.out.println("cls2 == cls3: " + (cls2 == cls3));
}catch (ClassNotFoundException e){
System.out.println(e);
}
}
}
2.1Class实例比较和instanceof的差别
public class Main {
public static void main(String[] args){
Integer n = new Integer(2);
boolean b1 = n.getClass()==Integer.class;
System.out.println("n.getClass()==Integer.class: " + b1);
boolean b2 = n.getClass()==Number.class;
//System.out.println("n.getClass() == Number.class: "+ b2);//Error:(10, 34) java: 不可比较的类型: java.lang.Class<capture#1, 共 ? extends java.lang.Integer>和java.lang.Class<java.lang.Number>
boolean b3 = n instanceof Integer;
System.out.println("n instanceof Integer: " + b3);
boolean b4 = n instanceof Number;
System.out.println("n instanceof Number: " + b4);
}
通常情况下,使用instanceof判断数据类型,因为面向抽象编程的时候,我们不关心具体的子类型;只有在需要精确判断某个类型的时候,才需要获取其Class进行判断。
## 2.2反射的目的
反射的目的是当获得某个Object实例时,我们可以获取该Object的class信息。
从Class实例获取class信息:
* getName() 获取完整的类名
* getSimpleName() 获取简单的类名
* getPackage() 获取包名
```#java
public class Main {
public static void main(String[] args){
Integer n = new Integer(2);
Class cls = n.getClass();
String fullName = cls.getName();
System.out.println(fullName);
String simpleName = cls.getSimpleName();
System.out.println(simpleName);
String packageName = cls.getPackage().getName();
System.out.println(packageName);
}
}
<img src="https://img2018.cnblogs.com/blog/1418970/201902/1418970-20190203151635280-1262524766.png" width="500" />
从Class实例判断class类型
* isInterface() 是否是接口
* isEnum() 是否是枚举类
* isArray() 是否是数组
* isPrimitive() 是否是基本类型</font>
```#java
public class Main {
public static void main(String[] args){
Boolean b1 = Runnable.class.isInterface();
Boolean b2 = java.time.Month.class.isEnum();
Boolean b3 = String[].class.isArray();
Boolean b4 = int.class.isPrimitive();
Boolean b5 = String.class.isPrimitive();
System.out.println("Runnable.class是接口:"+b1);
System.out.println("java.time.Month.class是枚举累:"+b2);
System.out.println("String[].class是数组:"+b3);
System.out.println("int.class是基本类型:"+b4);
System.out.println("String.class是基本类型:"+b5);
}
}
## 2.3通过newInstance创建新的实例。
```#java
public class Main {
public static void main(String[] args) throws InstantiationException,IllegalAccessException{
Class cls = String.class;
/*通过newInstance可以创建一个新的String实例。
局限:只能调用public的没有参数的构造方法,带参数的构造方法是不能调用的。*/
String s = (String) cls.newInstance();
}
}
```
# 3.动态加载
利用JVM动态加载class的特性:
* 可以在运行期根据条件加载不同的实现类
```#java
public class Main {
//如Commons Logging优先使用Log4j,没有再使用jdk自带的Logging
public static void main(String[] args) {
/*
代码仅供演示。createLog4j()和createJdkLog()未定义
*/
LogFactory factory;
if (isClassPresent("com.apache.Logging.log4j.Logger")){
factory = createLog4j();
}else {
factory = createJdkLog();
}
}
static boolean isClassPresent(String name){
try{
Class.forName(name);//判断一个类是否存在
return true;
}catch (Exception e){
return false;
}
}
}
```
Hello.java
```#java
package com.reflection;
public interface Hello {
public void hello();
}
Student.java
```#java
package com.reflection;
public class Student implements Hello{
private String name;
public Student(){
this("unNamed");
}
public Student(String name){
this.name=name;
}
public void hello(){
System.out.println(name+" is Student");
}
}
Teacher.java
package com.reflection;
public class Teacher implements Hello{
private String name;
public Teacher(){
this("unNamed");
}
public Teacher(String name){
this.name=name;
}
public void hello(){
System.out.println(name+" is Teacher");
}
}
Main.java
package com.reflection;
public class Main {
public static void main(String[] args) throws InstantiationException,IllegalAccessException{
Class cls = Student.class;
System.out.println("class name:"+cls.getName());
System.out.println("class simple name:"+cls.getSimpleName());
System.out.println("class package name:"+cls.getPackage().getName());
Student s = (Student) cls.newInstance();
s.hello();
}
}
改写Main.java,使用动态加载实现
```#java
package com.reflection;
public class Main {
public static void main(String[] args) throws InstantiationException,IllegalAccessException,ClassNotFoundException{
Class cls ;
if (clsClassPresent("com.reflection.President")){
cls = Class.forName("com.reflection.President");
}else{
cls = Class.forName("com.reflection.Student");
}
System.out.println("class name:"+cls.getName());
System.out.println("class simple name:"+cls.getSimpleName());
System.out.println("class package name:"+cls.getPackage().getName());
Hello s = (Hello) cls.newInstance();
s.hello();
}
static boolean clsClassPresent(String name){
try{
Class.forName(name);
return true;
}catch (Exception e){
return false;
}
}
}
<img src="https://img2018.cnblogs.com/blog/1418970/201902/1418970-20190211211313954-898023001.png" width="500" />
# 4.总结
* JVM为每个加载的class创建对应的Class实例来保存class的所有的信息
* 获取一个class的Class实例后,就可以获取该class的所有信息
* 通过Class实例获取class信息的方法成为反射Reflection
* JVM总是动态加载class,可以在运行期根据条件控制加载class
廖雪峰Java4反射与泛型-1反射-1Class类的更多相关文章
- 廖雪峰Java4反射与泛型-3泛型-7泛型和反射
1.部分反射API是泛型 1.1获取反射API的泛型 部分反射API是泛型,如Class<T>是泛型 //如果使用Class,不带泛型,出现compile warning编译警告 Clas ...
- 廖雪峰Java4反射与泛型-3范型-4擦拭法
1.擦拭法是Java泛型的实现方式. 编译器把类型视为Object. * 泛型代码编译的时候,编译器实际上把所有的泛型类型T统一视为Object类型.换句话说,虚拟机对泛型一无所知,所有的工作都是编译 ...
- 廖雪峰Java4反射与泛型-2注解-3处理注解
1.处理注解 注解本身对对代码逻辑没有任何影响 SOURCE类型的注解在编译期就被丢掉了 CLASS类型的注解仅保存在class文件中 RUNTIME类型的注解在运行期可以被读取 如何使用注解由工具决 ...
- 廖雪峰Java4反射与泛型-1反射-2访问字段Field和3调用方法Method
2.字段Field 2.1.通过Class实例获取字段field信息: getField(name): 获取某个public的field,包括父类 getDeclaredField(name): 获取 ...
- 廖雪峰Java4反射与泛型-3范型-6super通配符
1.super通配符 1.1super通配符第一种用法 泛型的继承关系 Pair<Integer>不是Pair<Number>的子类,如 static void set(Pai ...
- 廖雪峰Java4反射与泛型-3范型-5extends通配符
1.泛型的继承关系: Pair<Integer>不是Pair<Number>的子类 add()不接受Pair<Integer> Pair.java package ...
- 廖雪峰Java4反射与泛型-3范型-3编写泛型
编写泛型类比普通的类要麻烦,而且很少编写泛型类. 1.编写一个泛型类: 按照某种类型(例如String)编写类 标记所有的特定类型例如String 把特定类型替换为T,并申明 Pair.java pa ...
- 廖雪峰Java4反射与范型-3范型-1什么是泛型
1.为什么需要泛型? JDK提供了ArrayList,可以看作"可变长度"的数组: 比数组使用方便 示例1:如果使用ArrayList存储String类型: 需要强制转型 不方便, ...
- 廖雪峰Java4反射与泛型-2注解-2定义注解
1.定义注解 使用@interface定义注解Annotation 注解的参数类似无参数方法 可以设定一个默认值(推荐) 把最常用的参数命名为value(推荐) 2.元注解 2.1Target使用方式 ...
随机推荐
- 06 Listener,Filter,BeanUtils
Listener 监听器,监听某一个事件的发生. 状态的改变. 内部机制其实就是接口回调. 接口回调 需求:A在执行循环,当循环到5的时候, 通知B.事先先把一个对象传递给 A , 当A 执行到5的 ...
- windows查询占用端口
https://jingyan.baidu.com/article/3c48dd34491d47e10be358b8.html 1)端口号 - 查进程 netstat -aon|findstr &qu ...
- React中的Context——从父组件传递数据
简介:在React中,数据可以以流的形式自上而下的传递,每当你使用一个组件的时候,你可以看到组件的props属性会自上而下的传递.但是,在某些情况下,我们不想通过父组件的props属性一级一级的往下传 ...
- POI事件模型处理execl导入功能(只支持07版本的execl)
由于通过new XSSFWorkbook 这种方式导入导致生产环境端口宕机.通过dump文件和javacore文件分析是导入功能导致的.解决办法:自己通过网上写的工具类,不知道是否存在bug. pac ...
- 对spark算子aggregateByKey的理解
案例 aggregateByKey算子其实相当于是针对不同“key”数据做一个map+reduce规约的操作. 举一个简单的在生产环境中的一段代码 有一些整理好的日志字段,经过处理得到了RDD类型为( ...
- 使用kube_ping进行Keycloak群集设置 - DZone Cloud
转自:https://www.jdon.com/51501 看看如何使用kube_ping和Keycloak实现自动发现? Keycloak是一个开源软件,提供身份管理和访问管理的单点登录.Keyco ...
- keycloak docker-compose 运行
内容很简单,主要是搭建一个可运行的keycloak 环境,方便开发测试,同时支持数据库的持久化 docker-compose 文件 version: "3" services: a ...
- 【甘道夫】MapReduce实现矩阵乘法--实现代码
之前写了一篇分析MapReduce实现矩阵乘法算法的文章: [甘道夫]Mapreduce实现矩阵乘法的算法思路 为了让大家更直观的了解程序运行,今天编写了实现代码供大家參考. 编程环境: java v ...
- Use swig + lua quick guide
软件swigwin3 用于生成c的lua包装lua5.2源代码 步骤进入目录G:\sw\swigwin-3.0.12\Examples\lua\arrays执行 SWIG -lua ex ...
- CSS背景渐变支持transition过渡效果
background-image 是不支持 CSS3 的transition过渡效果的,而CSS3 gradient 渐变作为背景图片存在的时候, 下面的CSS不会有过渡效果 <div clas ...