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. 看这个视频,4万人学会云上部署 Stable Diffusion

    目前大火的 AIGC 领域中, 除了 ChatGPT,Stable Diffusion 在文生图领域大放异彩,深刻影响着绘画.视频制作等相关领域.<动手吧,开发者>本期活动邀请 B 站知识 ...

  2. java基础-反射-day15

    目录 1. 案例引入 2. Class 的理解 3. 反射的详细使用 4. Class 类都有哪些实例 5. 详细使用 6. 获取属性 7. 获取方法 8 获取类的 接口 注解 所在的包 9. 思考 ...

  3. Object.defineProperty()实现双向数据绑定

    <div id="app"> <input type="text" name="txt" id="txt&quo ...

  4. [转帖]windows10彻底关闭Windows Defender的4种方法

    https://zhuanlan.zhihu.com/p/495107049 Windows Defender是windows10系统自带的杀毒软件.默认情况下它处于打开的状态.大多数第三方的杀毒软件 ...

  5. [转帖]PD Control 使用说明

    https://docs.pingcap.com/zh/tidb/stable/pd-control PD Control 是 PD 的命令行工具,用于获取集群状态信息和调整集群. 安装方式   注意 ...

  6. [转帖]必看!PostgreSQL参数优化

    https://zhuanlan.zhihu.com/p/333201734 前不久,一个朋友所在的公司,业务人员整天都喊慢. 朋友是搞开发的,不是很懂DB,他说他们应用的其实没什么问题,但是就是每天 ...

  7. [转帖]py_innodb_page_info.py工具使用

    目录 一.Linux安装Python3 1. 解压包 2. 安装环境 3. 生成编译脚本 4. 检查python3.10的编译器 5. 建立Python3和pip3的软链 6. 添加到PATH 7.  ...

  8. [转帖]重置 VCSA 6.7 root密码和SSO密码

    问题描述 1.用root用户登录 VMware vCenter Server Appliance虚拟机失败,无法登录 2.vCenter Server Appliance 6.7 U1的root帐户错 ...

  9. [转帖]使用 Crash 工具分析 Linux dump 文件

    前言 Linux 内核(以下简称内核)是一个不与特定进程相关的功能集合,内核的代码很难轻易的在调试器中执行和跟踪.开发者认为,内核如果发生了错误,就不应该继续运行.因此内核发生错误时,它的行为通常被设 ...

  10. [译]深入了解现代web浏览器(一)

    本文是根据Mariko Kosaka在谷歌开发者网站上的系列文章https://developer.chrome.com/blog/inside-browser-part1/ 翻译而来,共有四篇,该篇 ...