java 反射类的泛型_廖雪峰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();

dda574ef78db0c6fcc4615fc4aae80be.png

class/interface的数据类型是Class。

每加载一个class,JVM就为其创建一个Class类型的实例,并关联起来。Class实例是JVM内部创建的。

25fd19c54983c21f5ddfd76ef89150a1.png

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);

}

}

}

28c35d626dcc64f1c34a56be377a76ff.png

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和java.lang.Class

boolean b3 = n instanceof Integer;

System.out.println("n instanceof Integer: " + b3);

boolean b4 = n instanceof Number;

System.out.println("n instanceof Number: " + b4);

}

833fed30503d29a320e8cce7baf1450b.png

通常情况下,使用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);

}

}

da32c1d58979d4662232592373897154.png

从Class实例判断class类型

* isInterface() 是否是接口

* isEnum() 是否是枚举类

* isArray() 是否是数组

* isPrimitive() 是否是基本类型

```#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);

}

}

9453d21772c34d1fe3c054a6100a87d5.png

## 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();

}

}

242c6b212f6d2a365052eee0cd42c7c6.png

改写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;

}

}

}

2ecd7763fe04592074ecca2fbc6b0086.png

# 4.总结

* JVM为每个加载的class创建对应的Class实例来保存class的所有的信息

* 获取一个class的Class实例后,就可以获取该class的所有信息

* 通过Class实例获取class信息的方法成为反射Reflection

* JVM总是动态加载class,可以在运行期根据条件控制加载class

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值