java什么是反射 代码说明_什么是反射?

1.对象有编译类型和运行类型

Object obj = new java.util.Date();

编译类型:Object

运行类型(其实就是obj对象真实的类型):java.util.Date

需求:根据对象obj调用Date类中的一个方法,toLocaleString,如何来做?

obj.toLocaleString()代码在编译阶段去编译类型Object中检查是否有该方法,若没有,编译失败.

1.对象有编译类型和运行类型

Object obj = new java.util.Date();

编译类型:Object

运行类型(其实就是obj对象真实的类型):java.util.Date

需求:根据对象obj调用Date类中的一个方法,toLocaleString,如何来做?

obj.toLocaleString()代码在编译阶段去编译类型Object中检查是否有该方法,若没有,编译失败.

解决方案1:强制转换obj为Date类型,前提:必须知道对象的真实类型是什么?

Date d = (Date)obj;

d.toLocaleString();//YES

如果我不知道obj的真实类型,那又如何去调用toLolcaeString方法. 如何去做?

解决方案2: 使用反射

对象使用类描述的,但是Java中一些皆对象,其实所有的类,底层都有一个字节码对象,用什么来描述这一个个类底层的字节码对象

解决方案 : 使用反射

dfee8849760e10e3c53323e3f1a994e5.png

反射:(reflection):在运行时期,动态地去获取类中的信息(类的信息,方法信息,构造器信息,字段等信息进行操作);

一个类中包含的信息有: 构造器,字段,方法

如何使用反射描述这些相关的信息

Class : 描述类

Method : 描述方法

Constructor :描述构造器

Field :描述字段

获取类的Class实例三种方式:

在反射操作某一个类之前,应该先获取这个类的字节码实例

获取字节码实例有三种方式

注意:同一个类在JVM的字节码实例只有一份

1. 类名.class

2. 类的对象.getClass()

3. Class.forName(“类的全限定名”)

(1)     全限定名 = 包名 + 类名

1 public classUser {2 @Test3 public void testName() throwsException {4 //1.使用类名.class 获取类的字节码实例

5 Class clz1 = User.class;6 System.out.println(clz1.toString());7

8 //2.对象.getClass()

9 User user = newUser();10 Class> clz2 =user.getClass();11 System.out.println(clz2);12

13 //3.Class.forName("全限定名"):用的最多

14 Class> clz3 = Class.forName("cn.sxt.reflect.User");15 System.out.println(clz3);16 }17 }

获取九大内置类的字节码实例:

对于对象来说,可以直接使用对象.getClass()或者Class.forName(className); 类名.class都可以获取Class实例.

但是我们的基本数据类型,就没有类的权限定名,也没有getClass方法.

问题: 那么如何使用Class类来表示基本数据类型的Class实例?

八大基本数据类型和 void关键字都是有 字节码实例的

byte,short,int,long,char,float,double,boolean ,void关键字

答 : 数据类型/void.class 即可

每个基本数据类型都是包装类型 如 :int ----Integer包装类型

注意: 基本数据类型和包装数据类型底层的字节码实例是不相同

获取8大基本数据类型和void的字节码实例:byte,short,int,long,char,float,double,boolean;   void关键字;

1 public classBaiscDataTypeClassTest {2 @Test3 public void testName() throwsException {4 //1.获取byte的字节码实例

5 Class> byteClz = byte.class;6 System.out.println(byteClz);7 //....8 //获取void关键字的字节码实例

9 Class> voidClz =void.class;10 System.out.println(voidClz);11

12

13 //所有的基本数据类型都有包装类型14 //int---Integer15 //int 和Integer 的字节码是绝对不相等的

16 Class> intClz1 = int.class;17 Class> intClz2 = Integer.class;18 System.out.println(intClz1);19 System.out.println(intClz2);20 System.out.println(intClz1 ==intClz2);21 }22 }

获取数组类型的字节码实例

表示数组的Class实例:

String[] sArr1 = {"A","C"};

Class clz = String[].class;//此时clz表示就是一个String类型的一位数组类型

所有具有相同元素类型和维数的数组才共享同一份字节码(Class对象);

注意:和数组中的元素没有一点关系.

1 packagecn.sxt.reflect._01.getclass;2

3 import static org.junit.Assert.*;4

5 importorg.junit.Test;6

7 //获取数组类型的字节码实例

8 public classArrayClassTest {9 @Test10 public void testName() throwsException {11 //定义数组

12 int[] arr = {1,2,3};13 Class clz1 = (Class) arr.getClass();14 System.out.println(clz1);15 Class clz2= int[].class;16 System.out.println(clz2);17

18

19 int[] arr2 = {2,3,4};20 Class clz3 = (Class) arr2.getClass();21 System.out.println(clz3);22

23

24 System.out.println(clz1 == clz2);//true

25 System.out.println(clz1 == clz3);//true

26 }27 }

构造函数-Constructor,获取构造函数

类的构函数有 有参数构造函数,无参构造函数,公共构造函数,非公共构造函数,根据不同的构造函数 Class提供了几种获取不同构造函数的方法;

Constructor>[]

getConstructors()

获取所有的公共构造函数

Constructor>[]

getDeclaredConstructors()

获取所有的构造函数,和访问权限无关

Constructor

getConstructor(Class>... parameterTypes)

获取指定的公共构造函数

parameterTypes: 如果构造函数有参数,传递的是参数的字节码实例

Constructor

getDeclaredConstructor(Class>... parameterTypes)

获取和访问权限无关的指定的构造函数

字节码实例:

1 public classConstructorTest {2 @Test3 public void testName() throwsException {4

5 //1.获取Student的字节码实例

6 Class> stuClz = Student.class;7

8 //2.获取所有的公共构造函数

9 Constructor>[] cts1 =stuClz.getConstructors();10 for (Constructor>ct : cts1) {11 System.out.println(ct);12 }13 System.out.println("----------------------");14 //3.获取所有的构造函数包括私有的

15 Constructor>[] cts2 =stuClz.getDeclaredConstructors();16 for (Constructor>ct : cts2) {17 System.out.println(ct);18 }19 System.out.println("----------------------");20

21 //4.获取指定的构造函数(clz.getConstructor(...))只能获取公共的构造函数

22 Constructor> ct1 =stuClz.getConstructor();23 System.out.println(ct1);24

25 Constructor> ct2 =stuClz.getConstructor(String.class);26 System.out.println(ct2);27 //4.获取指定的构造函数(clz.getDeclaredConstructor(...))获取的构造函数和权限没有关系

28 Constructor> ct3=stuClz.getDeclaredConstructor(String.class,int.class);29 System.out.println(ct3);30 }31 }

调用构造函数创建对象:

调用构造器,创建对象

Constructor类:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器

常用方法:

public T newInstance(Object... initargs):如调用带参数的构造器,只能使用该方式.

参数:initargs:表示调用构造器的实际参数

返回:返回创建的实例,T表示Class所表示类的类型

如果:一个类中的构造器可以直接访问,同时没有参数.,那么可以直接使用Class类中的newInstance方法创建对象.

public Object newInstance():相当于new 类名();

调用私有的构造器:

1.Constructor 创建对象的方法

使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

2.Class类中创建对象的方法, 如果使用Class直接创建对象,必须保证类中有一个无参数公共构造函数

创建此 Class 对象所表示的类的一个新实例。

3.设置忽略访问权限

f3a77e872195b07b5ff43819027236c2.png

如果是私有构造方法,反射默认是无法直接执行的,找到父类中AccessibleObject的方法,设置为true,即可忽略访问权限

abb15ec134a988c85646da8e27e54940.png

void

(boolean flag)

如果执行私有方法,设置忽略访问权限 为 true即可

使用构造器创建对象

1 public classNewInstanceTest {2 @Test3 public void testName() throwsException {4

5 //1.获取Student的字节码实例

6 Class> clz = Class.forName("cn.sxt.reflect.Student");7

8 //1.1如果类有无参数公共构造函数,直接可以使用类的字节码实例就创建对象

9 Student stu0 =(Student) clz.newInstance();10

11

12 //2.获取一个参数的构造函数

13 Constructor ct1 = (Constructor) clz.getConstructor(String.class);14 //2.1.创建对象

15 Student stu1 = ct1.newInstance("东方不败");16

17 //3.获取私有构造函数并创建对象

18 Constructor ct2 = (Constructor) clz.getDeclaredConstructor(String.class,int.class);19 //3.1设置权限可以创建对象

20 ct2.setAccessible(true);21 //3.2创建对象

22 Student stu2 = ct2.newInstance("西门吹雪",50);23 }24 }

操作方法-Method

一个类创建对象以后,一般就要执行对象的方法等等,使用反射操作对象

首先要获取方法,再去执行;

获取方法和方法的执行

一个类中的方法有很多,无参,有参,静态,可变参数私有方法,等等,针对不同的方法处理,提供了不同的获取方案

使用Class 获取对应的方法

()

获取所有的公共方法,包括父类的公共方法

(String name,

Class>... parameterTypes)

获取指定方法名称的方法,和访问权限无关

Name: 指定的方法名称

parameterTypes: 方法参数的类型

Method执行方法

方法获取以后就需要执行。Method对象中提供方法执行的功能

执行方法

Obj :如果是对象方法,传指定的对象,如果是类方法,传 null

Args: 方法的参数

如果方法有返回结果,可以接收

设置忽略访问权限,同上

6f257def6eea6b8b99304233551fb7ac.png

void

(boolean flag)

如果执行私有方法,设置忽略访问权限 为 true即可

方法操作的代码:

Student类:

1 packagecn.sxt.reflect._03method;2

3 importjava.util.Arrays;4

5 public classPerson {6

7 public voidhell1() {8 System.out.println("我是无参数无返回值方法");9 }10

11 publicString hello2(String name) {12

13 return "你好 :"+name;14 }15

16 private String hello3(String name,intage) {17 return "我是 :"+name+",今年 :"+age;18 }19

20

21

22 public static voidstaticMethod(String name) {23 System.out.println("我是静态方法 :"+name);24 }25

26

27

28 public static void method1(int[] intArr) {29 System.out.println(Arrays.toString(intArr));30 }31

32 public static voidmethod2(String[] strArr) {33 System.out.println(Arrays.toString(strArr));34 }35

36 }

测试类:

1 packagecn.sxt.reflect._03method;2

3 import static org.junit.Assert.*;4

5 importjava.lang.reflect.Method;6

7 importorg.junit.Test;8

9 //获取Person类的方法

10 public classGetMethodTest {11

12 @Test13 public void testName() throwsException {14 //1.获取Person字节码实例

15 Class clz = Person.class;16 //2.创建对象

17 Person p =clz.newInstance();18

19 //3.获取方法(使用反射),获取所有公共方法,包含父类的公共方法

20 Method[] methods1 =clz.getMethods();21 for(Method method : methods1) {22 System.out.println(method);23 }24 System.out.println("------------------------------");25 //4.获取自己类中的所有方法(包括私有)

26 Method[] methods2 =clz.getDeclaredMethods();27 for(Method method : methods2) {28 System.out.println(method);29 }30 System.out.println("------------------------------");31 //4.获取单个指定名称的方法

32 Method method = clz.getMethod("hello2", String.class);33 System.out.println(method);34

35 //4.1执行方法

36 Object res = method.invoke(p, "陆小凤");37 System.out.println(res);38

39 //5.获取私有的方法

40 Method hello3 = clz.getDeclaredMethod("hello3", String.class, int.class);41 System.out.println(hello3);42

43 //5.1设置忽略访问权限

44 hello3.setAccessible(true);45

46 Object res1 = hello3.invoke(p, "叶孤城", 30);47 System.out.println(res1);48

49 //6.获取静态方法

50 Method staticMethod = clz.getMethod("staticMethod", String.class);51

52 //6.1执行静态方法

53 staticMethod.invoke(null, "花满楼");54

55 //7.获取有整数数组参数的方法

56 Method method1 = clz.getMethod("method1", int[].class);57 method1.invoke(null, new Object[] {new int[] { 1, 2, 3, 4}});58

59 //8.获取有整数数组参数的方法

60 /*

61 * 如果反射传递的参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来62 * 解决方案: 将数组外面在包装一层数组,如果拆箱一次,得到还是一个数组63 */

64 Method method2 = clz.getMethod("method2", String[].class);65 method2.invoke(null,new Object[] {new String[] {"AA","BB","CC"}});66 }67 }

可变参数的方法执行

如果方法中有可变参数(数组),如果反射传递的可变参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来

解决方案: 将数组外面在包装一层数组,如果拆箱一次,得到还是一个数组

1 packagecn.sxt.reflect._03method;2

3 importjava.util.Arrays;4

5 public classPerson {6

7 public static void method1(int... intArr) {8 System.out.println(Arrays.toString(intArr));9 }10

11 public static voidmethod2(String...strArr) {12 System.out.println(Arrays.toString(strArr));13 }14 }15

16 //7.获取有整数数组参数的方法

17 Method method1 = clz.getMethod("method1", int[].class);18 method1.invoke(null, new Object[] {new int[] { 1, 2, 3, 4}});19

20 //8.获取有整数数组参数的方法

21 /*

22 * 如果反射传递的参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来23 * 解决方案: 将数组外面在包装一层数组,如果拆箱一次,得到还是一个数组24 */

25 Method method2 = clz.getMethod("method2", String[].class);26 method2.invoke(null,new Object[] {new String[] {"AA","BB","CC"}});

操作字段(成员变量)-Field

类中的字段有各种数据类型和各种访问权限,针对这些情况,反射操作有对应的方法来获取和处理

Class中获取字段方法

获取当前Class所表示类中所有的public的字段,包括继承的字段.

获取当前Class所表示类中所有的字段,不包括继承的字段.

获取当前Class所表示类中

:获取当前Class所表示类中该fieldName名字的字段,不包括继承的字段.

Field操作设置值/获取值

给某个类中的字段设置值和获取值:

1,找到被操作字段所在类的字节码

2,获取到该被操作的字段对象

3,设置值/获取值

Field类常用方法:

void setXX(Object obj, XX value) :为基本类型字段设置值,XX表示基本数据类型

void set(Object obj, Object value) :表示为引用类型字段设置值

参数:

obj:    表示字段底层所属对象,若该字段是static的,该值应该设为null

value:  表示将要设置的值

-------------------------------------------------------------------------------------

XX getXX(Object obj) :获取基本类型字段的值,XX表示基本数据类型

Object get(Object obj) :表示获取引用类型字段的值

参数:

obj:    表示字段底层所属对象,若该字段是static的,该值应该设为null

返回:返回该字段的值.

void

设置引用类型的值,非基本数据类型

Obj: 要设置值得对象

Value : 要设置的值

1 packagecn.sxt.reflect._04Field;2

3 import static org.junit.Assert.*;4

5 importjava.lang.reflect.Field;6

7 importorg.junit.Test;8

9 public classFieldTest {10

11 @Test12 public void testName() throwsException {13 //1.获取People字节码

14 Class clz = People.class;15

16 People p =clz.newInstance();17

18 //2.获取所有公共字段

19 Field[] fields1 =clz.getFields();20 for(Field field : fields1) {21 System.out.println(field);22 }23 System.out.println("---------------------");24 //3.获取所有字段,和访问权限无关

25 Field[] fields2 =clz.getDeclaredFields();26 for(Field field : fields2) {27 System.out.println(field);28 }29 System.out.println("---------------------");30 //3.获取指定的公共字段

31 Field emialField = clz.getField("emial");32 System.out.println(emialField);33

34 //为字段设置值

35 emialField.set(p, "zhagnsan@qq.com");36 System.out.println(p);37 //4.获取指定所有的字段,和访问权限无关

38 Field nameFiled = clz.getDeclaredField("name");39 System.out.println(nameFiled);40 //设置忽略访问权限

41 nameFiled.setAccessible(true);42 nameFiled.set(p, "张三");43 System.out.println(p);44

45

46 //5 获取age字段

47 Field ageFile = clz.getDeclaredField("age");48 ageFile.setAccessible(true);49 //设置忽略访问权限

50 ageFile.setInt(p, 18);51 System.out.println(p);52

53 }54 }

Class的其他API方法

1 @Test2 public void testName() throwsException {3

4 //1.获取UserDaoImpl的字节码实例

5 Class> clz = Class.forName("cn.sxt.reflect._05otherapi.UserDaoImpl");6

7 //2.获取所有的接口

8 Class>[] interfaces =clz.getInterfaces();9 for (Class>intface : interfaces) {10 System.out.println(intface);11 }12

13 //3.获取全限定名

14 System.out.println(clz.getName());15

16 //4.获取简单类名

17 System.out.println(clz.getSimpleName());18 //5.获取包

19 System.out.println(clz.getPackage().getName());20 }

JavaBean, JavaBean就是一个个Java类,在java中符合JavaBean特点类才叫做JavaBean

JavaBean的三个特点:

1.JavaBean类的修饰符必须是public,也就是一个JavaBean必须是一个对应一个类文件

2.JavaBean必须有无参数公共构造方法(以便于反射直接通过直接通过字节码实例创建对象)

3.JavaBean中的成员变量/字段必须有get/set方法提供对应的属性

JavaBean中的属性:

Java类有成员变量,成员变量绝对不是属性,JavaBean中的属性是有get/set方法确定的

1.1Get方法确定属性

publicString getName() {returnname;

}

属性确定规则 : get方法去掉 get前缀 ,剩余部分 首字母小写

属性名称 : name

1.2Set方法确定属性

public voidsetName(String name) {this.name =name;

}

属性确定规则 : set方法去掉 set前缀 ,剩余部分 首字母小写

属性名称 : name

如果一个成员变量get/set方法都有确定的属性就只有一个

问题 :get/set方法确定确定的属性一般不就和成员变量一样啊,为什么要有属性了

答: 一般情况下,Eclipse工具有自动生成get/set方法的功能,确定的JavaBean的属性只是恰好和成员变量相同,但是成员变量不是属性

如下特殊性情况,属性和成员变量名称不同;

//Filed

privateString firstName;//Filed

privateString lastName;//属性 : fullName

publicString getFullName() {return this.firstName + this.lastName;

}

总结:

1. 理解反射概念?反射能干啥?

(1)     反射: 在jvm运行阶段,动态的获取类的信息(字节码实例,构造器,方法,字段),动态进行对象的创建,方法执行,字段操作。

2. 反射的常用类

(1)     Class :所有类的字节码实例的描述

(2)     Constructor :构造器

(3)     Method :方法

(4)     Field :字段

3. JDBC+反射 代码封装

(1)     通用 crud 方法

思路清晰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值