观看尚硅谷视频做的视频笔记

一、高级-反射与动态代理(十四)

1、反射概述

1)java程序中,所有的对象都有两种类型:编译时类型,运行时类型,而很多时候对象的编译类型和运行时类型不一致。

此处就是多态性体现。

Object obj=new String(“hello”);

2)例如:某些变量或形参的声明类型是Object类型,但是程序却需要调用该对象运行时类new String(“hello”);的方法compareTo方法,该方法不是Object中的方法,那么如何解决?

方案1:多态中有用到,向下转型。在编译和运行是都完全知道类型的具体的信息,在这种情况下,我们可以直接先使用instanceof运算符进行判断是否为String类型,若是就利用强制类型转换符将其转成运行时类的变量即可,强制转换后就可以用String里面的方法。缺点:①若用这种方法会写很多instanceof这种判断。②此判断是否全,是否满足需求。此时写好了代码,形参是Object类型。判断obj是否为A类型,是就进行强转,调方法,B类型,C类型,目前只是ABC三个对象。后续可能DEF,也有可能作为参数传进来,就需要进行修改,有没有更好的方案解决此问题,自然而然就考虑方案2.

JAVA高级-反射与动态代理(十五)插图

方案2:编译时根本无法预知该对象和类的真实信息,程序只能依靠运行时obj已经在内存中,信息来发现该对象和类的真实信息,这就必须使用反射。(程序运行过程中,动态获取所属类的类型obj.getClass,obj对象是哪个类造的,动态获取,及时把类转换成声明,动态的转换,再去调特有的方法就需要用到反射)

obj.getClass在Object中声明
框架中用的比较多。

3)反射是被是视为动态语言的关键,反射机制允许程序在运行期间借助于RelectionAPI取得任何类得内部信息,并能直接操作任意对象得内部属性及方法。(跟对象里面方法属性的权限都无关)

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象。(一个类只有一个Class对象),这个对象就包含了完整的类的结构的信息。我们可以i通过这个对象看到类的结构,这个对象就像一面镜子,通过这个镜子看到类的结构,所以我们形象的称为反射。

4)代码示例(利用面向对象做的操作 、 使用反射完成调属性方法操作、使用反射完成调私有属性方法操作)

package com.zhou.java;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionTest {
/* 利用反射之前做的操作 */
@Test
public void test1() {
//1.创建Person类的实例
//   public person()
Person p1 = new Person();
//2.调用属性、方法
p1.age = 10;
System.out.println(p1.age);
//3.调用方法
//public void show(){}
p1.show();
}
//使用反射完成上诉操作
@Test
public void test2() throws Exception {
//
//1.创建类的实例
//person.class就作为Class的实例出现
Class<Person> clazz = Person.class;
Person p1 = clazz.newInstance();//jdk9之后不建议用
System.out.println(p1);
//2.调属性、先获取当前类当中叫age名的属性。
Field agefield = clazz.getField("age");
agefield.set(p1, 10);
System.out.println(agefield.get(p1));
//3.调方法,先获取当前类当中叫show的方法。
Method showmethod = clazz.getMethod("show");
showmethod.invoke(p1);
}
//反射做其他事儿
@Test
public void test3() throws Exception {
//1.调用私有的构造器,创建Person实例
//   private(String name,int age){}
Class clazz1 = Person.class;
Constructor cons = clazz1.getDeclaredConstructor(String.class, int.class);//不用填写构造器名称,只需要告诉参数就行,需要传的是String参数和int参数,构造器有了,就需要造对象  
cons.setAccessible(true);
Person p1 = (Person) cons.newInstance("Tom", 20);
System.out.println(p1);
//2.调用私有的属性
Field namefield = clazz1.getDeclaredField("name");
namefield.setAccessible(true);
namefield.set(p1, "Jerry");
System.out.println(p1);
//2.调用私有的方法
//private String showNation(){}
Method showNation = clazz1.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String info = (String) showNation.invoke(p1, "CHN");
System.out.println(info);
}
}

5)通过使用反射前后的的例子的对比

①面向对象中创建对象,请用指定结构(属性、方法)等功能,可以不使用反射,也可以使用反射,请问有什么区别?

运行时类,运行的代码中,person类就会加载到内存中,放到内存中的类就称为运行时类。

不使用反射:我们需要考虑封装性,比如,出了Person类之后,就不能再调用Person类中的私有结构。使用反射:我们可以调用运行时类中任意的构造器、属性、方法。包括了私有的属性、方法、构造器。

②以前创建对象并调用方法的方式,与现在通过反射创建对象并调用方法的方式对比的话,哪种用的多?

从我们程序员来讲,我们开发中主要是完成义务代码。对于相关的对象,方法的调用都是确定,所以我们使用非反射的方式多一些。

因为反射体现了多态性(可以再运行时动态的获取对象所属的类,动态的调用相关的方法),所以我们在设计框架的时候,会大量的使用反射。

框架=注解+反射(获取相关注解)+设计模式

③单例模式的饿汉式和懒汉式,私有化的构造器,此时通过反射,可以创建单列模式的多个对象吗?

是的,单列模式的饿汉式和懒汉式,构造器都被私有。在类的内部造对象,外部直接用就可以。通过反射可以调构造器。

④.通过反射,可以调用类中私有结构,是否与面对对象的封装有冲突》是不是java语言设计存在bug?

不存在bug

封装性:体现的是否会建议我们调用内部api的问题,比如,private声明的结构,意味着不建议调用。

反射:体现的是我们能否调用的问题,因为类的完整结构都加载到了内存中,我们就有能力进行调用。

反射理解:是假设内存中有一个内存对象,通过这个对象,可以看成是哪个类创建的,通过类可以看到是在哪个包中声明的。

6)java反射机制提供的功能

在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时

JAVA高级-反射与动态代理(十五)插图(1)

JAVA高级-反射与动态代理(十五)插图(2)

JAVA高级-反射与动态代理(十五)插图(3)

2.Class类的理解

JAVA高级-反射与动态代理(十五)插图(4)
JAVA高级-反射与动态代理(十五)插图(5)

1)如下以Java类的加载为例说明

编译:针对于编写好的.java源文件进行编译(使用Javac.exe),会生成一个或多个.class字节码文件。
接着,我们使用Java.exe命令对指定的.class字节码文件进行解释运行。这个解释运行的过程中,我们需要将.class字节码文件加载到(使用类的构造器)内存中(方法区),加载到内存的class文件对应的结构即为Class的一个实例

比如:加载到内存中的Person类或String类或User类,都作为Class的一个一个的实例
接口加载到内存中也是对应得一个Class实例

Class clazz1=Person.class;
Class clazz2=String.class;
Class clazz3=User.class;
Class clazz4=Compareable.class;

3.获取Class实例的几种方式(掌握前三种)

import com.zhou.java.Person;
import org.junit.Test;
public class ClassTest {
//1.调用运行时类的静态属性
@Test
public void test1() throws Exception {
Class clazz1 = Person.class;
System.out.println(clazz1);
//2.调用运行时类的对象的getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz1 = clazz2);//true
//3.调用Class的静态方法forName(String className)
String className = "com.zhou.java.Person";//全类名
Class clazz = Class.forName(className);
//4.
Class systemClassLoader = ClassLoader.getSystemClassLoader().loadClass("com.zhou.java.Person");
}
}

4.class看作是反射源头

5.Class的实列都可以指向哪些结构呢?

class:外部类,成员(成员内部类,静态内部类)、局部内部类、匿名内部类
interface:接口
[]:数组
enum:枚举
annotation:注解
基本数据类型
void

JAVA高级-反射与动态代理(十五)插图(6)

6.类的加载过程(详细在jvm中有)

JAVA高级-反射与动态代理(十五)插图(7)

6.1过程1:loading(装载)

将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由加载器完成

6.2过程2linking(连接)

验证、准备、解析
验证(Verify):确保加载的类信息符合JVM规范,例如:以cafebabe开头,没有安全方面的问题。
准备prepare):正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。

解析(Resolve):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
JAVA高级-反射与动态代理(十五)插图(8)

6.3过程3Initialization(初始化)

JAVA高级-反射与动态代理(十五)插图(9)

6.4关于类的加载器(了解,JDK8版本为例)

1)作用:负责类的加载,并对应一个Class的实例

虽叫类的加载器,不仅能加载类,还能加载接口、没接、注解等
负责将字节码文件放到内存中
JAVA高级-反射与动态代理(十五)插图(10)

2) 分类(分为两种)

JAVA高级-反射与动态代理(十五)插图(11)
似乎是继承关系,其实不是继承关系,而是层级关系
JAVA高级-反射与动态代理(十五)插图(12)
JAVA高级-反射与动态代理(十五)插图(13)

①BootStrapClassLoader:引导加载器、启动加载器

使用C、c++语言编写的,不能通过java代码获取实例
负载加载java的核心库。(Java_Home/jar/lib/rt.jar)
java代码获取实例,获取的时候返回为null

②继承于ClassLoader的类加载器

扩展类加载器(jdk提供的)
系统类加载器、应用程序类加载器(jdk提供的)自定义的类默认使用的类的加载器
用户自定义类的加载器(Tomcat中也定义了一些类加载器)

JAVA高级-反射与动态代理(十五)插图(14)
JAVA高级-反射与动态代理(十五)插图(15)

③代码演示
获取系统类加载器

JAVA高级-反射与动态代理(十五)插图(16)

获取扩展加载器(获取上一层加载器)

JAVA高级-反射与动态代理(十五)插图(17)

JAVA高级-反射与动态代理(十五)插图(18)

获取引导类加载器失败,获取不到。返回值为null

JAVA高级-反射与动态代理(十五)插图(19)

用户自定义的类是系统类加载加载的
方式一

JAVA高级-反射与动态代理(十五)插图(20)

方式二

JAVA高级-反射与动态代理(十五)插图(21)
JAVA高级-反射与动态代理(十五)插图(22)

3)以上的类的加载器是否存在继承关系

4)掌握使用类的加载器获取流,并读取配置文件信息。

方案一:

propertites处理属性文件
读取配置文件时:
使用单元测试方法,默认就是使用的是当前module下面
JAVA高级-反射与动态代理(十五)插图(23)
通过propertites读取流当中文件的数据
JAVA高级-反射与动态代理(十五)插图(24)

处理的key和值都是String类型
JAVA高级-反射与动态代理(十五)插图(25)
JAVA高级-反射与动态代理(十五)插图(26)

以后会实现数据和代码的分离
数据会放在具体的配置文件中

使用Classloader也可以做这样的事儿
拿到系统加载器
JAVA高级-反射与动态代理(十五)插图(27)
作为流拿到一个资源
JAVA高级-反射与动态代理(十五)插图(28)
JAVA高级-反射与动态代理(十五)插图(29)

JAVA高级-反射与动态代理(十五)插图(30)

方案二:

7.反射的应用

7.1反射的应用1:创建运行时类的对象

1)如何实现:通过Class的实例调用newInstance()方法即可
2)要想创建对象成功,需要满足
①条件1:要求运行是类必须满足一个空参的构造器。
②条件2:要求提供的空参构造器的权限要足够。

Person类实现了两个接口

JAVA高级-反射与动态代理(十五)插图(31)

JAVA高级-反射与动态代理(十五)插图(32)

JAVA高级-反射与动态代理(十五)插图(33)

JAVA高级-反射与动态代理(十五)插图(34)

JAVA高级-反射与动态代理(十五)插图(35)

![在这里插入图片描述](http://img-blog.csdnimg.cn/235dae5963cd448a9876eaaff8a30cd7

JAVA高级-反射与动态代理(十五)插图(36)
.png)

创建Person对象此处的创建运行时类对象指的是Person类
JAVA高级-反射与动态代理(十五)插图(37)
当把Person类加载到内存中时
使用Java.exe指令时,走类的加载过程:loading,linking、initilion环节,在方法区就会有一个大的实例。就称为运行时类。

首先有一个大的Class实例,获取实例。
JAVA高级-反射与动态代理(十五)插图(38)

JAVA高级-反射与动态代理(十五)插图(39)

per调的是toString方法
JAVA高级-反射与动态代理(十五)插图(40)

若Person类里没有空参构造器,则抛异常JAVA高级-反射与动态代理(十五)插图(41)
JAVA高级-反射与动态代理(十五)插图(42)

JAVA高级-反射与动态代理(十五)插图(43)

还有一种异常是有构造器但不能用私有权限
JAVA高级-反射与动态代理(十五)插图(44)

JAVA高级-反射与动态代理(十五)插图(45)
默认权限,同包别的类能用
JAVA高级-反射与动态代理(十五)插图(46)

JAVA高级-反射与动态代理(十五)插图(47)

JAVA高级-反射与动态代理(十五)插图(48)

3)回忆:javabean中要求当前类:一个空参构造器,有什么用?
①场景1:子类对象在实例化时,子类的构造器的首行默认调用父类的空参的构造器默认有super()
②场景2:在反射中,经常用来创建运行时类的对象,那么我们要求各个运行时类都提供一个空参构造器,便于我们创建运行时类对象的代码。

JAVA高级-反射与动态代理(十五)插图(49)

Javabean的要求,当前类是公共的,提供当前类的空参构造器,有属性提供get、set方法、有toString方法、重写equals、hashcode方法,是为了防止将对象放在集合中、toString方法(打印对象变量时,打印地址、打印属性的值)

为啥要有这个提供空参构造器这个要求?

JAVA高级-反射与动态代理(十五)插图(50)
JAVA高级-反射与动态代理(十五)插图(51)

JAVA高级-反射与动态代理(十五)插图(52)

JAVA高级-反射与动态代理(十五)插图(53)

package com.zhou.java;
public class Creature<T> {
boolean gender;
public int id;
public void breath(){
System.out.println("呼吸");
}
private void info(){
System.out.println("我是一个生物");
}
}
package com.zhou.java;
public interface myInterface {
void method();
}
package com.zhou.java;
import org.junit.Test;
public class NewInstanceTest {
@Test
public void test() throws InstantiationException, IllegalAccessException {
Class clazz = Person.class;
//获取Person类的实例
Person per = (Person) clazz.newInstance();
System.out.println(per);//调的是toString()方法
}
}
package com.zhou.java;
public class Person extends Creature<String> implements Comparable, myInterface {
private String name;
public int age = 1;
private static String info;
private Person(String name, int age) {
this.name = name;
this.age = age;
}
protected Person(int age) {
this.age = age;
}
protected Person(String name) {
this.name = name;
}
Person() {
System.out.println("person()========");
}
public void show() {
System.out.println("您好我是一个Person");
}
private String showNation(String nation, int age) {
System.out.println("shownation");
return "我的国籍是:" + nation + ",生活了" + age + "年";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void showInfo() {
System.out.println("我是一个人");
}
@Override
public void method() {
}
@Override
public int compareTo(Object o) {
return 0;
}
}
4)在jdk标识为过时,替换成什么结构

通过Constructor类调用newInstance()

7.2反射的应用2:获取运行时类所有的结构

1)获取运行时类的内部结构1:所有属性、所有方法、所有构造器
2)获取运行时类的内部结构1:父类、接口们、包、贷泛型的父亲、父亲的泛型

JAVA高级-反射与动态代理(十五)插图(54)
JAVA高级-反射与动态代理(十五)插图(55)

package com.atguigu03.reflectapply.apply2;
import com.atguigu03.reflectapply.data.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @author shkstart
* @create 14:28
*/
public class FieldsTest {
@Test
public void test1() {
Class clazz = Person.class;
//getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
Field[] fields = clazz.getFields();
for (Field f : fields) {
System.out.println(f);
}
//getDeclaredFields():获取当前运行时类中声明的所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
}
//权限修饰符  变量类型  变量名
@Test
public void test2() {
Class clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
//1.权限修饰符
/*
* 0x是十六进制
* PUBLIC           = 0x00000001;  1    1
* PRIVATE          = 0x00000002;  2	10
* PROTECTED        = 0x00000004;  4	100
* STATIC           = 0x00000008;  8	1000
* FINAL            = 0x00000010;  16	10000
* ...
*
* 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
*
* mod = 17          0x00000011
* if ((mod & PUBLIC) != 0)  说明修饰符中有public
* if ((mod & FINAL) != 0)   说明修饰符中有final
*/
int modifier = f.getModifiers();
System.out.print(modifier + ":" + Modifier.toString(modifier) + "	");
//            //2.数据类型
Class type = f.getType();
System.out.print(type.getName() + "	");
//
//            //3.变量名
String fName = f.getName();
System.out.print(fName);
//
System.out.println();
}
}
}

JAVA高级-反射与动态代理(十五)插图(56)

JAVA高级-反射与动态代理(十五)插图(57)

JAVA高级-反射与动态代理(十五)插图(58)
得到的都是Person类声明的,父类的没有

JAVA高级-反射与动态代理(十五)插图(59)
JAVA高级-反射与动态代理(十五)插图(60)
获取每一个具体的信息
JAVA高级-反射与动态代理(十五)插图(61)
f.getModifiers()获取修饰符
JAVA高级-反射与动态代理(十五)插图(62)
类调里面的toString方法,可以看到权限修饰符
JAVA高级-反射与动态代理(十五)插图(63)
怎么做的?因为modifer这个数在Modifer这个类中有对应的十六进制对应关系
JAVA高级-反射与动态代理(十五)插图(64)
JAVA高级-反射与动态代理(十五)插图(65)
JAVA高级-反射与动态代理(十五)插图(66)

JAVA高级-反射与动态代理(十五)插图(67)

JAVA高级-反射与动态代理(十五)插图(68)
JAVA高级-反射与动态代理(十五)插图(69)

JAVA高级-反射与动态代理(十五)插图(70)
JAVA高级-反射与动态代理(十五)插图(71)

JAVA高级-反射与动态代理(十五)插图(72)

获取方法
JAVA高级-反射与动态代理(十五)插图(73)

JAVA高级-反射与动态代理(十五)插图(74)

JAVA高级-反射与动态代理(十五)插图(75)

JAVA高级-反射与动态代理(十五)插图(76)

都是当前类中有的
JAVA高级-反射与动态代理(十五)插图(77)

package apply2;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Method;
public class MethodTest {
@Test
public void test1() {
Class clazz = Person.class;
/*  //getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for (Method m:methods) {
System.out.println(m);
}*/
//getDeclareMethods():获取当前运行时类中声明的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
}
}
package apply2;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FieldsTest {
//权限修饰符、变量类型、变量名
@Test
public void test2() {
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
//1.权限修饰符
int modifier = f.getModifiers();
System.out.print(modifier + ":" + Modifier.toString(modifier) + "	");
//2.数据类型
Class type = f.getType();
System.out.println(type.getName() + "	");
//3.变量名
String sname = f.getName();
System.out.println(sname);
System.out.println();
}
}
@Test
public void test1() {
Class clazz = Person.class;
//getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
/*Field[] fields = clazz.getFields();
for (Field c:fields) {
System.out.println(c);
}*/
//getDeclareFields():获取当前运行时类中声明的所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
}
}

JAVA高级-反射与动态代理(十五)插图(78)
person里使用了注解
JAVA高级-反射与动态代理(十五)插图(79)
自定义注解,要想在反射中获取注解及注解的信息,需要求注解的生命周期长

JAVA高级-反射与动态代理(十五)插图(80)
JAVA高级-反射与动态代理(十五)插图(81)

JAVA高级-反射与动态代理(十五)插图(82)
JAVA高级-反射与动态代理(十五)插图(83)

JAVA高级-反射与动态代理(十五)插图(84)
JAVA高级-反射与动态代理(十五)插图(85)
JAVA高级-反射与动态代理(十五)插图(86)

JAVA高级-反射与动态代理(十五)插图(87)

JAVA高级-反射与动态代理(十五)插图(88)

JAVA高级-反射与动态代理(十五)插图(89)

JAVA高级-反射与动态代理(十五)插图(90)

JAVA高级-反射与动态代理(十五)插图(91)

JAVA高级-反射与动态代理(十五)插图(92)

JAVA高级-反射与动态代理(十五)插图(93)

JAVA高级-反射与动态代理(十五)插图(94)
JAVA高级-反射与动态代理(十五)插图(95)

JAVA高级-反射与动态代理(十五)插图(96)
首先有大的实例,指明全类名
JAVA高级-反射与动态代理(十五)插图(97)
JAVA高级-反射与动态代理(十五)插图(98)

JAVA高级-反射与动态代理(十五)插图(99)

JAVA高级-反射与动态代理(十五)插图(100)

JAVA高级-反射与动态代理(十五)插图(101)
person继承时带泛型
JAVA高级-反射与动态代理(十五)插图(102)
希望结果里带上泛型
JAVA高级-反射与动态代理(十五)插图(103)

JAVA高级-反射与动态代理(十五)插图(104)
JAVA高级-反射与动态代理(十五)插图(105)
JAVA高级-反射与动态代理(十五)插图(106)
一个类可以实现多个接口,所以就是数组
JAVA高级-反射与动态代理(十五)插图(107)

JAVA高级-反射与动态代理(十五)插图(108)

JAVA高级-反射与动态代理(十五)插图(109)

JAVA高级-反射与动态代理(十五)插图(110)

JAVA高级-反射与动态代理(十五)插图(111)

JAVA高级-反射与动态代理(十五)插图(112)

JAVA高级-反射与动态代理(十五)插图(113)
JAVA高级-反射与动态代理(十五)插图(114)

什么时候用到,泛型写apply时
自定义泛型时,写dao时,dao通用的增删改查操作
操作的哪个表暂时不确定,回到Java层面哪个类不确定?

有可能需要当前类中继承的方法,有一些需要重写,有一些需要继承父类调用的方法,在这里需要获取这里这个类继承的父类的泛型
JAVA高级-反射与动态代理(十五)插图(115)
获取某一个对象,就不用传大的Class

获取Person类的实例,希望打印出String
先获取带泛型的父类
JAVA高级-反射与动态代理(十五)插图(116)

JAVA高级-反射与动态代理(十五)插图(117)
也有可能这个类,父类没有泛型,
也有可能有泛型,若有泛型就进行强转。

JAVA高级-反射与动态代理(十五)插图(118)
数组就是泛型参数构成的
JAVA高级-反射与动态代理(十五)插图(119)
角标0就是想要的String
JAVA高级-反射与动态代理(十五)插图(120)

JAVA高级-反射与动态代理(十五)插图(121)
不想要class,就获取class名字
调getname()调不了
是因为目前看到的是Type
JAVA高级-反射与动态代理(十五)插图(122)

Type是Class实现的接口
强转成Class
JAVA高级-反射与动态代理(十五)插图(123)
然后再进行Class.getName
JAVA高级-反射与动态代理(十五)插图(124)

JAVA高级-反射与动态代理(十五)插图(125)

JAVA高级-反射与动态代理(十五)插图(126)
JAVA高级-反射与动态代理(十五)插图(127)

JAVA高级-反射与动态代理(十五)插图(128)

JAVA高级-反射与动态代理(十五)插图(129)

package apply2;
import org.junit.Test;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class OtherTest {
//获取运行时类的内部结构2:父类、接口们、包、带泛型的父类、父类的泛型等
//5.获取运行时类的父类的泛型(难)
@Test
public void test5() throws ClassNotFoundException {
Class clazz = Class.forName("com.zhou.java.Person");
//获取带泛型的父类(Type是一个接口,Class实现了此接口)
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
//如果父类是带泛型的,进行强转为ParameterizedType
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
//调用getActualTypeArguments()获取泛型的参数,结果是一个数组,因为可能有多个泛型参数。
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//获取泛型参数的名称
System.out.println(((Class) actualTypeArguments[0]).getName());
}
//4.获取运行时类所在的包
@Test
public void test4() throws ClassNotFoundException {
Class clazz = Class.forName("com.zhou.java.Person");
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
}
//3.获取运行时类实现的接口
@Test
public void test3() throws ClassNotFoundException {
Class clazz = Class.forName("com.zhou.java.Person");
Class[] interfaces = clazz.getInterfaces();
for (Class i : interfaces) {
System.out.println(i);
}
}
//1.获取运行时类的父类
@Test
public void test1() throws ClassNotFoundException {
Class clazz = Class.forName("com.zhou.java.Person");
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
}
//2.获取运行时类的带泛型的父类
@Test
public void test2() throws ClassNotFoundException {
Class clazz = Class.forName("com.zhou.java.Person");
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
}
package apply2;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Method;
public class MethodTest {
@Test
public void test1() {
Class clazz = Person.class;
/*  //getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for (Method m:methods) {
System.out.println(m);
}*/
//getDeclareMethods():获取当前运行时类中声明的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
}
}
package apply2;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FieldsTest {
//权限修饰符、变量类型、变量名
@Test
public void test2() {
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
//1.权限修饰符
int modifier = f.getModifiers();
System.out.print(modifier + ":" + Modifier.toString(modifier) + "	");
//2.数据类型
Class type = f.getType();
System.out.println(type.getName() + "	");
//3.变量名
String sname = f.getName();
System.out.println(sname);
System.out.println();
}
}
@Test
public void test1() {
Class clazz = Person.class;
//getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
/*Field[] fields = clazz.getFields();
for (Field c:fields) {
System.out.println(c);
}*/
//getDeclareFields():获取当前运行时类中声明的所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
}
}

7.3反射的应用3:调用指定的结构、指定的属性、方法、构造器

JAVA高级-反射与动态代理(十五)插图(130)

JAVA高级-反射与动态代理(十五)插图(131)
还是针对Person类

JAVA高级-反射与动态代理(十五)插图(132)
age非静态,获取它的值,跟对象打交道
创建当前类的对象
JAVA高级-反射与动态代理(十五)插图(133)
创建Person类的实例

JAVA高级-反射与动态代理(十五)插图(134)

JAVA高级-反射与动态代理(十五)插图(135)
JAVA高级-反射与动态代理(十五)插图(136)

获取当前类中名字叫age属性,File是java.lang包下的子类
JAVA高级-反射与动态代理(十五)插图(137)
JAVA高级-反射与动态代理(十五)插图(138)

这个属性是实例变量,得跟对象打交道
得说明是哪一个对象的值,是per对象的
JAVA高级-反射与动态代理(十五)插图(139)
JAVA高级-反射与动态代理(十五)插图(140)

JAVA高级-反射与动态代理(十五)插图(141)

因为此处是默认权限
JAVA高级-反射与动态代理(十五)插图(142)
改成public
JAVA高级-反射与动态代理(十五)插图(143)
JAVA高级-反射与动态代理(十五)插图(144)
设置属性的值
JAVA高级-反射与动态代理(十五)插图(145)

JAVA高级-反射与动态代理(十五)插图(146)

package apply3;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Field;
public class ReflectTest {
//反射的应用:调用指定的属性
// public int age = 1;
@Test
public void test() throws Exception {
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
//1.获取运行时类指定名的属性
Field agefield = clazz.getField("age");
System.out.println(agefield.get(person));
//2.获取或设置属性的值
agefield.set(person, 2);
System.out.println(agefield.get(person));
}
}

操作私有权限的属性
按age代码重先更改为name
JAVA高级-反射与动态代理(十五)插图(147)

JAVA高级-反射与动态代理(十五)插图(148)

JAVA高级-反射与动态代理(十五)插图(149)

JAVA高级-反射与动态代理(十五)插图(150)

JAVA高级-反射与动态代理(十五)插图(151)

JAVA高级-反射与动态代理(十五)插图(152)
JAVA高级-反射与动态代理(十五)插图(153)

JAVA高级-反射与动态代理(十五)插图(154)
JAVA高级-反射与动态代理(十五)插图(155)

package apply3;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Field;
public class ReflectTest {
//private String name;
@Test
public void test2() throws  Exception{
Class clazz = Person.class;
Person person = (Person)clazz.newInstance();
//1.通过Class实例调用getDeclareField(String fieldName)获取运行时类指定的属性
Field namefield = clazz.getDeclaredField("name");
//2、确保此属性可以访问
namefield.setAccessible(true);
//3、通过Filed类的实例调用get(Object obj)获取
// 或设置此属性的值set(Object obj,Object value)
namefield.set(person,"Tom");
System.out.println(namefield.get(person));
}
}

JAVA高级-反射与动态代理(十五)插图(156)

调用静态属性
JAVA高级-反射与动态代理(十五)插图(157)

JAVA高级-反射与动态代理(十五)插图(158)
infoField.get()里参数不写不行,因为他不是可变参数。写null是没问题的。
JAVA高级-反射与动态代理(十五)插图(159)
JAVA高级-反射与动态代理(十五)插图(160)

JAVA高级-反射与动态代理(十五)插图(161)
怎么理解此处null?获取属性时就是用Class获取的,clazz就是Person.class
JAVA高级-反射与动态代理(十五)插图(162)
若是实例变量,就必须要传对象
JAVA高级-反射与动态代理(十五)插图(163)

JAVA高级-反射与动态代理(十五)插图(164)

public class ReflectTest {
//调用静态属性
// private static String info;
@Test
public void test3() throws  Exception{
Class clazz = Person.class;
Field infofield = clazz.getDeclaredField("info");
infofield.setAccessible(true);
/* infofield.set(Person.class,"我是一个人");
System.out.println(infofield.get(Person.class));
*/
infofield.set(null,"我是一个人");
System.out.println(infofield.get(null));
}
}

JAVA高级-反射与动态代理(十五)插图(165)

这里是引用

JAVA高级-反射与动态代理(十五)插图(166)

JAVA高级-反射与动态代理(十五)插图(167)

JAVA高级-反射与动态代理(十五)插图(168)
这里为啥不能写Integer
JAVA高级-反射与动态代理(十五)插图(169)
因为不同类型的值才可以自动装箱,此处是类型
int class和Integer class 显然是不同的实例
这叫自动装箱
JAVA高级-反射与动态代理(十五)插图(170)
JAVA高级-反射与动态代理(十五)插图(171)
正常情况下,非静态方法用对象去调,传实参
JAVA高级-反射与动态代理(十五)插图(172)
JAVA高级-反射与动态代理(十五)插图(173)

JAVA高级-反射与动态代理(十五)插图(174)
JAVA高级-反射与动态代理(十五)插图(175)
发现方法有返回值,返回值怎么体现呢?
~~删除JAVA高级-反射与动态代理(十五)插图(176)

invoke方法的返回值就是shownation的返回值
JAVA高级-反射与动态代理(十五)插图(177)
JAVA高级-反射与动态代理(十五)插图(178)

JAVA高级-反射与动态代理(十五)插图(179)
JAVA高级-反射与动态代理(十五)插图(180)

JAVA高级-反射与动态代理(十五)插图(181)

JAVA高级-反射与动态代理(十五)插图(182)
JAVA高级-反射与动态代理(十五)插图(183)

import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
//反射应用3-2:调用指定的方法
// private String showNation(String nation, int age){}
@Test
public void test4() throws Exception{
Class clazz = Person.class;
Person person =(Person) clazz.newInstance();
//1.通过Class的实列调用getDeclareMethod(String methodName,Claass...args)获取指定的方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class, int.class);
//2.setAccessible(true);确保此方法是可以调用的
showNation.setAccessible(true);
//3.通过Method实例调用invoke(Onject obj,objs)即为对Method对应的方法调用
//invoke()返回值即为Method对应的返回值
//特别的,如果Method对应的返回值类型为void,则invoke()返回值为bull
Object invoke = showNation.invoke(person, "CHN", 10);
System.out.println(invoke);
}

JAVA高级-反射与动态代理(十五)插图(184)
涉及静态方法
JAVA高级-反射与动态代理(十五)插图(185)

JAVA高级-反射与动态代理(十五)插图(186)

package apply3;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
//调用静态方法
// public static void showInfo() {}
@Test
public void test5() throws  Exception{
Class clazz = Person.class;
Method declaredMethod = clazz.getDeclaredMethod("showInfo");
declaredMethod.setAccessible(true);
Object invoke = declaredMethod.invoke(null);
System.out.println(invoke);
}
}

JAVA高级-反射与动态代理(十五)插图(187)

JAVA高级-反射与动态代理(十五)插图(188)

JAVA高级-反射与动态代理(十五)插图(189)
JAVA高级-反射与动态代理(十五)插图(190)
JAVA高级-反射与动态代理(十五)插图(191)

package apply3;
import com.zhou.java.Person;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
//调用指定构造器
@Test
public void test6() throws Exception{
Class clazz= Person.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Person per = (Person)constructor.newInstance("Tom", 12);
System.out.println(per);
}
}

JAVA高级-反射与动态代理(十五)插图(192)
JAVA高级-反射与动态代理(十五)插图(193)

JAVA高级-反射与动态代理(十五)插图(194)
JAVA高级-反射与动态代理(十五)插图(195)

JAVA高级-反射与动态代理(十五)插图(196)
JAVA高级-反射与动态代理(十五)插图(197)
JAVA高级-反射与动态代理(十五)插图(198)
框架大量使用注解
框架使用反射去读注解,根据注解属性值做相应处理
熟悉常用注解,知道注解怎么赋值
参照SupperssWarming,他怎么写,我们就怎么写,
JAVA高级-反射与动态代理(十五)插图(199)

Table修饰类、接口类型
JAVA高级-反射与动态代理(十五)插图(200)

JAVA高级-反射与动态代理(十五)插图(201)
注解能让我们获取就的是RunnntimeJAVA高级-反射与动态代理(十五)插图(202)
在类的声明处就可以使用
此处为什么报错
没有进行赋值
JAVA高级-反射与动态代理(十五)插图(203)
JAVA高级-反射与动态代理(十五)插图(204)
此处可以进行默认赋值
JAVA高级-反射与动态代理(十五)插图(205)

此处就不再报错

反射复习
1.反射的概述(熟悉)
Java给我们提供了一套API
JAVA高级-反射与动态代理(十五)插图(206)
运行时动态获取指定对象所属类(通过对象调getClass)

JAVA高级-反射与动态代理(十五)插图(207)
API
JAVA高级-反射与动态代理(十五)插图(208)
JAVA高级-反射与动态代理(十五)插图(209)

2.Class的源头

3.类的加载过程、类的加载器(理解)

4.反射的应用1:创建运行时类的对象
5.反射的应用2:获取运行时类所有的结构
6.反射的应用3:调用指定的结构:属性、方法、构造器
7.反射的应用4:注解的使用
8.体会反射的动态性

本站无任何商业行为
个人在线分享 » JAVA高级-反射与动态代理(十五)
E-->