观看尚硅谷视频做的视频笔记
一、高级-反射与动态代理(十四)
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.
方案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反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时
2.Class类的理解
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
6.类的加载过程(详细在jvm中有)
6.1过程1:loading(装载)
将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由加载器完成
6.2过程2linking(连接)
验证、准备、解析
验证(Verify):确保加载的类信息符合JVM规范,例如:以cafebabe开头,没有安全方面的问题。
准备prepare):正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
解析(Resolve):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
6.3过程3Initialization(初始化)
6.4关于类的加载器(了解,JDK8版本为例)
1)作用:负责类的加载,并对应一个Class的实例
虽叫类的加载器,不仅能加载类,还能加载接口、没接、注解等
负责将字节码文件放到内存中
2) 分类(分为两种)
似乎是继承关系,其实不是继承关系,而是层级关系
①BootStrapClassLoader:引导加载器、启动加载器
使用C、c++语言编写的,不能通过java代码获取实例
负载加载java的核心库。(Java_Home/jar/lib/rt.jar)
java代码获取实例,获取的时候返回为null
②继承于ClassLoader的类加载器
扩展类加载器(jdk提供的)
系统类加载器、应用程序类加载器(jdk提供的)自定义的类默认使用的类的加载器
用户自定义类的加载器(Tomcat中也定义了一些类加载器)
③代码演示
获取系统类加载器
获取扩展加载器(获取上一层加载器)
获取引导类加载器失败,获取不到。返回值为null
用户自定义的类是系统类加载加载的
方式一
方式二
3)以上的类的加载器是否存在继承关系
4)掌握使用类的加载器获取流,并读取配置文件信息。
方案一:
propertites处理属性文件
读取配置文件时:
使用单元测试方法,默认就是使用的是当前module下面
通过propertites读取流当中文件的数据
处理的key和值都是String类型
以后会实现数据和代码的分离
数据会放在具体的配置文件中
使用Classloader也可以做这样的事儿
拿到系统加载器
作为流拿到一个资源
方案二:
7.反射的应用
7.1反射的应用1:创建运行时类的对象
1)如何实现:通过Class的实例调用newInstance()方法即可
2)要想创建对象成功,需要满足
①条件1:要求运行是类必须满足一个空参的构造器。
②条件2:要求提供的空参构造器的权限要足够。
Person类实现了两个接口
![在这里插入图片描述](https://img-blog.csdnimg.cn/235dae5963cd448a9876eaaff8a30cd7
.png)
创建Person对象此处的创建运行时类对象指的是Person类
当把Person类加载到内存中时
使用Java.exe指令时,走类的加载过程:loading,linking、initilion环节,在方法区就会有一个大的实例。就称为运行时类。
首先有一个大的Class实例,获取实例。
per调的是toString方法
若Person类里没有空参构造器,则抛异常
还有一种异常是有构造器但不能用私有权限
默认权限,同包别的类能用
3)回忆:javabean中要求当前类:一个空参构造器,有什么用?
①场景1:子类对象在实例化时,子类的构造器的首行默认调用父类的空参的构造器默认有super()
②场景2:在反射中,经常用来创建运行时类的对象,那么我们要求各个运行时类都提供一个空参构造器,便于我们创建运行时类对象的代码。
Javabean的要求,当前类是公共的,提供当前类的空参构造器,有属性提供get、set方法、有toString方法、重写equals、hashcode方法,是为了防止将对象放在集合中、toString方法(打印对象变量时,打印地址、打印属性的值)
为啥要有这个提供空参构造器这个要求?
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:父类、接口们、包、贷泛型的父亲、父亲的泛型
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) + "\t");
// //2.数据类型
Class type = f.getType();
System.out.print(type.getName() + "\t");
//
// //3.变量名
String fName = f.getName();
System.out.print(fName);
//
System.out.println();
}
}
}
得到的都是Person类声明的,父类的没有
获取每一个具体的信息
f.getModifiers()获取修饰符
类调里面的toString方法,可以看到权限修饰符
怎么做的?因为modifer这个数在Modifer这个类中有对应的十六进制对应关系
获取方法
都是当前类中有的
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) + "\t");
//2.数据类型
Class type = f.getType();
System.out.println(type.getName() + "\t");
//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);
}
}
}
person里使用了注解
自定义注解,要想在反射中获取注解及注解的信息,需要求注解的生命周期长
首先有大的实例,指明全类名
person继承时带泛型
希望结果里带上泛型
一个类可以实现多个接口,所以就是数组
什么时候用到,泛型写apply时
自定义泛型时,写dao时,dao通用的增删改查操作
操作的哪个表暂时不确定,回到Java层面哪个类不确定?
有可能需要当前类中继承的方法,有一些需要重写,有一些需要继承父类调用的方法,在这里需要获取这里这个类继承的父类的泛型
获取某一个对象,就不用传大的Class
获取Person类的实例,希望打印出String
先获取带泛型的父类
也有可能这个类,父类没有泛型,
也有可能有泛型,若有泛型就进行强转。
数组就是泛型参数构成的
角标0就是想要的String
不想要class,就获取class名字
调getname()调不了
是因为目前看到的是Type
Type是Class实现的接口
强转成Class
然后再进行Class.getName
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) + "\t");
//2.数据类型
Class type = f.getType();
System.out.println(type.getName() + "\t");
//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:调用指定的结构、指定的属性、方法、构造器
还是针对Person类
age非静态,获取它的值,跟对象打交道
创建当前类的对象
创建Person类的实例
获取当前类中名字叫age属性,File是java.lang包下的子类
这个属性是实例变量,得跟对象打交道
得说明是哪一个对象的值,是per对象的
因为此处是默认权限
改成public
设置属性的值
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
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));
}
}
调用静态属性
infoField.get()里参数不写不行,因为他不是可变参数。写null是没问题的。
怎么理解此处null?获取属性时就是用Class获取的,clazz就是Person.class
若是实例变量,就必须要传对象
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));
}
}
这里是引用
这里为啥不能写Integer
因为不同类型的值才可以自动装箱,此处是类型
int class和Integer class 显然是不同的实例
这叫自动装箱
正常情况下,非静态方法用对象去调,传实参
发现方法有返回值,返回值怎么体现呢?
~~删除
invoke方法的返回值就是shownation的返回值
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);
}
涉及静态方法
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);
}
}
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);
}
}
框架大量使用注解
框架使用反射去读注解,根据注解属性值做相应处理
熟悉常用注解,知道注解怎么赋值
参照SupperssWarming,他怎么写,我们就怎么写,
Table修饰类、接口类型
注解能让我们获取就的是Runnntime
在类的声明处就可以使用
此处为什么报错
没有进行赋值
此处可以进行默认赋值
此处就不再报错
反射复习
1.反射的概述(熟悉)
Java给我们提供了一套API
运行时动态获取指定对象所属类(通过对象调getClass)
API
2.Class的源头
3.类的加载过程、类的加载器(理解)
4.反射的应用1:创建运行时类的对象
5.反射的应用2:获取运行时类所有的结构
6.反射的应用3:调用指定的结构:属性、方法、构造器
7.反射的应用4:注解的使用
8.体会反射的动态性