Java24--反射+内部类

1 反射

1.1 概念

Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,private的只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。

反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。

1.2 为什么需要反射

好好的我们new User(); 不是很好,为什么要去通过反射创建对象呢?

那我要问你个问题了,你为什么要去餐馆吃饭呢?

例如:我们要吃个牛排大餐,如果我们自己创建,就什么都得管理。

好处是,每一步做什么我都很清晰,坏处是什么都得自己实现,那不是累死了。牛接生你管,吃什么你管,屠宰你管,运输你管,冷藏你管,烹饪你管,上桌你管。就拿做菜来说,你能有特级厨师做的好?

那怎么办呢?有句话说的好,专业的事情交给专业的人做,饲养交给农场主,屠宰交给刽子手,烹饪交给特级厨师。那我们干嘛呢?

我们翘起二郎腿直接拿过来吃就好了。

再者,饭店把东西做好,不能扔到地上,我们去捡着吃吧,那不是都成原始人了。那怎么办呢?很简单,把做好的东西放在一个容器中吧,如把牛排放在盘子里。

在开发的世界里,spring就是专业的组织,它来帮我们创建对象,管理对象。我们不在new对象,而直接从spring提供的容器中beans获取即可。Beans底层其实就是一个Map<String,Object>,最终通过getBean(“user”)来获取。而这其中最核心的实现就是利用反射技术。

总结一句,类不是你创建的,是你同事或者直接是第三方公司,此时你要或得这个类的底层功能调用,就需要反射技术实现。有点抽象,别着急,我们做个案例,你就立马清晰。

1.3 反射Class类对象

Class.forName(“类的全路径”);

类名.class

对象.getClass();

1.4 常用方法

获得包名、类名

clazz.getPackage().getName()//包名

clazz.getSimpleName()//类名

clazz.getName()//完整类名

!!成员变量定义信息

getFields()//获得所有公开的成员变量,包括继承的变量

getDeclaredFields()//获得本类定义的成员变量,包括私有,不包括继承的变量

getField(变量名)

getDeclaredField(变量名)

!!构造方法定义信息

getConstructor(参数类型列表)//获得公开的构造方法

getConstructors()//获得所有公开的构造方法

getDeclaredConstructors()//获得所有构造方法,包括私有

getDeclaredConstructor(int.class, String.class)

方法定义信息

getMethods()//获得所有可见的方法,包括继承的方法

getMethod(方法名,参数类型列表)

getDeclaredMethods()//获得本类定义的方法,包括私有,不包括继承的方法

getDeclaredMethod(方法名, int.class, String.class)

反射新建实例

c.newInstance();//执行无参构造

c.newInstance(6, "abc");//执行有参构造

c.getConstructor(int.class, String.class); //执行含参构造,获取构造方法

反射调用成员变量

c.getDeclaredField(变量名); //获取变量

c.setAccessible(true); //使私有成员允许访问

f.set(实例, 值); //为指定实例的变量赋值,静态变量,第一参数给 null

f.get(实例); //访问指定实例的变量的值,静态变量,第一参数给 null

反射调用成员方法

获取方法

Method m = c.getDeclaredMethod(方法名, 参数类型列表);

m.setAccessible(true) ;//使私有方法允许被调用

m.invoke(实例, 参数数据) ;//让指定的实例来执行该方法

1.5 反射的应用

1.5.1 获取类对象

 private static void method() throws Exception {

       Class clazz = Student.class;

       Class<?> clazz2 = Class.forName("seday15.Student");

       Class clazz3 = new Student().getClass();

      

       System.out.println(clazz.getName());

       System.out.println(clazz2.getName());

       System.out.println(clazz3.getName());

    }

1.5.2 获取构造方法

private static void method3(Class clazz) {

       Constructor[] cs = clazz.getDeclaredConstructors();

       for (Constructor c : cs) {

           String name = clazz.getSimpleName();

           System.out.println(name);

          

           Class[] cs2 = c.getParameterTypes();//参数

           System.out.println(Arrays.toString(cs2));

          

       }

      

    }

1.5.3 获取成员方法

private static void method4(Class clazz) {

     Method[] ms = clazz.getMethods();

       for (Method m : ms) {

           String name = m.getName();

           System.out.println(name);

          

           Class<?>[] cs = m.getParameterTypes();

           System.out.println(Arrays.toString(cs));

       }

    }

1.5.4 获取成员变量

  private static void method2(Class clazz) {

       Field[] fs = clazz.getFields();//获取public的属性

       for (Field f : fs) {

           String name = f.getName();

           String tname = f.getType().getSimpleName();

           System.out.println(name);

           System.out.println(tname);

       }

    }

1.5.5 创建对象

package seday15;

 

import java.lang.reflect.Constructor;

import java.util.Scanner;

 

//反射新建两个对象

public class Test3 {

    public static void main(String[] args) throws Exception {

       String s =  new Scanner(System.in).nextLine();

       Class<?> clazz = Class.forName(s);

      

       Object o1 = clazz.newInstance();//用无参构造

       System.out.println(o1);

 

Constructor<?> c = clazz.getConstructor(String.class);//用含参构造

       Object o2 = c.newInstance("jack");

       System.out.println(o2);

    }

}

 

1.6 暴力反射

指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。需要使用的常见方法如下:
在这里插入图片描述

1.6.1 创建Person类

class Person{

   

    private String name="jack";

    private int age = 30;

   

    private void show(int[] a) {

       System.out.println("show()..."+Arrays.toString(a));

    }

    private void test() {

       System.out.println("test()...");

    }

}

1.6.2 测试

1、 获取私有属性值并修改

2、 获取私有方法并执行

package seday16new;

 

import java.lang.reflect.Field;

import java.lang.reflect.Method;

 

public class Test3_ReflectPerson {

    public static void main(String[] args) throws Exception {

       Class<?> clazz = Class.forName("seday16new.Person");

//     method(clazz);//隐私属性

       method2(clazz);//执行方法

    }

 

    private static void method2(Class<?> clazz) throws Exception {

       Method m = clazz.getDeclaredMethod("show", int[].class);

       Object obj = clazz.newInstance();

       m.setAccessible(true);//方法隐私可见

       m.invoke(obj, new int[]{1,2,3});//执行

    }

 

    private static void method(Class clazz) throws Exception {

       Field f = clazz.getDeclaredField("name");

       System.out.println(f.getType().getName());

        f.setAccessible(true);//属性隐私可见

       Object obj = clazz.newInstance();

//     f.set(obj, "rose");//设置值

       System.out.println(f.get(obj));//获取值

   

      

       //---所有属性

       Field[] fs = clazz.getDeclaredFields();

       for (Field ff : fs) {

           System.out.println(ff);

           ff.setAccessible(true);//暴力反射

           System.out.println(ff.get(obj));

       }

      

    }

   

}

2 内部类

2.1 概述

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

A类中又定义了B类,B类就是内部类。B类可以当做A类的一个成员看待。

2.2 特点

1、 内部类可以直接访问外部类中的成员,包括私有成员

2、 外部类要访问内部类的成员,必须要建立内部类的对象

3、 在成员位置的内部类是成员内部类

4、 在局部位置的内部类是局部内部类

2.3 成员内部类

被private修饰

package cn.tedu.inner;

 

//测试内部类被private修饰

public class Test5_InnerClass2 {

    public static void main(String[] args) {

       //TODO 创建内部类对象,并执行show()

//     Outer2.Inner2 oi = new Outer2().new Inner2();//报错,Inner2已经被private了

       //3,测试被private的内部类的资源能否执行!

       new Outer2().test();

    }

}

class Outer2{

    //2,如果想要访问private的内部类,可以访问外部类提供的对应方法

    public void test() {

       //访问内部类方法

       new Inner2().show();

    }

    //位置在类里方法外--成员内部类

    //1,内部类可以被private修饰,但是外界无法直接创建对象了!

    private class Inner2{

       public void show() {

           System.out.println("Inner2.show()");

       }

    }

}

被static修饰

package cn.tedu.inner;

//测试内部类被static修饰

public class Test6_InnerClass3 {

    public static void main(String[] args) {

       // 创建内部类对象测试show()

//     Outer3.Inner3 oi = new Outer3().new Inner3();//报错,原因是Inner3是静态的内部类

      

 

 

 

 

Outer3.Inner3 oi = new Outer3.Inner3();//Outer3.Inner3通过类名.调用类中的静态资源

       oi.show();

      

       Outer3.Inner3.show2();//调用静态内部类里的静态方法

    }

}

class Outer3{

   

    //1,内部类被static修饰--随着类的加载而加载,会造成内存资源浪费,并不常用!

    static class Inner3{

 

       public void show() {

           System.out.println("Inner3.show()");

       }

       static public void show2() {

           System.out.println("Inner3.show2()");

       }

    }

}

2.4 匿名内部类

匿名内部类属于局部内部类,并且是没有名字的内部类。

package cn.tedu.inner;

 

//测试匿名内部类

public class Test8_InnerClass5 {

    public static void main(String[] args) {

       new Hello() {// 匿名对象,本身接口不能new,这里new Hello()匿名对象,就相当于Hello接口的实现类

           // 匿名内部类

           @Override

           public void save() {

              System.out.println("save()..");

           }

 

           @Override

           public void update() {

              System.out.println("update()..");

           }

       }.update();// 触发指定的方法

       new Hello2() {//抽象类的匿名内部类

           @Override

           public void show() {  }

       }.show();

      

       new Animal() {//普通类的匿名内部类

           @Override

           public void eat() {   }

       };

    }

}

//TODO 创建匿名对象+匿名内部类测试

class Animal{

    public void eat() {}

}

abstract class Hello2 {

    abstract public void show();

    public void delete() {   }

}

 

// 定义接口

interface Hello {

    void save();

    void update();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值