零基础入门学习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类并未初始化,变先用类加载器去初始化类,调用其中的
主动引用的时候类会被加载,被动引用的时候类不会被加载
-
反射、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();
}