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. 【收藏】制作艺术二维码,用 Stable Diffusion 就行!

    [收藏]Stable Diffusion 制作光影文字效果 https://www.cnblogs.com/Serverless/p/17620406.html 基于函数计算FC 快捷部署 Stabl ...

  2. 如何通过canvas实现电子签名

    想要实现一个电子签名,可以支持鼠标签名,还能类似书法效果线条有粗有细,同时可以导出成图片. 一.实现连贯的划线 1)首先需要注册鼠标下压.鼠标放开.鼠标移出和鼠标移动事件,通过鼠标下压赋值downFl ...

  3. excel常用函数-countif与countifs

    countif用于一个条件的计数 countifs用于多个条件的计数,用法比较简单,如下: 注多条件计数的说明 :=COUNTIFS(条件匹配查询区域1,条件1,条件匹配查询区域2,条件2,以此类推. ...

  4. React技巧之设置input值

    原文链接:https://bobbyhadz.com/blog/react-set-input-value-on-button-click 作者:Borislav Hadzhiev 正文从这开始~ 总 ...

  5. 【Python】.format用法

    格式化打印 print("***{}".format(args))   格式化转换 module = "skull" print "MODULE_{} ...

  6. NewStarCTF 2023 公开赛道 WEEK4|CRYPTO WP

    RSA Variation II 1.题目信息 提示:"Schmidt Samoa" 附件信息 from secret import flag from Crypto.Util.n ...

  7. Mygin实现动态路由

    本篇是Mygin的第四篇 目的 使用 Trie 树实现动态路由解析. 参数绑定 前缀树 本篇比前几篇要复杂一点,原来的路由是用map实现,索引非常高效,但是有一个弊端,键值对的存储的方式,只能用来索引 ...

  8. 【中介者模式(Mediator)】使用Java实现中介者模式

    引言 中介者,何为中介者,顾名思义就是我们的在处理A和B之间的关系的时候,引入一个中间人,来处理这两者之间的关系,例如生活中我们需要去租房,买房,都会有中介,来处理房东和租客之间的协调关系,这个就是中 ...

  9. [转帖]shell编程:shell变量的核心基础知识与实战(二)

    shell编程:shell变量的核心基础知识与实战(二) https://www.cnblogs.com/luoahong/articles/9152039.html Shell 变量类型 变量可以分 ...

  10. [转帖]安全技术和iptables防火墙

    目录 安全技术 Netfilter 防火墙工具介绍 iptables firewalld nftables iptables的组成概述 netfilter与iptables关系 iptables的四表 ...