黑马程序员_Java反射机制

一切的操作都将使用Object完成,类,数组的引用都可以使用Object来接收

1,认识Class类

以前要是想知道一个类中的属性,成员变量,方法等等的信息的话,需要通过new这个类的对象才能得到这些信息,但是在Java中,也允许一个实例化对象找到一个类的完整的信息,这个类就是Class类,Class类是继承Object类的.

正常方式:  引入需要的"包.类"名称 >取得实例化对象

反射方式:  实例化对象>得到完整的"包.类"名称

getClass()这个方法的返回值是Class类,实际上该类是Java反射的源头

在Class类中没有定义构造方法,那么得到Class类对象的方法有3种:

(1)使用forName()的静态方法实例化对象  (2) 类.class  (3)对象.getClass()

package cn.reflect;

class Demo{

}
public class RefDemo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("cn.reflect.Demo");
        Class c2 = Demo.class;
        Class c3 = new Demo().getClass();
        System.out.println("类名称:"+c1.getName());
        System.out.println("类名称:"+c2);
        System.out.println("类名称:"+c3);
    }
}

3种实例化Class对象的方式是一样的,但是forName()这个方式比较常用,它只需要传入类所在的位置的名称的字符串参数就可以了,这样使程序具有很大的灵活性.

2,Class类的使用

2.1通过无参构造函数实例化对象

Class类在开发中最常用的是,利用forName这个方法,传入完整的包.类的路径的字符串形式,来实例化一个类的对象

想要通过Class本身来实例化其他类的对象,则可以使用Class类中的newInstance()方法来完成,但是要保证被实例化的类中存在这一个无参的构造方法

(1)forName传入需要实例化的类的完整包.类名称

(2)使用newInstance()方法,是实例化需要被实例化的对象,需要强转

package cn.reflect;

class Person{
    private String name;
    private int age;
    public Person(){

    }//被实例化的对象必须存在无参构造方法
    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 class RefInstance {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class clazz = Class.forName("cn.reflect.Person");
        Person p = (Person)clazz.newInstance();
        p.setName("wjd");
        p.setAge(25);
        System.out.println("name:"+p.getName()+"  age:"+p.getAge());//name:wjd  age:25
    }

}

上述代码中,Person类并没有new一个新的对象,而是通过Class类,来完成了对Person类中的属性的访问.一般做在使用Class类来实例化对象时,一定要在类中编写无参的构造方法

2.2调用有参构造实例化对象

(1)通过Class类中的getConstructors()取得本类中的所有的构造方法

(2)向构造方法中传递一个对象数组中去,里面包含了构造方法是所需的各个参数

(3)通过Constructor实例化对象

package cn.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class Worker{
    private String name;
    private int age;
    public Worker(String name,int age){
        this.setName(name);
        this.setAge(age);
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }
}
public class InstanceDemo01 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class c = Class.forName("cn.reflect.Worker");
        Constructor[] con = c.getConstructors();
        Worker worker = (Worker)con[0].newInstance("吴杰栋",25);//Worker中构造方法中有参数的,这里实例化的时候传参数,注意顺序,只有一个构造函数,所以数组中的0就可以
        System.out.println("age:"+worker.getAge() +" name:"+ worker.getName());
    }

}

在上述代码中,newInstance()方法是Constructor类中的, 查看API可以发现这个方法中传入的参数都是对象,25其实是Integer对象(在使用是进行了自动拆箱)

在java类中是有可能存在多个构造函数的,它们只是构造函数中的参数类型不同而已,在API中,查阅到Class类中newIntance()这个类只能获取到带有无参构造函数的对象,那么带有参数的构造函数的时候,我们该如何获取该类的对象呢?

(1),构造函数没有参数的时候,产生该类对象,直接通过Class类中的newIntance()来获取

(2).构造函数有参数的时候,通过Class类中getConstructor()方法,在方法中传入构造函数参数类型的class文件,返回值是一个Constructor对象,查阅API发现在Constructor这个类中,也有一个带这参数类型的newIntance的方法,这样就能获取到带有参数类型的构造函数的类的对象了

package cn.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//拿Person类中的构造函数
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //createNewObject();
        createNewObject_2();
    }

    public static void createNewObject_2() throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        String name = "cn.bean.Person";
        Class<?> clazz = Class.forName(name);
        //获取到了Person中带有参数类型的构造方法
        Constructor<?> con = clazz.getConstructor(int.class,String.class);
        //这里通过constructor类中的方法来初始化类
        Object obj = con.newInstance(23,"wjd");
    }

    public static void createNewObject() throws Exception{
        String name = "cn.bean.Person";
        //找寻该文件的类文件并加载进内存,并产生class对象
        Class<?> clazz = Class.forName(name);
        //产生该类的对象
        Object obj = clazz.newInstance();
    }
}

 

3,反射的应用---得到类的属性

在反射中得到一个类的完成结构的话,使用到java.lang.reflect包中的以下几个类

(1) Constructor:表示类中的构造方法 (2)Field:表示类中的属性  (3)Method:表示类中的方法

Constructor类中常用的方法


序号


方法


描述


1

public int getModifiers() 得到构造函数的修饰符

2

public String getName() 得到构造函数的名称

3

public Class<?>[] getParameterTypes() 得到构造函数中的参数类型

4

public String toString() 返回此构造函数的信息

5

public T newInstance(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException 向构造函数中传入参数,实例化对象,就是需要拿到有参数构造函数的类的对象的时候,就需要用到这个

Field类中常用的方法


序号


方法


描述

1 public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException 得到一个对象中属性的内容
2 public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException 设置指定对象中属性的具体内容
3 public int getModifiers() 得到属性的修饰符
4 public String getName() 返回此属性的名称
5 public String toString() 返回此Field类的信息
6 public void setAccessible(boolean flag) throws SecurityException 设置一个属性是否被外部访问(需要访问私有属性需要用这个方法true一下)暴力访问
7 public static void setAccessible(AccessibleObject[] array, boolean flag) throws SecurityException 设置一组属性是否被外部访问

Method类中常用的方法

序号 方法 描述
1 public int getModifiers() 得到方法的访问修饰符
2 public String getName() 得到方法的名称
3 public Class<?>[] getParameterTypes() 得到方法的全部参数类型
4 public Class<?> getReturnType() 得到方法的全部返回值类型
5 public Class<?>[] getExceptionTypes() 得到一个方法全部抛出的类型
6 public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException 当通过反射得到类的对象,类的方法的名称,方法中的参数的时候,用这个方法,我们就能完美的运行该类

这三个类都是AccessibleObject类的子类

以上三个类基本覆盖了反射所需要用到的类包括类中的方法,必须要熟练记忆

在反射操作中,得到一个类中的全部属性,有两种不同的操作

(1)得到实现的接口或者父类中的公共属性     在Class类中的getFields()方法

(2)得到本类中的所有属性,包括私有属性      在Class类中的getDeclaredFields()

根据以前学过的知识,要想操作一个类中的属性,肯定得要先得到一个类的对象,那么在反射中,也不例外,也需要通过newIntance()来得到一个类的对象,这样才能去取得类中的属性

总之你想得到我的属性,必须给我对象

package cn.reflect;

import java.lang.reflect.Field;

//拿Person类中的字段
public class ReflectDemo3 {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        getField();
    }
//拿到字节码文件的中的字段
    public static void getField() throws Exception {
        Class<?> clazz = Class.forName("cn.bean.Person");
        //拿到Person类中的age对象,返回的是一个Field的对象
    //Field f = clazz.getField("age");//只能获取共有的的
        Field field = clazz.getDeclaredField("age");//可以获取本类.包含私有
        //对私有的属性,取消其权限的检查,暴力访问
        field.setAccessible(true);
        //设置属性的时候,必须要用对象来设置属性,所以必须先弄个对象出来
        Object obj = clazz.newInstance();
        field.set(obj, 23);
        Object o = field.get(obj);
        System.out.println(o);
    }

}

 

4,反射的应用---得到类中的方法

得到类中的方法,是使用Class类中的getMethod()方法,此方法返回的是一个Method类的对象数组

需要运行一个类

(1)需要先得到该类的方法,方法中的参数的class对象

(2)然后得到该类的对象

(3)调用Method中的invoke方法,将对象,和方法的参数传入该方法

package cn.reflect;

import java.lang.reflect.Method;

//获取Person类中的方法
public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
    //    getMethod();
        getMethod_2();
    }

    public static void getMethod_2() throws Exception {
        Class<?> clazz = Class.forName("cn.bean.Person");
        Method method = clazz.getMethod("paramMethod", String.class,int.class);
        //方法要运行起来,也需要对象的支持,所以要造个对象出来
        Object obj = clazz.newInstance();
        //Method中有个方法,能传入对象和方法,这样的话,方法就能完美的运行起来了
        method.invoke(obj, "wjd",23);
    }

    public static void getMethod() throws Exception {
        Class<?> clazz = Class.forName("cn.bean.Person");
        Method[] methods = clazz.getMethods();//这个获取的都是共有的方法
        methods = clazz.getDeclaredMethods();//只能获取本类中的方法,但是包含了私有的方法
        for(Method method : methods){
            System.out.println(method);
        }
    }
}

5,反射的应用---得到类中的的字段(暴力访问的话,可以得到类中的私有字段)

package cn.reflect;

import java.lang.reflect.Field;

//拿Person类中的字段
public class ReflectDemo3 {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        getField();
    }
//拿到字节码文件的中的字段
    public static void getField() throws Exception {
        Class<?> clazz = Class.forName("cn.bean.Person");
        //拿到Person类中的age对象,返回的是一个Field的对象
    //Field f = clazz.getField("age");//只能获取共有的的
        Field field = clazz.getDeclaredField("age");//可以获取本类.包含私有
        //对私有的属性,取消其权限的检查,暴力访问
        field.setAccessible(true);
        //设置属性的时候,必须要用对象来设置属性,所以必须先弄个对象出来
        Object obj = clazz.newInstance();
        field.set(obj, 23);
        Object o = field.get(obj);
        System.out.println(o);
    }

}

黑马程序员_Java反射机制,布布扣,bubuko.com

时间: 2024-10-12 02:15:26

黑马程序员_Java反射机制的相关文章

黑马程序员---java反射机制的实现原理

------- android培训.java培训.期待与您交流! ---------- 反射机制就是java语言在运行时拥有一项自观的能力. 通过这种能力可以彻底的了解自身的情况为下一步的动作做准备. 下面具体介绍一下java的反射机制.这里你将颠覆原来对java的理解. Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method: 其中class代表的时类对象, Constructor-类的构造器对象, Field-类的属性对象, Method-类的方

黑马程序员___java反射机制

 ----------- android培训.java培训.java学习型技术博客.期待与您交流! --------- Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method:其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象.通过这四个对象我们可以粗略的看到一个类的各个组 成部分.Class:程序运行时,java运行时系统会对所有的对象进行运行时类型的处理.这项信息记录了每个

黑马程序员---Java反射机制学习

由现在这个时间补上反射机制的学习笔记,本想报20期的JavaEE班,无奈真担心自己过不去,所以这段时间,一直的复习现在改报21期的吧!! 准备知识:一 1.Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method:    其中class代表的时类对象,    Constructor-类的构造器对象,    Field-类的属性对象,    Method-类的方法对象. 2.在Java中,每个class都有一个相应的Class对象.也就是说,当我们编写一

黑马程序员_java反射的简单使用

反射概述: 一个已经写好的应用程序,后期要添加新功能,但一般无法获取该应用程序的源码,无法直接在该应用程序中用new创建对象,该怎么办?既然子类不确定,可以通过对外提供配置文件的形式,将不确定的信息存储到配置文件中即可.该应用程序需要在设计时写好如何读取配置文件信息?怎么做呢,先存储指定的子类名,根据具体的名称找该类并进行加载和对象的创建,这些动作都在前期定义软件时写好. 没有类之前就将创建对象的动作完成了.这就是动态的获取指定的类,并使用类中的功能,这就是反射技术.反射技术的出现大大的提高了程

黑马程序员_java 反射

------- android培训.java培训.期待与您交流! ---------- 反射反射只要知道其类对象就可以获得其内部所有属性对象和方法对象.只要知道其类的实例对象就可以获得其类对象.Class类.不同于关键字class,他是对java中各个类的封装,是对所有类的抽象描述,而某一个具体的类就是其实例对象.同一个类的实例对象获得的类类型对象是同一个,是由同一个字节码地址类文件实例化出的对象.类名的获取方法,其实是类类型对象的获取,获取Class的该类实例对象,这个对象!=该类,只是内容为

黑马程序员_Java基础加强(下)

8.注解类 注解相当于一种标记,加了注解就等于打上了某种标记,没加就等于没打特殊标记,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记就去干什么事,标记可以加在包.类.字段.方法,方法的参数以及局部变量上. 注解的应用结构图: 为注解增加属性 定义基本类型的属性和应用属性 在注解类中增加String color(); @MyAnnotation(color = "red") 用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法 MyAnno

黑马程序员_Java高新技术

1  JDK5的新特性 1.1 静态导入       在API中那些不需要new对象的类,可以在类文件的开头,import static java.lang.Math.*;这里把Math中的所有的静态方法都导入了,在类中不需要调用Math类就能直接用Math的方法了 package cn.wjd.staticimport; import static java.lang.Math.*; public class StaticImport { public static void main(Str

黑马程序员_JAVA 基础加强学习笔记

一.面向对象 (一)继承  1.继承的好处: (1) 提高了代码的复用性. (2) 让类与类之间产生了关系,提供了另一个特征多态的前提. 注意: 子类中所有的构造函数都会默认访问父类中的空参数的构造函数,因为每一个子类构造内第一行都有默认的语句super();  如果父类中没有空参数的构造函数,那么子类的构造函数内,必须通过super语句指定要访问的父类中的构造函数. 如果子类构造函数中用this来指定调用子类自己的构造函数,那么被调用的构造函数也一样会访问父类中的构造函数. 2.final特点

黑马程序员_Java基础加强(上)

1.静态导入 静态导入是jdk1.5版本以后出现的新特性,一般是指导入静态方法,如:import static java.lang.System.out 是指导入系统输出的静态方法. 例: import static java.lang.System.out //导入java.lang包下的System类的静态方法out public class StaticImport { public static void main(String[] args) { int x=1; x++; out.p