首页 > 其他分享 >反射

反射

时间:2023-03-15 10:23:50浏览次数:22  
标签:反射 name System println c1 public out

反射

class类创建方式

package com.zhang.annotation;
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println(person.name);
        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);  //class com.zhang.annotation.Student
        //方式二:forname获得
        Class c2 = Class.forName("com.zhang.annotation.Student");
        //方式三:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3);  //class com.zhang.annotation.Student
        //方式四:基本内置类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);    //int
        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);    //class com.zhang.annotation.Person
    }
}
class Person{
    public String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student(){
        this.name = "学生";
    }
}

类加载内存分析

首先在方法区产生类的一些静态基本数据,加载完成-->类在堆里面产生class对象,在栈里面执行main()方法。链接的时候为类变量(static)分配内存并设置类变量默认初始值,这些内存都在方法区中进行分配,m=0. 在堆里面让A实例化new A(),产生A类的对象,会拿到A类的所有数值,给A类显示赋值,初始化,A执行了clinit()方法,把静态代码块初始值合并,m=300,m=100,所以A.m=100.

什么时候会发生类的初始化

  1. 类的主动引用(一定会发生类的初始化)
    • 当虚拟机启动,先初始化main方法所在的类
    • new一个对象的类
    • 调用类的静态成员(除了final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射作用
    • 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
  2. 类的被动引用(不会发生类的初始化)
    • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
    • 通过数组定义类引用,不会触发此类初始化
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中)
package com.zhang.annotation;
public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //Son son = new Son();  子类和父类都被初始化
        //Class.forName("com.zhang.annotation.Son"); 同上
        //System.out.println(Son.b); 通过子类调用父类中的静态变量。子类没有被初始化,父类被初始化。
        //Son[] array = new Son[5];  儿子的数组,不会引起类的初始化
        System.out.println(Son.M);  //调用子类中常量池 M,不会引起初始化。
    }
}
class Father{
    static int b=2;
    static {
        System.out.println("父类被加载");
    }
}
class Son extends Father{
    static{
        System.out.println("子类被加载");
        m=300;
    }
    static int m=100;
    static final int M=1;
}

类加载器

类加载作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

类缓存:JavaSE类加载器可以按要求查找类,一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。JVM垃圾回收机制可以回收这些Class对象。

获取运行时类的完整结构

package com.zhang.annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.zhang.oop.Coll.Students");
        System.out.println(c1.getName());//获得包名+类名:com.zhang.oop.Coll.Students
        System.out.println(c1.getSimpleName()); //获得类名:Students
//==================================================================
        Field[] fields = c1.getFields();
        for (Field field : fields) { //只能找到public 属性:public int com.zhang.oop.Coll.Students.id
            System.out.println(field);
        }
        Field[] fields1 = c1.getDeclaredFields();
        for (Field field : fields1) {  //找到全部属性
            System.out.println(field);
        }
        Field name = c1.getDeclaredField("name");
        System.out.println(name); //获得指定属性的值:private java.lang.String com.zhang.oop.Coll.Students.name
     //===================================================
        Method[] methods = c1.getMethods();
        for (Method method : methods) { //获得本类及其父类的全部public方法
            System.out.println("正常"+method);
        }
        methods = c1.getDeclaredMethods();
        for (Method method : methods) {  // 获得本类的所有方法
            System.out.println("全部"+method);
        }
        //获得指定方法
        Method getName = c1.getMethod("getName",null);
        Method setAge = c1.getMethod("setAge", int.class);
        System.out.println(getName);//public java.lang.String com.zhang.oop.Coll.Students.getName()
        System.out.println(setAge);//public void com.zhang.oop.Coll.Students.setAge(int)
   //===================================================
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {  //获得public构造器
            System.out.println(constructor);
        }
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {  //获得全部构造器
            System.out.println("#"+constructor);
        }
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);
        System.out.println(declaredConstructor);  //获得指定构造器
    }
}

动态创建对象

有了Class对象,创建类的对象:调用Class对象的newlnstance()方法

  1. 类必须有一个无参数的构造器
  2. 类的构造器的访问权限需要足够

没有无参的构造器,只要在操作的时候明确的调用类中的构造器并将参数传递进去之后,才可以实例化操作

  1. 通过Class类的getDeclaredConstructor()取得本类的指定形参类型的构造器
  2. 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
  3. 通过Constructor实例化对象
package com.zhang.annotation;
import com.zhang.oop.Coll.Students;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Text04 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1 = Class.forName("com.zhang.oop.Coll.Students");  //获得class对象
        Students students = (Students) c1.newInstance();  //构造一个对象,本质调用了类的无参构造器
        System.out.println(students);  //Students{name='null', age=0}
        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class,int.class);
        Students students1 = (Students)constructor.newInstance("zhangsan",20);
        System.out.println(students1);  //Students{name='zhangsan', age=20}
    // ========================================================================
        //通过反射调用普通方法
        Students students2 = (Students) c1.newInstance();  //创建类的对象
        //通过反射获取一个方法
        Method setname = c1.getMethod("setName", String.class);
        //invoke 激活  (对象,“方法的值”)
        setname.invoke(students2,"lisi");
        System.out.println(students2.getName());  //lisi
    //====================================================================
        //通过反射操作属性
        Students students3 = (Students)c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,需要关闭程序的安全检测,属性或者方法或者构造器的setAccessible(true)
        name.setAccessible(true);
        name.set(students3,"wangwu");
        System.out.println(students3.getName());  //wangwu
    }
}

参数值为true则指示反射的对象在使用时应该取消Java语言访问检查

  1. 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁调用,设置为true
  2. 原本无法访问的私有成员也可以访问

获取注解信息

package com.zhang.annotation;
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Text05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //Students student = new Students(1001,20,"zhangsan");
        Class c1 = Class.forName("com.zhang.annotation.Students");
        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation); //@com.zhang.annotation.Tablezhang(value=db_student)
        }
        //获得注解的value值
        Tablezhang tablezhang = (Tablezhang)c1.getAnnotation(Tablezhang.class);
        String values = tablezhang.value();
        System.out.println(values);  //db_student
        //获得类指定的注解
        Field f = c1.getDeclaredField("name");
        Fieldzhang annotation = f.getAnnotation(Fieldzhang.class);
        System.out.println(annotation.columnName()); //db_name
        System.out.println(annotation.type());  //varchar
        System.out.println(annotation.length());  //3
    }
}
@Tablezhang("db_student")
class Students{
    @Fieldzhang(columnName = "db_id",type = "int",length = 10)
    private int id;
    @Fieldzhang(columnName = "db_age",type = "int",length = 10)
    private int age;
    @Fieldzhang(columnName = "db_name",type = "varchar",length = 3)
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Students{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    public Students(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    public Students() {
    }
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablezhang{
    String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldzhang{
    String columnName();
    String type();
    int length();
}

标签:反射,name,System,println,c1,public,out
From: https://www.cnblogs.com/rockz/p/17217547.html

相关文章

  • Python反射机制
    Python反射机制1.Python反射机制反射使得程序具有在运行时动态修改自己的结构和行为的能力,比如导入模块,调用函数等等,这些都是python的反射机制,是一种编程方法,设计模式的......
  • 反射和注解及二者综合案例
    一、反射1、反射概述在java.lang.reflect包是这么描述的:提供类和接口,以获得关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法......
  • Java(单元测试,反射)
    单元测试、反射一、单元测试1.1单元测试快速入门所谓单元测试,就是针对最小的功能单元,编写测试代码对其进行正确性测试。我们想想,咱们之前是怎么进行测试的呢?比如说我......
  • 深入理解ES6--迭代器、生成器、代理、反射、Promise
    迭代器(Iterator)和生成器(Generator)for-of循环及展开运算符…都是针对迭代器的!!!不能使用箭头函数来创建生成器;ES6函数的简写方式可以(只需在函数名前加星号)可迭代对象具有Symbol......
  • java反射
    1.反射机制的概念及作用(原文链接:https://blog.csdn.net/lililuni/article/details/83449088)   JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属......
  • 【转】Golang Reflect反射的使用详解1 --- makeFunc的使用
     转,原文: https://studygolang.com/articles/12300 ---------------------------------- Whatyouarewastingtodayistomorrowforthosewhodiedyesterday......
  • 注解与反射
    注解与反射注解注解Annotation是从JDK5.0开始引入的新技术.Annotation的作用:不是程序本身,可以对程序作出解释.(这一点和注释(comment)没什么区别)可以被其他程序(比......
  • 使用反射拷贝数组
      publicstaticvoidmain(String[]args){    int[]arr={1,2,3};    int[]obj=(int[])goodCopyOf(arr,1);    System.out.prin......
  • C# 反射
    反射是一种在运行时动态获取程序类型信息的技术,它可以用来查找和操作程序中的类型、成员、属性和方法等。·以下是一个简单的利用反射查找、创建对象、调用方法、获取/修......
  • java 反射
    反射1.获取类对象的三种方法publicstaticvoidmethod2()throwsClassNotFoundException{//获取类对象方法1Class<Monkey>c1=Monkey.class;......