目录
一、相关基础概念
- 类对象:就是用来介绍一个类有哪些属性和方法的对象(提供类本身的信息);对反射来说类对象就是一面镜子。
- Class类:
(1)Class类的基本介绍
(2)Class类的相关方法
(3)Class类对象的三种获取方式
三种方式对应计算机的三个阶段(编译 加载 运行)
(4)哪些类型有类对象
(5)类的加载
静态加载和动态加载的区别,举个例子:
解释:new Dog()是静态加载,所以必须要编写Dog类,否则会报错;
Person类是动态加载,所以,不编写Person类也不会报错,只有动态加载到该类时,才会报错;
(6)类加载的五个阶段
加载阶段就是创建一个Class类对象
连接阶段的三个子阶段
验证阶段就是验证数据的文件格式是否正确
准备阶段就是给静态变量分配内存空间
解析阶段就是当数据存储进内存时,将符号引用换成地址来引用;
初始化阶段就是通过clinit()方法自动收集静态变量和静态代码块,并合并;同时系统会保证多个线程同一时刻只有一个线程加载类(即会上锁,有同步机制控制)
重点:
1.一个类的class类对象只有一个,不管new创建多少个对象都是同一个(即哈希值相同)
2.class对象是存放在堆里面的
3.类对象有三种获取方式对应计算机的三个阶段
二、反射
1.反射是什么?
类对象就像是一面镜子,通过类对象(镜子)看到类的结构(类本身的信息,就是有哪些属性、哪些方法),这个就是反射
2反射有什么用?
可以在不需改源代码的情况下,通过修改配置文件来控制程序(即开闭功能)
3.反射怎么用?
(1)通过反射获取类的结构信息(API)
(2)通过反射创建对象
先拿到class类对象,再用类对象获取到构造器对象,再用构造器对象创建对象
实例代码
import java.lang.reflect.Constructor;
//韩顺平735集
//演示通过反射创对象
public class ReflectCreateInstance {
public static void main(String[] args) throws Exception {
//1.先获取User类的class类对象
Class<?> user = Class.forName("getClass.User"); //注意类对象的数据类型是Class,不是User
//2.通过public的无参构造器来创建对象
Object u = (User) user.newInstance();//newInstance()方法是用来调用无参构造器来创建对象
System.out.println(u);
//3.通过public的有参构造器来创建对象
//3.1对于有参构造器要先获取构造器对象,再用构造器对象来调用newInstance()方法(调用无参构造器来创建对象)来创建对象
Constructor constructor = user.getConstructor(String.class);
//3.2创建对象,并传入实参
Object hsp = constructor.newInstance("hsp");
System.out.println(hsp);
//4.通过非public的无参构造器来创建对象
//4.1先要得到private的构造器对象
Constructor constructor1 = user.getDeclaredConstructor(int.class, String.class);
//4.2创建对象
constructor1.setAccessible(true);//暴破(暴力破解),通过反射访问私有的构造器
Object hsp1 = constructor1.newInstance(12,"hsp");
System.out.println(hsp1);
}
}
class User{
private String name = "韩顺平教育";
private int age = 10;
public User(){
}
public User(String name) { //共有有参构造器
this.name = name;
}
private User(int age,String name){ //私有有参构造器
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
(3)通过反射暴破获取属性
import java.lang.reflect.Field;
//韩顺平726集
//演示通过反射暴破获取属性
public class ReflectAccessProperty {
public static void main(String[] args) throws Exception {
//1.获得类对象
Class<?> aClass = Class.forName("getClass.Student");//全类路径不要写错,包名.类名
//2.得到类对象后,还要创建对象
Object o = aClass.newInstance();
//怎么获得属性
//3.用类对象,即反射来获得age属性对象
Field age = aClass.getField("age");
age.set(o,88);
System.out.println(o);
//先设置还是先暴破,什么时候暴破? 暴破后才能设置
//4.使用反射操作name属性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(o,"John");
System.out.println(o);
}
}
class Student{
private String name;
public int age;
public Student(){
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
(4)通过反射操作方法
import java.lang.reflect.Method;
//韩顺平727集
//演示反射操作方法
public class ReflectAccessMethod {
public static void main(String[] args) throws Exception {
//1.获得类对象
Class<?> aClass = Class.forName("getClass.Boss");//全路径不要再写错了
//2.创建对象
Object o = aClass.newInstance();
//3.获得方法对象
Method hi = aClass.getDeclaredMethod("hi",String.class);//getMethod()方法根据方法名获得方法对象,并要传入方法实参
//4.调用方法
System.out.println( hi.invoke(o, "张三"));
//私有方法的暴破
Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
System.out.println(say.invoke(o,100,"李四",'男'));
}
}
class Boss{
public int age;
private static String name;
public Boss() {
}
private static String say(int n,String s,char c) {
return n + " " + s + " " + c;
}
public void hi(String s){
System.out.println("hi"+s);
}
}
类对象是为了获得对象、属性对象和方法对象(通过调用方法);
创建对象是为了设置属性和方法;
属性对象和方法对象是为了调用属性和方法;