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. AIO异步通信。BIO同步阻塞式IO, NIO同步非阻塞通信。

    IO 什么是IO? 它是指计算机与外部世界或者一个程序与计算机的其余部分的之间的接口.它对于任何计算机系统都非常关键,因而所有 I/O 的主体实际上是内置在操作系统中的.单独的程序一般是让系统为它们完 ...

  2. SpringCloud学习 系列八、OpenFeign

    系列导航 SpringCloud学习 系列一. 前言-为什么要学习微服务 SpringCloud学习 系列二. 简介 SpringCloud学习 系列三. 创建一个没有使用springCloud的服务 ...

  3. chage详解:liunx账户密码过期时处理

    公司安装elasticSearcher7.10.2版本时提示账户密码过期,可以做以下的处理方式: 一.查看账户的使用情况 chage -l baikang [root@localhost ~]# ch ...

  4. mybatis 源码学习

    本文为博主原创,未经允许不得转载:

  5. QT启动问题--找不到python36.dll-cnblog

    1.报错:找不到python36.dll 2.解决 通过该查询CSDN下载相应的python36.dll放到C:\Windows\System32目录下即可 https://blog.csdn.net ...

  6. python环境 anaconda安装

    官网: https://www.anaconda.com/distribution/#macos 国内镜像: https://mirrors.tuna.tsinghua.edu.cn/anaconda ...

  7. 07 - HTTP

    HTTP 强烈推荐学习:HTTP | MDN 一 .基础概念 请求和响应报文 客户端发送一个请求报文给服务器,服务器根据请求报文中的信息进行处理,并将处理结果放入响应报文中返回给客户端. 请求报文结构 ...

  8. Django-Import-Export插件关于外键的处理

    前言 Django-Import-Export是一款很好用很方便的Django数据导出导入插件,可以和DjangoAdmin管理后台完美集成,只需要少量的代码配置即可方便实现你要的多种格式导出导入,关 ...

  9. [转帖]JVM性能调优工具2之jcmd详解(覆盖全网最全的jcmd命令与说明文档)

    上篇文章里<JVM常用性能调优工具详解1>我们已经探究了jps.jstat等监控工具,以及jinfo.jmap.jstack.jhat等故障排查工具,这里我单独拿出一篇文章,特别介绍jcm ...

  10. [转帖]redis-benchmark的使用总结

    redis-benchmark的使用总结 Redis简介: 测试需求: 测试环境架构 测试工具Redis-benchmark 1 redis-benchmark使用方法 参数的作用 2 测试查看 测试 ...