反射//掌握(☆☆☆☆☆)
一、类的加载
1.加载类
*把字节码文件(.class文件)加载进内存
*创建一个对应的字节码文件对象,用来描述类的结构
2.连接类
*检查该类的语法是否符合规范要求
3.初始化类
先完成父类的初始化,再初始化子类
二、类的初始化时机
*创建类的实例
*调用类的类方法
*访问类或者接口的类变量,或者为该类变量赋值
*使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
*初始化某个类的子类
*直接使用java.exe命令来运行某个主类
//什么时候使用就什么时候加载
三、类加载器
1.类加载器的功能
将字节码文件加载进内存,并创建对应的字节码文件对象
2.特点
对于不同的类和文件而言,会有不同的类加载器
四、反射的概念//(☆☆☆☆☆)
就是使用类的"字节码文件对象"(而不是Java对象)来获取类的成员变量、构造方法、成员方法,并且无视权限修饰符
五、获取字节码文件对象的方式
1.使用类名.class //最简单
Class c1 = Student.class;
2.使用对象.getClass()
Student s1 = new Student();
Class c2 = s1.getClass();
3.使用Class.forName(全类名) //开发中最常用
//(1)什么是全类名? 包名+类名 例如: demo4.Student
//怎么写全类名 : 选中你要用的那个类---------->右键---------->选择Copy Reference
//为什么说第三种方法最灵活?
//因为第三种方法可以结合配置文件使用 使用匹配文件就是为了解耦合
六、反射获取构造方法
1.为什么要获取构造方法
创建对象
2.类和方法
*Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组 //多个public修饰的 构造方法
*Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组 //所有的修饰符修饰的构造方法
*Constructor getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象 //指定的单个public修饰的构造方法
*Constructor getDeclaredConstructor(Class<?>... parameterTypes)返回单个构造方法对象//指定的单个任意修饰的构造方法
//使用构造方法对象创建对象的方法
T newInstance(Object...initargs) 根据指定的构造方法创建对象
3.使用步骤
(1)获取字节码文件对象
Class<?> c1 = Class.forName("demo4.Student");
(2)获取构造方法对象
Constructor<?> constructor = c1.getConstructor(String.class, int.class); //传入的参数需要是类型的class形式
(3)使用构造方法对象来创建对象
Object o = constructor.newInstance("王二小", 9);
4.注意事项
获取的构造方法的参数一定要和创建对象时newInstance方法的参数对应
七、暴力反射
1.应用场景
当我们使用private修饰的构造方法对象、成员变量对象、成员方法对象,需要使用暴力反射
2.怎么使用
(1)在获取构造方法、成员变量、成员方法对象的时候,需要使用带Declared的方法
(2)必须使用构造方法、成员变量、成员方法对象的setAccesible(true); //表示暂时允许我访问
代码实现:
Class<?> c1 = Class.forName("demo4.Student");
Constructor<?> constructor = c1.getDeclaredConstructor(); //带Declared的
constructor.setAccessible(true); //暂时允许访问
Object o = constructor.newInstance();
System.out.println(o);
八、反射获取成员变量
1.为什么要获取成员变量对象?
给成员变量赋值
//在给对象的成员变量赋值是有前提的:先有一个对象
Student s1 = new Student();
s1.name= "林青霞";
2.相关的类和方法
(1)获取成员变量对象的方法
*Field[] getFields() 返回所有公共成员变量对象的数组 //所有的public修饰的成员变量对象
*Field[] getDeclaredFields() 返回所有成员变量对象的数组 //所有的任意修饰符的成员变量对象
*Field getField(String name) 返回单个公共成员变量对象 //指定的单个public修饰的成员变量对象
*Field getDeclaredField(String name) 返回单个成员变量对象 //指定的单个任意修饰的成员变量对象
//参数name是什么意思? 是成员变量的名称
(2)给成员变量赋值的方法
void set(Object obj,Object value) 给obj对象的成员变量赋值为value
//参数 obj:对象 value:指的是给成员变量赋的值
3.实现步骤
(1)获取字节码文件对象
(2)获取构造方法对象,并创建对象
(3)获取成员变量的对象
(4)调用set方法给成员变量赋值
//代码实现:
Class<?> c1 = Class.forName("demo4.Student");
Constructor<?> con = c1.getDeclaredConstructor();
con.setAccessible(true);
Object o = con.newInstance();
Field age = c1.getDeclaredField("age");
age.setAccessible(true);
age.set(o,13); //o是对象 age成员变量 13成员变量的值 Student s = new Student(); s.age=13;
System.out.println(o);
九、反射获取成员方法的对象
1.为什么要获取成员方法对象?
为了调用该方法
//想调用对象的成员方法是有前提的:先有一个对象
2.相关的类和方法
(1)获取成员方法对象的方法
// getMethods和getDeclaredMethods的区别? 面试题
*Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的 //所有的public修饰的方法+继承过来的
*Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的 //所有的任意修饰符修饰的方法 (不包括继承过来的)
*Method getMethod(String name, Class<?>... parameterTypes)返回单个公共成员方法对象 //指定的public修饰的
*Method getDeclaredMethod(String name, Class<?>... parameterTypes)返回单个成员方法对象 //指定的任意修饰符修饰的
//参数:name指的是方法的名称 parameterTypes指的是方法的参数的类型
(2)调用成员方法的方法
Object invoke(Object obj,Object... args) 调用obj对象的成员方法,参数是args,返回值是Object类型
//参数: obj:指的是调用成员方法的对象 args指的是方法的参数
//代码实现:
Class<?> c1 = Class.forName("demo4.Student");
Constructor<?> con = c1.getDeclaredConstructor();
con.setAccessible(true);
Object o = con.newInstance();
Method show = c1.getDeclaredMethod("show", String.class);
show.setAccessible(true);
Object obj = show.invoke(o, "南京黑马第一帅玮");
System.out.println(obj);
十、关于案例
1.越过泛型检查
泛型只会在编写代码的编译期间进行泛型的检查
当生成字节码文件后(编译结束之后),泛型就就会被擦除
模块化 //了解
一、模块化的概述
1.模块的概念
在心爱的idea中,我们在项目(project)中新建的module就是模块
2.模块的特点
不同的模块之间不能相互访问
3.模块化的使用前提
jdk大于等于9
二、模块化的基本使用
1.模块化:解决模块间不能相互访问的问题
2.我要在A模块中使用B模块中的内容
//A使用者 B提供者
(1)在A和B的src目录下新建module-info.java文件
(2)在A的module-info.java文件
requires 模块名
(3)在B的module-info.java文件
exports 包名
三、面向接口编程
对外只提供接口的名称,其他的具体实现不对外提供。保证了代码的安全性
举例:美团外卖中的地图功能