零基础入门学习Java之注解与反射
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之注解与反射的更多相关文章
- 《零基础入门学习Python》【第一版】视频课后答案第001讲
测试题答案: 0. Python 是什么类型的语言? Python是脚本语言 脚本语言(Scripting language)是电脑编程语言,因此也能让开发者藉以编写出让电脑听命行事的程序.以简单的方 ...
- 零基础入门学习Python(1)--我和Python的第一次亲密接触
前言 最近在学习Python编程语言,于是乎就在网上找资源.其中小甲鱼<零基础入门学习Python>试听了几节课,感觉还挺不错,里面的视频都是免费下载,小甲鱼讲话也挺幽默风趣的,所以呢,就 ...
- 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封装 ...
- 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现
088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...
- 080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则
080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则 本文知识点:单一职责原则 说明:因为时间紧张,本人写博客过程中只是 ...
- 057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和
057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和 本文知识点:求整型数组的数组元素的元素值累加和 案例:求整型数 ...
- 056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用
056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用 本文知识点:数组的实际应用 程序开发中如何应用数组? 程序代码及其运行结果: 不同数据类 ...
- 055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念
055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念 本文知识点:数组的概念 数组的声明创建.初始化 在学习数组的声明创建.初始化前,我们可以和之 ...
- 054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述
054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述 本文知识点:数组概述 为什么要学习数组? 实际问题: 比如我们要对学生的成绩进行排序,一个班级 ...
- 051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1
051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试--debug入门1 本文知识点: 程序调试--debug入门1 程序 ...
随机推荐
- 如何在iOS手机上查看应用日志
引言 在开发iOS应用过程中,查看应用日志是非常重要的一项工作.通过查看日志,我们可以了解应用程序运行时的状态和错误信息,帮助我们进行调试和排查问题.本文将介绍两种方法来查看iOS手机上的应用日志 ...
- 修改elasticsearch默认索引返回数
1. 背景 (1) 客户反映es查询只能返回10000个数据,而需求时返回1.9W个数据,因此需要设置对应索引的默认返回数index.max_result_window (2) 给客户部署的服务以do ...
- SV 接口中的clocking
接口 module可以例化模块,可以例化接口 接口不能例化模块 采样和数据驱动 时钟驱动数据,数据会有延迟,RTL仿真的时候,不会仿真出这个延时;RTL仿真的时候,不会仿真出寄存器的延时;只有在门级仿 ...
- 【rt-thread】Kconfig文件添加子Kconfig文件时是以顶级Kconfig所在目录为当前路径的
示例如下 顶级Kconfig文件所在目录 子级Kconfig文件所在目录 子级Kconfig文件添加次子级Kconfig文件,以顶级目录为当前路径依次写出次子级Kconfig文件所在目录
- [转帖]TiDB Lightning 监控告警
https://docs.pingcap.com/zh/tidb/v6.5/monitor-tidb-lightning tidb-lightning 支持使用 Prometheus 采集监控指标 ( ...
- [转帖]Nginx中if语句中的判断条件
https://www.cnblogs.com/songxingzhu/p/6382007.html 一.if语句中的判断条件(nginx) 1.正则表达式匹配: ==:等值比较; ~:与指定正则表达 ...
- 关于JVM指针压缩性能的研究
关于JVM指针压缩性能的研究 摘要 JVM的内存对消最小是 8bytes 所以32G内存的情况下可以使用 32位的指针就可以了. 32位就是4G 在乘以最小的内存extent 8 bytes 的出来可 ...
- 解决node与npm版本不一致,出现npm WARN npm npm does not support Node.js v15.14.0
出现node与npm版本不一致 今天我升级了node之后,出现的了如下信息 npm WARN npm You should probably upgrade to a newer version of ...
- vue获取子组件的实例$el、$attrs和inheritAttrs的使用
我的需求 有些时候,我们需要获取组件的DOM元素 有些小伙伴会说,这还不简单 直接使用this.$ref.xx不就可以了吗 我们来看一下,是不是我们想的那样简单 组件内容 <template&g ...
- 任意文件下载包含https的图片
使用a标签进行下载 <a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ. ...