反射
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.
什么时候会发生类的初始化
- 类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化main方法所在的类
- new一个对象的类
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射作用
- 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
- 类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中)
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()方法
- 类必须有一个无参数的构造器
- 类的构造器的访问权限需要足够
没有无参的构造器,只要在操作的时候明确的调用类中的构造器并将参数传递进去之后,才可以实例化操作
- 通过Class类的getDeclaredConstructor()取得本类的指定形参类型的构造器
- 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
- 通过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语言访问检查
- 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁调用,设置为true
- 原本无法访问的私有成员也可以访问
获取注解信息
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();
}