Java基础-day18-反射方法应用·暴力反射·内部类

Day19

反射获取方法

getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)

    @Test
    public void getFunction() throws Exception {
        //1.获取目标资源的字节码对象--本方法的参数是类的全路径名,包名.类名
        Class<?> clazz = Class.forName("cn.tedu.reflection.Student");
        //2.获取所有成员方法
        Method[] ms = clazz.getMethods();
        //3.遍历数组,获取每个方法的信息
        for(Method m : ms){
            System.out.println(m.getName());//获取方法名
            Class<?>[] pt = m.getParameterTypes();//获取本方法的参数类型
            System.out.println(Arrays.toString(pt));//打印查看这些参数类型
        }
    }

反射获取成员变量
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)

/注意!!!目前成员变量的修饰符必须是public才能获取到
* 采用默认的修饰符反射获取不到
/

    //5.通过单元测试获取成员变量
    @Test
    public void getFields(){
        //1.获取目标资源对应的字节码对象
        Class<?> clazz = Student.class;

        //2.获取所有成员变量
        /*注意!!!目前成员变量的修饰符必须是public才能获取到
        * 采用默认的修饰符反射获取不到*/
        Field[] fs = clazz.getFields();

        //3.遍历数组,获取每个成员变量对应的信息
        for (Field f: fs){
            System.out.println(f.getName());//获取参数名
            System.out.println(f.getType().getName());//获取变量类型 名
        }
    }

反射新建实例对象
c.newInstance();//执行无参构造创建对象
c.newInstance(666,”海绵宝宝”);//执行含参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法
/方式一:通过字节码对象直接调用newInstance(),触发无参构造来创建对象
* 方式二:先获取指定的构造函数,再通过这个构造函数对象来创建对象
/

    @Test
    public void getObject() throws Exception {
        //1.获取目标资源对应的字节码对象
        Class<?> clazz = Student.class;

        //2.创建对象
        Object obj = clazz.newInstance();/*会触发无参构造*/
        //需要重写Student中的toString(),否则打印的是对象的地址值
        System.out.println(obj);//Student{name='null', age=0}

        System.out.println("下面的内容是方式二");
        //3.要指定去调用哪个构造方法来创建对象,所以要先获取这个指定的构造方法
        /*注意!!!这个方法参数类型是构造方法参数类型对应的字节码对象*/
        Constructor<?> c = clazz.getConstructor(String.class, int.class);
        Object obj2 = c.newInstance("张三", 3);
        System.out.println(obj2);

        //5.通过反射创建出来的对象获取属性值并使用方法
        /*注意!此处需要把父类型Object类型的obj强制转换成子类型Student的s
        * 为什么要强转?因为此处我们想要使用子类的特有功能,而父类无法使用子类的特有功能
        * Object父类中是没有Student子类自己的属性与功能的
        * 所以,我们把之前看做是父类型的子类对象转回成子类型,去调用子类的特有功能
        * 这个现象称作:向下造型
        * 【注意!!!向下造型之前必须先向上造型,纯纯的父类对象不能向下造型】*/
        Student s = (Student)obj2;
        System.out.println(s.name);
        System.out.println(s.age);
        s.play(666);
    }

//5.通过反射创建出来的对象获取属性值并使用方法
/注意!此处需要把父类型Object类型的obj强制转换成子类型Student的s
* 为什么要强转?因为此处我们想要使用子类的特有功能,而父类无法使用子类的特有功能
* Object父类中是没有Student子类自己的属性与功能的
* 所以,我们把之前看做是父类型的子类对象转回成子类型,去调用子类的特有功能
* 这个现象称作:向下造型
* 【注意!!!向下造型之前必须先向上造型,纯纯的父类对象不能向下造型】
/
*

暴力反射

指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源, 方法格式以 "getDeclared----"开头

//单元测试方法的格式:@Test+public+void+无参
/单元测试 1:暴力反射获取与设置私有属性值/

----------暴力反射!!!注意!!!要设置私有可见,不然访问不了
field.setAccessible(true);

package cn.tedu.reflection;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*本类用于测试暴力反射*/
public class TestReflect2 {
    //单元测试方法的格式:@Test+public+void+无参
    /*单元测试 1:暴力反射获取与设置私有属性值*/
    @Test
    public void getFields() throws Exception {
        //1.获取目标资源对应的字节码对象
        Class<?> clazz = Person.class;
        //2.获取指定名称的私有属性
        Field field = clazz.getDeclaredField("name");
        //3.根据获取到的属性对象拿到它的类型
        System.out.println(field.getType().getName());
        System.out.println(field.getType());
        //4.设置属性的值
        //4.1 没有对象就通过反射的方式创建对象
        Object obj = clazz.newInstance();
        //4.2 暴力反射!!!注意!!!要设置私有可见,不然访问不了
        field.setAccessible(true);
        //4.3刚刚获取到的name属性对象设置值
        /*注意需要设置两个参数:哪个对象的属性值,以及要设置一个什么值
        * set(m,n) m-给哪个对象设置值  n-给这个对象的属性设置一个什么值*/
        field.set(obj,"林冲");
        //4.4打印刚刚给属性设置的值
        /*注意还是需要指定获取的是哪个对象的这个属性的值*/
        System.out.println(field.get(obj));
    }
}

/单元测试 2 :通过暴力反射获取与使用方法/

//2.通过暴力反射获取私有方法
/本方法的参数列表是
1.getDeclaredMethod(name,x,y,z…)
* name:指的是要获取方法的名字
* x,y,z…可变参数,指的是要获取方法的参数类型,注意是字节码对象“.class”

*
2./invoke()用来调用目标方法,参数1是执行哪个对象的这个方法
后续的参数是执行目标方法时传入的参数,这个参数是可变参数,根据目标方法的具体情况来写
/

    /*单元测试 2 :通过暴力反射获取与使用方法*/
    @Test
    public void getFunction() throws Exception {
        //1.获取目标资源对应的字节码对象
        Class<?> clazz = Person.class;
        //2.通过暴力反射获取私有方法
        /*本方法的参数列表是getDeclaredMethod(name,x,y,z...)
        * name:指的是要获取方法的名字
        * x,y,z...可变参数,指的是要获取方法的参数类型,注意是字节码对象“.class”*/
        Method method = clazz.getDeclaredMethod("add", String.class, int.class);
        //3.1没有对象就通过反射创建对象
        Object obj = clazz.newInstance();
        //3.2如果想要执行私有的方法,也要设置私有可见
        method.setAccessible(true);
        //3.3执行获取到的这个私有方法
        /*invoke()用来调用目标方法,参数1是执行哪个对象的这个方法
        后续的参数是执行目标方法时传入的参数,这个参数是可变参数,根据目标方法的具体情况来写*/
        method.invoke(obj,"李四儿",18);
    }

method.invoke(obj,“李四儿”,18);//获取并设置私有方法,自打印

内部类

如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。
就是把类定义在类的内部的情况就可以形成内部类的形式。
在这里插入图片描述

  1. 内部类可以直接访问外部类中的成员,包括私有成员
  2. 外部类要访问内部类的成员,必须要建立内部类的对象
  3. 在成员位置的内部类是成员内部类
  4. 在局部位置的内部类是局部内部类

测试1: 成员内部类(类里方法外)*/*

package cn.tedu.innerclass;
/*本类用于测试内部类的入门案例*/
public class TestInner {
    public static void main(String[] args) {
        //创建内部类对象,   外部类名.内部类名  对象名 = new 外部类名().new内部类名()
        Outer.Inner oi = new Outer().new Inner();
        oi.delete();
        System.out.println(oi.sum);
        //调用外部类的方法--这样创建的是一个匿名的外部类对象,只使用一次
        new Outer().find();
    }
}

class Outer{
    String name;
    private  int age;
    public void find(){
        System.out.println("Outer...find()");
        //System.out.println(sum);不能直接使用内部类的属性
        //delete();不能直接使用内部类的方法
        /*外部类想用内部类资源,比逊先创建内部类对象
        * 通过内部类对象来调用内部类的资源*/
        Inner in = new Inner();
        System.out.println(in.sum);
        in.delete();
    }
    //2.创建内部类Inner--外部类的一个特殊成员
    /*根据内部类的位置的不同,分为成员内部类(类里方法外)
    * 局部内部类(方法类)*/
    class Inner{
        int sum = 10;
        public void delete(){
            System.out.println("Inner...delete");
        //测试内部类可以直接使用外部类的资源,也包含私有资源
            System.out.println(name);
            System.out.println(age);
            //find();
            /*注意此处测试, 否则来回调用会抛出栈溢出异常StackOverflowError*/
        }
    }
}

测试2://私有成员内部类被包含在外部类之中,被看做是外部类

package cn.tedu.innerclass;

public class TestInner2 {
    public static void main(String[] args) {
        //new Outer2().new Inner2();外部无法直接创建内部类private
        //创建外部类对象间接访问私有内部类的资源
        new Outer2().getInner2Eat();
    }
}
class  Outer2{
    //私有内部类被包含在外部类之中,被看做是外部类
    public void  getInner2Eat(){
        Inner2 in = new Inner2();
        in.eat();
    }

    private  class Inner2{
        public void eat(){
            System.out.println("chichi");
        }
    }
}

测试3://成员内部类为静态类

  • 6.可以直接外部类类名创建内部类对象*/—只可以访问一次
package cn.tedu.innerclass;

public class TestInner3 {
    public static void main(String[] args) {
//        Outer3.Inner3 oi = new Outer3().new Inner3();
//        oi.show();
//        //创建匿名对象的方式来访问show()--只可以访问一次
//        new Outer3().new Inner3().show();
//
        /*现象:内部类被static修饰以后 报错
        * 6.可以直接外部类类名创建内部类对象*/
        Outer3.Inner3 oi = new Outer3.Inner3();
        oi.show();
        /*访问静态内部类中的静态资源可以链式加载*/
        new Outer3.Inner3().show();
    }
}
class Outer3{
    //内部类为静态类
    static class Inner3{
        public  void show(){
            System.out.println("Inne3....show()");
        }
        //改为静态方法
        static public  void show2(){

            System.out.println("Inne3....show2()");
        }
    }
}

测试4://局部内部类(方法里)

package cn.tedu.innerclass;
//局部内部类
public class TestInner4 {
    public static void main(String[] args) {
        new Outer4().show();
    }
}
class Outer4{
    public  void show(){
        class  Inner4{
            String name;
            int age;
            public  void eat(){
                System.out.println("Inner4''''eat()");
            }
        }
        /* 在show()创建内部类对象 */
        Inner4 in = new Inner4();
        in.eat();
        System.out.println(in.age);
        System.out.println(in.name);
    }
}

测试5:匿名内部类:
//创建匿名内部类
/以前使用接口,需要先创建接口的实现类
* 接着接口实现类需要添加接口中未实现的方法
/
/相当于创建接口实现类+重写接口中的方法+创建对象+调用功能/

package cn.tedu.innerclass;
/*测试匿名内部类
* */
public class TestInner5 {
    public static void main(String[] args) {
        //创建匿名内部类
        /*以前使用接口,需要先创建接口的实现类
        * 接着接口实现类需要添加接口中未实现的方法并实现
        //最后需要创建接口实现类对象并进行调用,这样比较复杂*/
        //如果有的方法只是需要使用一次,就没必要这么复杂,使用匿名内部类即可
        /*相当于创建接口实现类+重写接口中的方法+创建对象+调用功能*/
        new Inner1(){

            @Override
            public void save() {
                System.out.println("Inner1 .... save()");
            }

            @Override
            public void get() {
                System.out.println("Inner1....get()");
            }
        }.get();//触发实现get(),注意只能使用一个,使用一次
        new Inner2() {
            @Override
            public void drink() {
                System.out.println("hedianba");
            }
        }.drink();
        new Inner3().power();
        Inner3 i3 = new Inner3();
        i3.power();
        i3.study();
    }
}
//1.创建接口
interface Inner1{
    void save();
    void get();

}
//抽象类
abstract  class Inner2{
    public void play(){
        System.out.println("Inner2...play()");
    }
    abstract public void drink();
}
//3.普通类
class Inner3{
    public  void study(){
        System.out.println("学习");
    }
    public void power(){
        System.out.println("光头强");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值