类的形成
1.(加载)先将Class文件字节码 加载到内存,并将这些静态数据转换成方法区运行时的数据结构,然后生成一个代表这个类的 java.lang.Class 类对象
方法区:(包含在内的元素)
- 静态方法
- 静态变量
- 常量池 -->类名、变量名、方法名,常量(final)
- 代码
2.(连接)将JAVA类二进制代码合并到JVM的运行状态之中的过程
- 1、 (验证) 验证信息完整性、规范性(JVM规范) 和 安全性
- 2、 (准备) 正式为类变量(static)分配内存并设置类变量的默认值的阶段,这些空间都将在方法区中进行分配
- 3、 (解析) 虚拟机常量池中的符号引用(常量名) 都将替换为真正的引用(地址)(指针)的过程。
3.(初始化) 执行类构造器()——(这里要区别对象构造器),,
- 1、 < clinit >()方法 会将所有类变量赋值。
- 2、 < clinit >()方法 会将所有的 静态(static)代码合并 。
- 3、 当初始化一个类的时候发现他的父类没有被初始化,会先调用它父类的 类初始化。
- 4、 虚拟机会保证一个类的()方法 在多线程下 被 正确的加锁 和 同步。
代码详情:
package reflection;
/**
* @ClassName ReflectionTest_1
* @Description
* @Author SkySong
* @Date 2020-09-27 20:42
*/
public class ReflectionTest_1 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.a);
}
/**
* 1.(加载)先将Class文件字节码 加载到内存,并将这些静态数据转换成方法区运行时的数据结构,然后生成一个代表这个类的 java.lang.Class 类对象
* 方法区-->
* 静态方法
* 静态变量
* 常量池 -->类名、变量名、方法名,常量(final)
* 代码
* 2.(连接)将JAVA类二进制代码合并到JVM的运行状态之中的过程
* 1>(验证) 验证信息完整性、规范性(JVM规范) 和 安全性
* 2>(准备) 正式为类变量(static)分配内存并设置类变量的默认值的阶段,这些空间都将在方法区中进行分配
* 3>(解析) 虚拟机常量池中的符号引用(常量名) 都将替换为真正的引用(地址)(指针)的过程。
* 3.(初始化) 执行类构造器<clinit>()——(这里要区别对象构造器),,
* 1> <clinit>()方法 会将所有类变量赋值。
* 2> <clinit>()方法 会将所有的 静态(static)代码合并 。
* 3> 当初始化一个类的时候发现他的父类没有被初始化,会先调用它父类的 类初始化。
* 4> 虚拟机会保证一个类的<clinit>()方法 在多线程下 被 正确的加锁 和 同步。
*/
}
class A{
static {
System.out.println("A类静态代码块初始化");
a = 300;
}
static int a = 100;
/**
* 静态代码合并
* System.out.println("A类静态代码块初始化");
* a = 300;
* int a = 100;
*/
public A(){
System.out.println("A类的无参构造初始化");
}
}
执行结果:
A类静态代码块初始化
A类的无参构造初始化
100
Process finished with exit code 0
类的加载
package reflection;
/**
* @ClassName ReflectionTest_2
* @Description
* @Author SkySong
* @Date 2020-09-27 21:37
*/
public class ReflectionTest_2 {
static {
System.out.println("main方法类静态代码块的初始化");
}
public static void main(String[] args) throws ClassNotFoundException {
//主动引用
/**
* 当检测到父类没有被加载时,会先加载父类
*/
Sun sun = new Sun();
//利用反射
Class.forName("reflection.Sun");
//不会触发子类加载
// 利用子类去调用父类的变量
System.out.println(Sun.name);
//创建数组
/**
* array 会在常量池中找到(无需加载类)
* Sun[5] 只是分配了 5块空间,并没有初始化。
*/
Sun[] array = new Sun[5];
//调用类中的常量也不会初始化类
System.out.println(Sun.sum);
}
}
class Father{
static {
System.out.println("Father类静态代码块的初始化");
}
static String name = "father";
}
class Sun extends Father{
static {
System.out.println("Sun类静态代码块的初始化");
}
static final int sum = 10;
}
执行结果:
main方法类静态代码块的初始化
Father类静态代码块的初始化
Sun类静态代码块的初始化
father
10
Process finished with exit code 0
具体可以参照:JVM——类加载器
获取类信息
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @ClassName ReflectionTest_4
* @Description 获得类的信息
* @Author SkySong
* @Date 2020-09-28 21:23
*/
public class ReflectionTest_4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("reflection.User");
//获得类的名字
System.out.println(c1.getName());//包名 + 类名
System.out.println(c1.getSimpleName());//类名
//获得类的属性
Field[] fields = c1.getFields();
for (Field field:fields){
//无法打印出来,,因为getFields() 方法只能找到 public 的属性
System.out.println(field.getName());
}
//getDeclaredFields() 方法可以找到 所有权限的 属性
Field[] fields1 = c1.getDeclaredFields();
for (Field field:fields1){
System.out.println(field);
}
//获得指定属性
System.out.println(c1.getDeclaredField("name").getName());
/**
* =========================================================
*/
System.out.println("========================================");
//获得类的方法
/**
* 获得类 及其 父类的 全部 public 方法
*/
Method[] methods = c1.getMethods();
for (Method method:methods){
System.out.println("正常的:"+ method);
}
/**
* 获得 本类的 所有方法
*/
Method[] declaredMethods = c1.getDeclaredMethods();
for (Method method:declaredMethods){
System.out.println("declare的:"+method);
}
System.out.println("==========================================");
//获得指定方法
/**
* 需要将参数类型也传入,是因为方法有重载的特性。(需要参数列表来做区分)
*/
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
//获得所有的构造器
System.out.println("===========================================");
/**
* 获得 本类的 public 构造器方法
*/
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor:constructors){
System.out.println(constructor);
}
/**
* 获得 本类的 所有 构造器方法
*/
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("#"+ declaredConstructor);
}
System.out.println();
//获得指定的构造器
Constructor constructor = c1.getConstructor(null);
System.out.println(constructor);
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, String.class);
System.out.println("#"+ declaredConstructor);
}
}
执行结果:
reflection.User
User
private java.lang.String reflection.User.name
private int reflection.User.age
private java.lang.String reflection.User.career
name
========================================
正常的:public java.lang.String reflection.User.toString()
正常的:public java.lang.String reflection.User.getName()
正常的:public void reflection.User.setName(java.lang.String)
正常的:public java.lang.String reflection.User.getCareer()
正常的:public int reflection.User.getAge()
正常的:public void reflection.User.setAge(int)
正常的:public void reflection.User.setCareer(java.lang.String)
正常的:public final void java.lang.Object.wait() throws java.lang.InterruptedException
正常的:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
正常的:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
正常的:public boolean java.lang.Object.equals(java.lang.Object)
正常的:public native int java.lang.Object.hashCode()
正常的:public final native java.lang.Class java.lang.Object.getClass()
正常的:public final native void java.lang.Object.notify()
正常的:public final native void java.lang.Object.notifyAll()
declare的:public java.lang.String reflection.User.toString()
declare的:public java.lang.String reflection.User.getName()
declare的:public void reflection.User.setName(java.lang.String)
declare的:public java.lang.String reflection.User.getCareer()
declare的:private void reflection.User.privateMethod()
declare的:public int reflection.User.getAge()
declare的:public void reflection.User.setAge(int)
declare的:public void reflection.User.setCareer(java.lang.String)
==========================================
public java.lang.String reflection.User.getName()
public void reflection.User.setName(java.lang.String)
===========================================
public reflection.User()
public reflection.User(java.lang.String,int,java.lang.String)
#public reflection.User()
#public reflection.User(java.lang.String,int,java.lang.String)
public reflection.User()
#public reflection.User(java.lang.String,int,java.lang.String)
Process finished with exit code 0
构建对象
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @ClassName ReflectionTest_5
* @Description
* @Author SkySong
* @Date 2020-09-28 23:05
*/
public class ReflectionTest_5 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得class对象
Class<?> userClass = Class.forName("reflection.User");
//创建一个对象
User user = (User) userClass.newInstance();//本质上是掉用无参构造器
System.out.println(user);
//利用构造器 创建对象
Constructor<?> userClassDeclaredConstructor = userClass.getDeclaredConstructor(String.class, int.class, String.class);
User user1 = (User) userClassDeclaredConstructor.newInstance("Sky", 23, "god");
System.out.println(user1);
//通过反射调用方法
User user2 = (User) userClass.newInstance();
Method setName = userClass.getMethod("setName", String.class);
//invoke():激活
//invoke(对象,"方法对应的参数")
setName.invoke(user2,"btg");
System.out.println(user2.getName());
//通过反射操作属性
User user3 = (User) userClass.newInstance();
Field name = userClass.getDeclaredField("name");
/**
* 不能直接操作私有属性,需要关闭他的安全检测
* 可以提高反射的性能
*/
name.setAccessible(true);//取消他的安全检测
name.set(user3,"边边");
System.out.println(user3);
}
}
执行结果:
User{name=‘null’, age=0, career=‘null’}
User{name=‘Sky’, age=23, career=‘god’}
btg
User{name=‘边边’, age=0, career=‘null’}
Process finished with exit code 0
附上User类:
(全程都是用的这个 User类)
package reflection;
/**
* @ClassName User
* @Description
* @Author SkySong
* @Date 2020-09-28 21:25
*/
public class User {
private String name;
private int age;
private String career;//职业
//无参构造
public User(){}
public User(String name, int age, String career) {
this.name = name;
this.age = age;
this.career = career;
}
private void privateMethod(){
System.out.println("这是一个私有方法!!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCareer() {
return career;
}
public void setCareer(String career) {
this.career = career;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", career='" + career + '\'' +
'}';
}
}
性能分析( setAccessible(true) )
setAccessible(true) 是关闭安全检测。可以提高反射的构建效率。
package reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @ClassName ReflectionTest_6
* @Description 性能分析
* @Author SkySong
* @Date 2020-09-29 21:56
*/
public class ReflectionTest_6 {
//直接获取对象
public static void test_1(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("直接获取对象,getName()方法跑10亿次所需:"+(endTime-startTime)+"ms");
}
//反射获取对象
public static void test_2() throws Exception {
Class<?> userClass = Class.forName("reflection.User");
User user = (User) userClass.newInstance();
Method getName = userClass.getDeclaredMethod("getName");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime = System.currentTimeMillis();
System.out.println("反射获取对象,getName()方法跑10亿次所需:"+(endTime-startTime)+"ms");
}
//反射获取对象 (关闭安全检测)—— setAccessible(true)
public static void test_3() throws Exception {
Class<?> userClass = Class.forName("reflection.User");
User user = (User) userClass.newInstance();
Method getName = userClass.getDeclaredMethod("getName");
getName.setAccessible(true);//关闭安全检测
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime = System.currentTimeMillis();
System.out.println("反射获取对象(关闭安全检测),getName()方法跑10亿次所需:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws Exception {
test_1();
test_2();
test_3();
}
}
执行结果:
直接获取对象,getName()方法跑10亿次所需:5ms
反射获取对象,getName()方法跑10亿次所需:3015ms
反射获取对象(关闭安全检测),getName()方法跑10亿次所需:1370ms
Process finished with exit code 0
反射获取注解
package reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @ClassName ReflectionTest_7
* @Description
* @Author SkySong
* @Date 2020-09-29 23:23
*/
public class ReflectionTest_7 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
//这里的泛型化 可以避免 后续的强转
Class<?> studentClass = Class.forName("reflection.Student");
//通过反射获得注解
Annotation[] annotations = studentClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解 value 的值
table annotationValue = studentClass.getAnnotation(table.class);
String table = annotationValue.table();
System.out.println(table);
//获得指定属性的 注解值
Field name = studentClass.getDeclaredField("name");
field f = name.getAnnotation(field.class);
System.out.println(f.column());
System.out.println(f.length());
System.out.println(f.type());
}
}
/**
* 类(Class)的注解
*/
//运行时
@Retention(RetentionPolicy.RUNTIME)
//TYPE(class) METHOD(方法) FIELD(属性)
@Target({ElementType.TYPE})
@interface table{
String table();
}
/**
* 属性的注解
*/
@Retention(RetentionPolicy.RUNTIME)
//TYPE(class) METHOD(方法) FIELD(属性)
@Target({ElementType.FIELD})
@interface field{
String column();
String type();
int length();
}
@table(table = "db_student")
class Student{
@field(column = "student_id",type = "int",length = 10)
private int id;
@field(column = "student_name",type = "varchar2",length = 32)
private String name;
@field(column = "student_age",type = "int",length = 10)
private int age;
public Student(){}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
执行结果:
@reflection.table(table=db_student)
db_student
student_name
32
varchar2
Process finished with exit code 0
总结
反射是通过 " 非直接手段 " 去获取类的信息,我们把 类 比作 印刷 对象 的 模子,有了这个模子,我们便可以 印刷 对象 。
Java有了反射机制,就有了动态性。但这也降低了安全性。