文章目录
类加载器
分类:
-
Bootstrap ClassLoader
根类加载器- 负责Java运行时核心类的加载,JDK中JRE的lib目录下rt.jar
-
Extension ClassLoader
扩展类加载器- 负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录
-
Sysetm(App) ClassLoader
系统类加载器/应用加载器- 负责加载自己定义的Java类
逻辑上的父子关系:
类加载时机
-
创建类的实例(首次创建该类对象)
-
访问类的静态变量 (首次)
-
调用类的静态方法 (首次)
-
加载某个类的子类,会先触发父类的加载
-
直接使用
java.exe
命令来运行某个主类,也就是执行了某个类的main()
方法 -
使用反射方式来强制创建某个类或接口对应的
java.lang.Class
对象
Java代码的3个阶段
反射
获取运行时类信息 的一种手段,反射的起点是字节码文件对象。
获取字节码文件对象的几种方式:
对象.getClass()
类名.class
Class.forName(String className)
全限定名- ClassLoader里的
loadClass(String className)
无论通过什么方式获取的字节码文件对象 ,都是同一个。
eg:
java
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
// 对象.getClass()
A a = new A();
Class<? extends A> c1 = a.getClass();
// 类名.class
Class<A> c2 = A.class;
System.out.println(c1 == c2);
// Class.forName(String className) 全限定名
Class<?> c3 = Class.forName("com.cskaoyan.Demo0112.A");
System.out.println(c1 == c3);
// ClassLoader里的loadClass(String className)
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Class<?> c4 = systemClassLoader.loadClass("com.cskaoyan.Demo0112.A");
System.out.println(c1 == c4);
}
}
class A{
}
注:
类名.class
没有执行静态代码块Class.forName()
执行静态代码块
eg:
java
@Test
public void test1() throws ClassNotFoundException {
// 类名.class
// 没有执行静态代码块
Class<B> b1 = B.class;
// Class.forName()
// 执行静态代码块
Class<?> b2 = Class.forName("com.cskaoyan.Demo0112.B");
}
class B{
static{
System.out.println("this is static");
}
}
关于Class
-
Class
类的实例表示正在运行的 Java 应用程序中的类和接口 -
Class
没有公共构造方法 。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass
方法自动构造的。
配置文件(.properties)
-
配置文件的几种格式
.properties
、.xml
、.yml
-
配置文件的作用 : 放配置信息的 (数据库的, 第三方服务的配置信息)
-
.properties
的格式:- 键值对 (
key-value
) key=value
key
是不能重复的- 注释 是
#
- 文件里面全是
String
- 键值对 (
Properties类
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
在文件 ---> 资源包
创建可得
eg:
java
# 数据库的配置信息
url=jdbc:mysql://localhost:3306/test
host=localhost
port=3306
user= root
password=1234567
构造方法:
java
Properties() // 创建一个无默认值的空属性列表。
成员方法:
eg:
java
public class Demo {
public static void main(String[] args) throws IOException {
// 1. 创建Properties对象
Properties properties = new Properties();
// 2. load
properties.load(new FileInputStream("People.properties"));
// 3. 获取属性值
// getProperty(String key)
String port = properties.getProperty("port");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String host = properties.getProperty("host");
System.out.println(port);
System.out.println(password);
System.out.println(user);
System.out.println(host);
}
}
或
java
public class Demo {
public static void main(String[] args) throws IOException {
// 1. 创建Properties对象
Properties properties = new Properties();
// 2. 通过类加载器
URL systemResource = ClassLoader.getSystemResource("");
System.out.println(systemResource);
// "" 在这里面,把"People.properties"应该放这里输出的路径下面
InputStream in = ClassLoader.getSystemResourceAsStream("People.properties");
// 3. load
properties.load(in);
// 4. 获取属性值
// getProperty(String key)
String port = properties.getProperty("port");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String host = properties.getProperty("host");
System.out.println(port);
System.out.println(password);
System.out.println(user);
System.out.println(host);
}
}
输出中文的情况:
java
public class Demo {
public static void main(String[] args) throws IOException {
// 创建Properties对象
Properties properties = new Properties();
// load
properties.load(
new InputStreamReader(
new FileInputStream("People.properties"),"GBK"));
// 获取属性
String user = properties.getProperty("user");
System.out.println(user);
}
}
通过反射获取构造方法(Constructor)
通过反射获取所有构造方法:
java
Constructor[] getConstructors() // 获取的是public的构造方法
Constructor[] getDeclaredConstructors() // 获取所有的构造方法
获取指定构造方法:
java
Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
使用Constructor创建对象:
java
Person p = new Person("zs",20,true)
newInstance(参数列表)
暴力破解:
上面的方法创建不了private
的对象,这里可以
java
setAccessible(true) // 忽略java语法检查
先定义一个Person类:
java
public class Person {
public String name;
private int age;
boolean gender;
public Person(String name, int age, boolean gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
private Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this.name = name;
}
public Person() {
}
public void eat() {
System.out.println("eat food");
}
private void eat(String food) {
System.out.println("eat" + food);
}
private String sleep() {
return "sleep";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
}
eg:
java
public class Demo {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, InstantiationException, IllegalAccessException {
// 1. 获取字节码文件对象
Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");
// 2. 获取所有的构造方法
// Constructor[] getConstructors()
Constructor<?>[] constructors = a1.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
// Constructor[] getDeclaredConstructors()
Constructor<?>[] declaredConstructors = a1.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
// 3. 获取指定构造方法
// Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<?> constructor = a1.getConstructor
(String.class, int.class, boolean.class);
System.out.println(constructor);
// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor<?> declaredConstructor = a1.getDeclaredConstructor
(String.class, int.class);
System.out.println(declaredConstructor);
// 4. 使用Constructor创建对象
// 通过构造方法对象创建对象
//newInstance(参数列表)
Object o = constructor.newInstance("zs", 20, true);
System.out.println(o);
// 5. setAccessible(true)
declaredConstructor.setAccessible(true);
Object o1 = declaredConstructor.newInstance("ww", 18);
System.out.println(o1);
}
}
通过反射获取成员变量(Field)
通过反射获取所有成员变量:
java
Field[] getFields()
Field[] getDeclaredFields()
获取指定成员变量:
java
Field getField(String name) // 获取的是public权限
Field getDeclaredField(String name) // 获取的是所有权限
通过Field读写对象的成员变量(可暴力破解):
java
Object get(Object obj) // 获取值,传入对象
void set(Object obj, Object value) // 赋值,传入对象
eg:
java
public class Demo {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchFieldException,
NoSuchMethodException, InvocationTargetException,
InstantiationException, IllegalAccessException {
// 1. 拿到字节码文件对象
Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");
// 2. 通过反射获取所有的成员变量
// Field[] getFields()
Field[] fields = a1.getFields();
for (Field field : fields) {
System.out.println(field);
}
// Field[] getDeclaredFields()
Field[] declaredFields = a1.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// 3. 获取指定成员变量
// Field getField(String name)
Field nameField = a1.getField("name");
System.out.println(nameField);
// Field getDeclaredField(String name)
Field ageField = a1.getDeclaredField("age");
System.out.println(ageField);
// 4. 通过Field读写对象的成员变量(可暴力破解)
// void set(Object obj, Object value):赋值,传入对象
Constructor<?> declaredConstructor = a1.getDeclaredConstructor();
Object o = declaredConstructor.newInstance();
nameField.set(o,"zs");
System.out.println(o);
// Object get(Object obj):获取值,传入对象
Object o1 = nameField.get(o);
System.out.println(o1);
}
}
通过反射获取成员方法(Method)
获取所有成员方法:
java
Method[] getMethods()// 父类的也能获取到,只能获取public的方法
Method[] getDeclaredMethods() // 能够获取所有的方法
获取指定的成员方法:
java
Method getMethod(String name, Class<?>... parameterTypes)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
利用Method调用对象的方法:
java
Object invoke(Object obj, Object... args)
eg:
java
public class Demo {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, InstantiationException,
IllegalAccessException {
// 1. 获取字节码文件对象
Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");
// 2. 获取所有成员方法
// Method[] getMethods()// 父类的也能获取到
Method[] methods = a1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// Method[] getDeclaredMethods()
Method[] declaredMethods = a1.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
// 3. 获取指定的成员方法
// Method getMethod(String name, Class<?>... parameterTypes)
Method eatMethod = a1.getMethod("eat");
System.out.println(eatMethod);
// Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method eatDeclaredMethod = a1.getDeclaredMethod("eat", String.class);
System.out.println(eatDeclaredMethod);
// 利用Method调用对象的方法
// Object invoke(Object obj, Object... args)
Constructor<?> declaredConstructor = a1.getDeclaredConstructor();
Object o = declaredConstructor.newInstance();
eatMethod.invoke(o);
}
}
其他API
注 :可以通过Class直接实例化 , 但是要有一个无参构造方法
eg:
java
public class Demo {
public static void main(String[] args)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.A");
// 通过class对象直接实例化对象
Object o = a1.newInstance();
System.out.println(o);
}
}
class A {
int a;
public A(int a) {
this.a = a;
}
public A() {
}
}
eg:
java
public class Demo {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchFieldException,
NoSuchMethodException {
// 1. 先获取字节码文件对象
Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");
Class<?> a2 = Class.forName("java.io.OutputStream");
// 2. 获取类名
System.out.println(a1.getName());
// 3. 获取简单名
System.out.println(a1.getSimpleName());
// 4. 获取父类
System.out.println(a1.getSuperclass());
System.out.println(a1.getSuperclass().getSimpleName());
// 5. 获取实现的接口
Class<?>[] interfaces = a2.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface);
}
// 6. 获取成员变量
Field nameField = a1.getDeclaredField("name");
// 获取成员变量的类型
System.out.println(nameField.getType());
int modifiers = nameField.getModifiers();
System.out.println(modifiers); // 1 就是public
System.out.println(Modifier.toString(modifiers));
// 7. 获取method对象
Method eatMethod = a1.getDeclaredMethod("eat", String.class);
// 方法的返回值类型
System.out.println(eatMethod.getReturnType());
// 方法的参数类型
Class<?>[] parameterTypes = eatMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
}
}
自定义类加载器
步骤:
- 继承
ClassLoader
- 重写
findClass
方法
eg:
java
MyClassLoader自定义类加载器:
public class MyClassLoader extends ClassLoader {
// 成员
String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> aClass = null;
// 读取.class文件
try {
byte[] data = getData();
// defineClass(String name, byte[] b, int off, int len)
// 将一个 byte 数组转换为 Class 类的实例。
aClass = defineClass(name, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
// 最终要返回一个Class对象
return aClass;
}
private byte[] getData() throws IOException {
// 读取字节码文件
// 创建FileInputStream
FileInputStream in = new FileInputStream(classPath);
// 使用ByteArrayOutputStream
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int readCount;
byte[] bytes = new byte[1024];
while ((readCount = in.read(bytes)) != -1 ){
outputStream.write(bytes,0,readCount);
}
/*
byte[] toByteArray()
创建一个新分配的byte数组
*/
byte[] bytes1 = outputStream.toByteArray();
// 返回字节码文件里的数据
return bytes1;
}
}
-----------------------------------------------------
public class Demo {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
// 定义加载路径
String classPath =
"D:\\Test.class";
// 创建自定义类加载器
MyClassLoader myClassLoader = new MyClassLoader(classPath);
// 通过loadClass方法加载类
Class<?> testLc = myClassLoader.loadClass("Test");
// 得到字节码文件对象
// 拿到Method对象
Method funcMethod = testLc.getDeclaredMethod("func");
// invoke
Object o = testLc.newInstance();
funcMethod.invoke(o);
}
}
反射的应用
-
通过反射获取注解信息
-
动态代理
-
ORM(Object Relational Mapping)框架
, 数据库框架