JAVA反射

一、 Java是静态语言

        在运行期间,如果我们要产生某个类的对象,java虚拟机会检查该类型的Class对象是否被加载。如果未被加载,JVM会根据类的名称找到.class文件并加载它,一旦某个类型的class对象已被加载到内存,就可以用它来产生该类型的所有对象。

面向对象的思维:万事万物皆对象

        

        类似于Class对象: 二、获取字节码的四种方式

public class Test {
    public static void main(String[] args) throws Exception {
        //方式1:通过getClass()方式获取
        Person p = new Person();
        Class c1 = p.getClass();
        //方式2:通过内置class属性
        Class c2 = Person.class;
        //方式3:用的最多 调用Class类提供的静态方法forName
        Class c3 = Class.forName("com.zhaoss.test02.Person");
        //方法4:利用类的加载器
        ClassLoader loader = Test.class.getClassLoader();
        Class c4 = loader.loadClass("com.zhaoss.test02.Person");
    }
}

三、作为Class类的实例的种类

//Class类的具体的实例:
//(1)类:外部类,内部类
Class c1 = Person.class;
//(2) 接口
Class c2 = Comparable.class;
//(3) 注解
Class c3 = Override.class;
//(4) 数组
int[] arr1 = {1,2,3};
Class c4 = arr1.getClass();
int[] arr2 = {4,5,6};
Class c5 = arr2.getClass();
// true -- 同一个维度,同一个元素类型(int),得到的字节码就是同一个
System.out.println(c4==c5);  
//(5) 基础数据类型
Class c6 = int.class;
//(6) void
Class c7 = void.class;

四、获取信息

        定义注释

/*
@Target:定义当前注解能够修饰程序中的哪些元素
@Retention:定义注解的声明周期
*/
@Target({TYPE,FIELD,METHOS,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();//属性
}

parameter  [pəˈræmɪtə(r)] 参数       retention 保留;保持    policy 策略

dafa variable [ˈveəriəbl]  变量  

@MyAnotation(value="hello")
public class Student extends Person implements MyInterface{
    //属性:
    private int sno;//学号
    double height;//身高
    protected double weight;//体重
    public double score;//成绩
    //方法:
    @MyAnnotation(value="himethod")
    public String showInfo(){
        return "我是一名三好学生";
    }
    public String showInfo(int a,int b){
        return "重载方法====我是一名三好学生";
    }
    private void work(){
        System.out.println("我以后会找工作--》成为码农  程序员 程序猿  程序媛");
    }
    void happy(){
        System.out.println("做人最重要的就是开心每一天");
    }
    protected int getSno(){
        return sno;
    }
    //构造器
    public Student(){
        System.out.println("空参构造器");
    }
    private Student(int sno){
        this.sno = sno;
    }
    Student(int sno,double weight){
        this.sno = sno;
        this.weight = weight;
    }
    protected Student(int sno,double height,double weight){
        this.sno = sno;
    }
    @Override
    @MyAnnotation(value="hellomyMethod")
    public void myMethod() {
        System.out.println("我重写了myMethod方法。。");
    }
    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", height=" + height +
                ", weight=" + weight +
                ", score=" + score +
                '}';
    }
}

①获取构造器和实例:

//获取字节码信息
Class cls = Student.calss;
//通过字节码信息获取构造器
//getConstructors只能获取当前运行时类的 被public修饰的构造器
Constructor[] c1 = cls.getConstructors();

//getDeclaredConstructors:获取运行时类的全部修饰符的构造器
//declared [dɪˈkleəd]公开宣布(声明)的
Constructor[] c2 = cls.getDeclaredConstructors();

//获取空参数的构造器 - public
Constructor c3 = cls.getConstructor();

//得到两个参数的有参构造器 -- public
Constructor c4 = cls.getConstructor(double.class, double.class);

//得到一个参数的有参构造器--private
Constructor c5 = cls.getDeclaredConstructor(int.class);

//创建对象
Object o1 = c3.newInstance();

Object o2 = c4.newInstance(180.3, 170.5);

②获取属性,并赋值  field   [fiːld]字段

//getFields:获取运行时类和父类中被public修饰的属性
Field[] fields = cls.getFiedls();

//获取运行时类中的所有属性
cls.getDeclaredFields();

//获取指定属性
cls.getField("score");
cls.getDeclaredField("sno");

//获取属性的修饰符
Modifier.toString(sno.getModifiers());

//属性的数据类型
Class class = sno.getType();
class.getName();

//属性的名字
sno.getName()

//给属性赋值
Field sco = cls.getField("score");
Object obj = cls.newInstance();
sco.set(sco,98);

③ 获取方法和调用方法

//获取运行时类和所有父类中的public的方法,包括Object类的方法
cls.getMethods()

//获取运行时类中的所有方法
cls.getDeclaredMethods();

//获取指定的方法
cls.getMethod("showInfo");
cls.getMethod("showInfo",int.class,int.class);
cls.getDeclaredMethod("work");

//获取方法的具体结构
/* @注解
 * 修饰符 返回值类型 方法名(参数列表) throw XXX{}
*/
//方法名称
work.getName()

//修饰符
work.getModifiers()

//返回值
work.getReturnType()

//参数列表
work.getParameterTypes()

//获取注解 只能获取生命周期是运行时的注解-----RetentionPolicy.RUNTIME
//@Override 声明周期是SOURCE,只编译器,只会在编译器的校验,运行时获取不到
work.getAnnotations()

//获取异常
work.getExceptionTypes()

//调用方法
Object o = cls.newInstance();
work.invork(o);

showInfo.invoke(o,12,45);

④获取类的接口、所在包、注解

//获取运行时类的接口
cls.getInterfaces();

//获取父类的接口
//先得到父类的字节码信息
Class superclass = cls.getSuperclass();
//得到接口
superclass.getInterfaces();

//运行时类所在包
Package aPachage = cls.getPachage();
aPachage.getName();

//获取运行时类的注解
cls.getAnnotations()

五 面试题

① 创建Person的对象,以后用new Person()创建,还是反射创建

        实际上此问题是在问什么情况下会用反射,平时用new即可,运行时才能确定使用的对象,动态性,比如选择微信还是支付宝支付

② 反射是否破坏了面向对象的封装性

        private 修饰的字段,反射可以访问,本质上是破坏了,但不能这么说。比如反射要访问private的字段,可以在定义的时候,直接定义为public。 

        比如女厕所门上贴的是女,但是还是有变态会进去,不能因为有变态,就把门口的女字去掉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值