Java反射

Java的程序为什么能在JVM虚拟机中跑起来?接下来将深入探讨下Java虚拟机类加载的机制

1.类的加载

整个Java内存可以分为三大板块

  • 堆

    • 存放new的数组、对象等
  • 栈

    • 存基本变量类型
    • 引用对象的变量
  • 方法去(特殊的堆)

    • 可以被线程共享
    • 包含了class以及static变量

类的加载分为三大板块:加载>链接>初始化

加载:将编译后的class文件加载到内存中,并且把当前类的静态数据转换到方法区的运行数据结构,生成一个这个类的Class的对象

链接:将二进制代码合并到JVM运状态之中的过程

​ 1.确保类信息合法

​ 2.为类变量static分配内存并且赋值

​ 3.将常量替换为地址引用

初始化:执行类构造器的clinit()方法,编译器执行方法的时会自动收集类中所有类变量的赋值以及静态代码块中的语句。初始化子类时发现父没初始化会先初始化父类,虚拟机会保证每个类的()方法在多线程环境中被正确加锁和同步

ps:是因为要初始化才有的clinit()方法

package com.starvk.Test;

public class demo01 {
public static void main(String[] args) { Test test = new Test();
System.out.println(test.m);
}
} class Father{
static int n = 10;
static {
n = 100;
System.out.println("Father");
}
} class Test extends Father{ static int m =100; static{
System.out.println("static");
m = 20;
} public Test(){
System.out.println("Test");
} public Test(int m){ } }

在上诉代码中,程序在加载阶段会先把class文件加载到内存中,并且在类的相关信息创建到方法去内,在堆中生成类的Class类

加载阶段是类加载过程的第一个阶段。在这个阶段,JVM 的主要目的是将字节码从各个位置(网络、磁盘等)转化为二进制字节流加载到内存中,接着会为这个类在 JVM 的方法区创建一个对应的 Class 对象,这个 Class 对象就是这个类各种数据的访问入口。

加载阶段完成之后,链接阶段会检测代码的合法性,正式的为类变量分配内存并且初始化,这些内存会在方法区中分配

链接阶段完成后,JVM虚拟机会最先执行main方法,在main方法中

Test test = new Test();

JVM发现Test类并未初始化,变先用类加载器去初始化类,调用其中的()方法就行初始化,然后在堆中找到Test对象的Clss,new出一个Test对象在堆中把堆Test对象的引用放在栈中

主动引用的时候类会被加载,被动引用的时候类不会被加载

  • 反射、new的类都会被加载

  • 调用父类的静态方法以及变量、创建类的数组不会被加载

2.反射详解

Java是静态的高级编程语言,但也是准动态的高级编程语言

Java基于反射的机制,使得自己能动态的创建对象,并且获取和调用其中的方法

什么是反射?在正常编写代码中,通过创建类的对象引用从而操控对象,而反射则恰恰相反,通过创建的对象的引用而获取类,从而创建另外一个对象,Java中的反射机制使得Java能动态的创建对象

在类的加载中,可以了解到每个对象都有自己对应的Class类,可以通过obj.getClass()方法去获取这个Class类的对象,在上代码之前,应先创建类似如下代码

package com.starvk.Test01;

public class UserDemo {

    static private int nowId = 0;
private int id = 0;
private String name;
private int age;
private String sex;
public int uid = 0; public UserDemo( String name, int age, String sex) {
this.id = ++nowId;
this.name = name;
this.age = age;
this.sex = sex;
} public UserDemo() {
this.id = ++nowId;
this.name = "";
this.age = 0;
this.sex = null;
} private void Say(){
System.out.println("hello");
} 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;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public String toString() {
return "UserDemo{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}

只是一个简单的user类

package com.starvk.Test01;

public class Demo01 {
public static void main(String[] args) {
UserDemo user = new UserDemo("ZhanSan",15,"boy");
Class c1 = user.getClass(); //class com.starvk.Test01.UserDemo
System.out.println(c1);
}
}

这好像并没有什么用 别着急

除了使用getClass以外,还可以使用Class.getName()方法通过类的路径来获取类的Class

package com.starvk.Test01;

public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("com.starvk.Test01.UserDemo");
System.out.println(c1);
}
}

但这又有什么用呢? 或许可以通过class类来创建其对象

package com.starvk.Test01;

public class Demo01 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.starvk.Test01.UserDemo");
UserDemo user = (UserDemo)c1.getConstructor(String.class,int.class,String.class).newInstance("ZhanSan",16,"boy");
System.out.println(user); }
}

在上述代码中,通过getConstructor()方法轻松获得UserDemo这个类的一个有参构造器

(获取构造器的时候要说明是哪个参数的构造器,否则运行时会抛出异常,无参构造器要在类先声明才能定义)

当然也可以查看这个类中的所有构造器

package com.starvk.Test01;

import java.lang.reflect.Constructor;

public class Demo01 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.starvk.Test01.UserDemo");
Constructor[] constructs = c1.getDeclaredConstructors();
for(Constructor con : constructs){
System.out.println(con);
}
}
}

获取类的所有方法

package com.starvk.Test01;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method; public class Demo01 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.starvk.Test01.UserDemo");
Method[] methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}

获取类的所有属性

package com.starvk.Test01;

import java.lang.reflect.Field;

public class Demo01 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.starvk.Test01.UserDemo");
Field[] fields = c1.getDeclaredFields(); for (Field field : fields) {
System.out.println(field);
}
}
}

利用反射操作公共的类方法

package com.starvk.Test01;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; public class Demo01 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.starvk.Test01.UserDemo"); Constructor constructor = c1.getConstructor(String.class, int.class, String.class);
UserDemo user1 = (UserDemo)constructor.newInstance("XiaoMing",17,"boy"); Method say = c1.getMethod("setName", String.class); //这样可以
say.invoke(user1,"XiaoZhang");
System.out.println(user1.getName()); user1.setName("XiaoLi");//这样也可以
System.out.println(user1.getName());
}
}

利用反射操作私有类变量

package com.starvk.Test01;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; public class Demo01 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.starvk.Test01.UserDemo"); Constructor constructor = c1.getConstructor(String.class, int.class, String.class);
UserDemo user1 = (UserDemo)constructor.newInstance("XiaoMing",17,"boy"); Field name = c1.getDeclaredField("name"); //获取私有属性
name.setAccessible(true); //开启高权限
name.set(user1,"HaHa");//修改
System.out.println(user1.getName()); }
}

通过反射获取注解信息

package com.starvk.Test02;

import java.lang.annotation.*;
import java.lang.reflect.Field; public class Demo01 {
public static void main(String[] args) throws NoSuchFieldException { //获取方法的注解
Annotation[] annotations = Student.class.getAnnotations();
Table annotation = Student.class.getAnnotation(Table.class);
System.out.println(annotation.value()); //获取属性的注解
Field name = Student.class.getDeclaredField("name");
key annotation1 = name.getAnnotation(key.class);
System.out.println(annotation1.length());
System.out.println(annotation1.type()); }
} @Table(value = "Student")
class Student{ private static int idTotal = 0;
@key(type="int",length = 5)
private int id;
@key(type="String",length = 10)
private String name;
@key(type="int",length = 3)
private int age;
@key(type="int",length = 3)
private int score; @Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
} public static int getIdTotal() {
return idTotal;
} public static void setIdTotal(int idTotal) {
Student.idTotal = idTotal;
} 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;
} public int getScore() {
return score;
} public void setScore(int score) {
this.score = score;
} public Student(String name, int age, int score) {
this.id = ++idTotal;
this.name = name;
this.age = age;
this.score = score;
} public Student() {
this.id = ++idTotal;
this.name = "null";
this.age = 0;
this.score = 0;
}
} @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
} @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface key{
String type();
int length();
}

零基础入门学习Java之注解与反射的更多相关文章

  1. 《零基础入门学习Python》【第一版】视频课后答案第001讲

    测试题答案: 0. Python 是什么类型的语言? Python是脚本语言 脚本语言(Scripting language)是电脑编程语言,因此也能让开发者藉以编写出让电脑听命行事的程序.以简单的方 ...

  2. 零基础入门学习Python(1)--我和Python的第一次亲密接触

    前言 最近在学习Python编程语言,于是乎就在网上找资源.其中小甲鱼<零基础入门学习Python>试听了几节课,感觉还挺不错,里面的视频都是免费下载,小甲鱼讲话也挺幽默风趣的,所以呢,就 ...

  3. 093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 03 static关键字(下)

    093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  4. 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现

    088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...

  5. 080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则

    080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则 本文知识点:单一职责原则 说明:因为时间紧张,本人写博客过程中只是 ...

  6. 057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和

    057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和 本文知识点:求整型数组的数组元素的元素值累加和 案例:求整型数 ...

  7. 056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用

    056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用 本文知识点:数组的实际应用 程序开发中如何应用数组? 程序代码及其运行结果: 不同数据类 ...

  8. 055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念

    055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念 本文知识点:数组的概念 数组的声明创建.初始化 在学习数组的声明创建.初始化前,我们可以和之 ...

  9. 054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述

    054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述 本文知识点:数组概述 为什么要学习数组? 实际问题: 比如我们要对学生的成绩进行排序,一个班级 ...

  10. 051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1

    051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试--debug入门1 本文知识点: 程序调试--debug入门1 程序 ...

随机推荐

  1. KCD技术分享:以SBOM为基础的云原生应用安全治理

    随着越来越多的企业和组织将他们的应用迁移到云上,云原生技术的应用部署和管理正在变得更加灵活和高效,但也相应地引入了一些新的安全风险.2023年4月15日,由云原生计算基金会(CNCF)发起,全球各国当 ...

  2. 深度学习(六)——神经网络的基本骨架:nn.Module的使用

    一.torch.nn简介 官网地址: torch.nn - PyTorch 2.0 documentation 1. torch.nn中的函数简介 Containers:神经网络的骨架 Convolu ...

  3. node-sass安装失败问题

    在node 中安装sass依赖总会出现各种各样的问题,第一次遇见这样的问题 Cached binary found at C:\Users\ltzhouhuan\AppData\Roaming\npm ...

  4. vue-asome-swiper

  5. React报错之The tag is unrecognized in this browser

    正文从这开始~ 总览 当我们使用一个在浏览器中不存在的标签或以小写字母开头的组件名称时,会产生"The tag is unrecognized in this browser"Re ...

  6. 07-verilog & sytem verilog

    一.数据类型 二值逻辑变量 bit 不赋值的时候,变量初始默认为0 x或z的值会转变为0 bit vector--bit矢量 bit [msb,lsb] variable_name = [initia ...

  7. 【收集】C & C++

    序 链接 备注 1 C语言0长度数组(可变数组/柔性数组)详解_CHENG Jian的博客-CSDN博客_0数组   2 C 语言参考 | Microsoft Learn   3 C++ 语言参考 | ...

  8. 【TouchGFX】visual studio 工程中 SIMULATOR 宏定义位置

  9. [转帖]Oracle11g实现只读表方法

    1.1 ALTER TABLE tab_name READ ONLY 参考:https://www.cnblogs.com/chinas/p/8440460.html Oracle 11g开始支持设置 ...

  10. [转帖]vm内核参数之缓存回收drop_caches

    注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4 1.关于drop_caches 通常在内存不足时,我们习惯通过echo 3 > /proc/sys/vm/drop_ ...