Java基础学习Day15--反射机制
今天又没什么业务
今天学习了java的反射机制,javase基础也算是告一段落了
女朋友今天回家了 有点桑心5555o(╥﹏╥)o
1.概念
java反射机制可通过类的全路径名对类进行动态加载实例化,获取类信息及类里面的成员变量,方法,改造方法等;加载完类之后,在堆中就产生了一个Clas类型的对象(一个类只有一个对象),这个对象包含了类的完整结构信息,通过这个对象可以得到类的结构(方法,构造方法,属性,结构)。
2.反射的原理
3.反射的用途:
(1)反编译:.class–>.java
(2)通过反射机制访问java对象的属性,方法,构造方法等
(3)当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
(4)反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。
4.反射的优缺点:
优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:
(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
5.使用
(1)在运行时判断任意一个对象所属的类
(2)在运行时构造任意一个类的对象
(3)在运行时得到任意一个类所具有的成员变量和方法
(4)在运行时调用任意一个对象的成员变量和方法
(5)生成动态代理
6.反射相关类
java.lang.refiect
java.lang.Class:代表一个类
java.lang.refiect.Method:代表类的方法
java.lang.refiect.Field:代表类的成员变量
java.lang.refiect.Constructors:代表类的构造方法
7.Class类分析
(1)class也是类,继承object类
(2)创建类
①传统方式:
/**
* public Class<?> loadClass(String name) throws ClassNotFoundException {
* return loadClass(name, false);
* }
*/
Student student=new Student();
②java反射:
Class aClass = Class.forName(“com.example.content.test.Student”);
对于某个类的class类对象,在内存中只存在一份,因此类只加载一次
③每个类的实例都知道他是由哪个class实例所生成
④通过class对象可以完整地得到一个类的完整结构,通过一系列api
⑤class对象放在堆空间
⑥类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法名,变量等等)
8.Class类的常用方法
//通过类路径获取类
Class aClass = Class.forName("com.example.content.test.Student");
System.out.println(aClass);//显示cla对象,是哪个类的Class对象
System.out.println(aClass.getClass());//运行类型
//得到包名
Package aPackage = aClass.getPackage();
System.out.println(aPackage);
//得到全类名
String className = aClass.getName();
System.out.println(className);
//创建对象实例
Student student = (Student) aClass.getConstructor().newInstance();
System.out.println(student);
//得到属性
Field nameField = aClass.getField("name");
System.out.println(nameField.get(student));
//设置属性
nameField.set(student, "萌萌猫");
System.out.println(nameField.get(student));
//得到所有属性
Field[] fields = aClass.getFields();
System.out.println(fields);
9.获取类对象的几种方式:
(1)Class aClass = Class.forName(“com.example.content.test.Student”);
前提:已知类的全路径,且该类在类路径下,通过此方法获取
应用场景:多用于配置文件,读取类全路径,加载类
(2)Class aClass1 = Student.class();
前提:已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高
应用场景:多用于参数传递,比如通过反射得到对应构造器对象
(3)Class aClass1 = student.getClass();
10.反射的基本使用:
(1)获得Class:主要有三种方法:
①Object–>getClass
②任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
③通过class类的静态方法:forName(String className)(最常用)
(2)判断是否为某个类的示例:
一般的,我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断时候为某个类的实例,他是一个native方法。
(3)创建实例:通过反射来生成对象主要有两种方法:
①使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class;
Object str = c.newInstance();
②先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。
//获取String的Class对象
Class<?> str = String.class;
//通过Class对象获取指定的Constructor构造器对象
Constructor constructor=c.getConstructor(String.class);
//根据构造器创建实例:
Object obj = constructor.newInstance(“hello reflection”);
(4)通过反射获取构造方法并使用:
①批量获取的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
②单个获取的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
③调用构造方法:
Constructor–>newInstance(Object… initargs)
newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:newInstance(Object… initargs) ,使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象,并为之调用。
11.Java中的成员变量分为两种:
一是没有static修饰的,这些成员变量是对象中的成员,称为实例变量。
二是有static修饰的,称为类变量(静态变量)。
类变量和实例变量的区别是:
类变量在内存中只存一份,在程序运行时,系统只为类变量分配一次内存,只进行一次的初始化。在加载类的过程中完成类变量的内存分配。
类变量可以通过类名访问。
实例变量是属于对象中的成员,每创建一个类的对象,就会为实例变量分配一次内存,实例变量在内存中有多个拷贝,分别属于不同对象,他们之间互不影响。
12.类加载:
(1) 加载过程:加载-连接(验证,准备,解析)-初始化
验证:(验证代码是否jvm的规范,文件格式是否正确,元数据验证,字节码验证,符号引用验证)
准备:(为类中定义的变量,默认初始化并分配空间,即静态变量分配内存并设置变量的初始值,通常情况为该数据类型的“零值”。)
解析(解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,此过程伴随着第二阶段验证中符号引用验证,放到jre中,类处于可运行的状态);
初始化(真正执行类中定义的java程序代码)
(2)类加载的两种形式
静态加载:依赖性太强,编译时加载相关的类,如果没有则报错
动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,依赖性不强
13.通过反射创建对象
(1)方式一:调用类中的public修饰的无参构造器
(2)方式二:调用类中的指定构造器
14.注解
元注解:@Target,Retention,@Document,@Inherited
@Target() :描述注解的使用范围
@Retention:就是我们需要告诉编译器我们需要在什么级别保存该注释信息,用于描述注解的生命周期。
@Document:
@Inherited
常用的内置注解:
@Override:修辞方法,表示打算重写超类中的方法声明。
@Deprecated:这个注释可以修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为他很危险或有更好的选择。
@SuperWarnings:这个注解主要是用来抑制警告信息的,我们在写程序时,可能会报很多黄线的警告,但是不影响运行,我们就可以用这个注解来抑制隐藏它。与前俩个注解不同的是我们必须给注解参数才能正确使用他。
明天会更好