Java第十七天:反射【重点重点重点】和单例

反射【重点重点重点】和单例

1. 单例
1.1 为什么要使用单例
要求当前类在整个程序的运行过程中有且只有一个类对象!!!

一般作为单例的对象都是一些核心的处理数据或者业务逻辑的对象!!!

Servlet

多线程编程中使用非常多。
例如:
	在项目处理数据,控制数据的类,一般会采用单例模式,防止数据出现冲突和冗余问题。并且极有可能导致共享资源问题
1.2 代码实现
package com.qfedu.a_single;

class SingleDog {

    private static SingleDog sd = null;

    private SingleDog() {}

    public static SingleDog getInstance() {
        // 反射告诉你这是什么???
        synchronized (SingleDog.class) {
            if (null == sd) {
                sd = new SingleDog();
            }
        }

        return sd;
    }
}

class SingleType {
    private static SingleType st = new SingleType();

    private SingleType() {}

    public static SingleType getInstance() {
        return st;
    }
}

/*
问题1:
    目前在代码中创建当前对象SingleDog的方式有且只有new关键字+构造方法可以使用
    但是这种方式,是任何一个程序员都可以随意调用的,无法满足单例模式的基本要求
公告:
    该对象我已经new过了,你们不能new
    匿名: 你是不是傻子
解决:
    从语法角度断绝new+构造方法组合
    构造方法私有化

问题2:
    私有化构造方法之后,类外没有创建对象的能力,这不符合单例模式需求。
分析:
    1. 类外需要一个对象
    2. 构造方法私有化了

    私有的方法类内可以使用

    留给类外可以调用的方法有哪些?
        普通成员方法不能使用,因为【没有对象】
        静态成员方法可以使用类名调用,因为【不需要对象】

    思考 是否可以让静态成员方法创建对象,提供给类外使用
    1. 静态成员方法需要类外使用 public
    2. 静态成员方法 需要使用 static修饰
    3. 获取一个类对象且是一个SingleDog对象,返回值类型SingleDog
    4. 方法名 getInstance
    5. 类内的构造方法没有参数,所有该方法不需要参数
    public static SingleDog getInstance()

问题3:
    发现南辕北辙,通过目前的方式依然得到的是不同对象,因为调用getInstance
    是new了不同的对象。
分析:
    也不是不让你new对象,但是只能new一次对象,之后调用该getInstance方法,只能
    返回之前new对象的空间首地址。

    这里需要保存第一次创建对象的空间首地址!!!
    成员变量
        getInstance方法是一个static方法,这家伙能用非静态成员变量?[没有对象]
    局部变量
        目前还是一个分母,没法用
    静态成员变量
        可以使用
        static
        SingleDog
        private
        private static SingleDog sd = null;

问题4:
    因为涉及到多线程问题,需要考虑加锁
    类锁!!!
 */
public class Demo {
    public static void main(String[] args) {
        System.out.println(SingleType.getInstance());
        System.out.println(SingleType.getInstance());
        System.out.println(SingleType.getInstance());
        System.out.println(SingleType.getInstance());
        System.out.println(SingleType.getInstance());
        System.out.println(SingleType.getInstance());
        System.out.println(SingleType.getInstance());
    }
}
2. 反射【重中之重】
2.1 反射是原理
Java文件通过Javac.exe编译之后,生成对应当前文件中所有class, 对应的.class

Java文件可以认为是包含了当前Java程序的所有内容,包含
	构造方法Constructor
	成员方法Method
	成员变量Field
	注解Annotation

对应当前Java文件的.class字节码文件包含了当前Java程序的所有内容,只不过是对应的当前Java程序的二进制文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Duc2bBqB-1584347733922)(.\img\反射内存图.png)]

2.2 获取Class类对象
Class Class.forName(String 完整的包名.类名);
	1. 可以通过指定的包名.类名获取对应当前类的Class类对象
	2. 该方法可以帮你加载指定类。

Class 类名.class;
	通过类名获取对应的Class类对象

Class 类对象.getClass();
	通过类对象获取对应的Class类对象
2.3 获取Constructor类对象
Constructor[] getConstructors();
/*
获取当Class类对象对应的所有非私有化构造方法,返回值是一个构造方法类对象数组
*/

Constructor[] getDeclaredConstructors();
/*
【暴力反射】
获取当Class类对象对应的所有构造方法,返回值是一个构造方法类对象数组
*/

Constructor getConstructor(Class... initArgumentTypes);
/*
获取指定初始化参数数据类型的非私有化构造方法类对象
Class: 这里要求是Class类对象
	例如: int.class String.class
... : 不定长参数 这里对于参数个数不限制,但是要求全部都是Class类型
	例如:
		无参数 (null)
		一个参数 (int.class)
		两个参数 (int.class, String.class)
*/

Constructor getDeclaredConstructor(Class... initArgumentTypes);
/*
【暴力反射】
获取指定初始化参数数据类型的任意构造方法类对象
Class: 这里要求是Class类对象
	例如: int.class String.class
... : 不定长参数 这里对于参数个数不限制,但是要求全部都是Class类型
	例如:
		无参数 (null)
		一个参数 (int.class)
		两个参数 (int.class, String.class)
*/

Object newInstance(Object... initArguments);
/*
使用Constructor类对象调用,传入当前Constructor构造方法类对象需要的实际参数,创建对象!!!
Object: 当前构造方法需要的实际参数
... : 不定长参数
	无参数: (null)
    一个参数: (10)
    两个参数: (10, "为所欲为")
*/
2.4 获取Method类对象
Method[] getMethods();
/*
获取类内所有非私有化成员方法类对象数组
注意
	包括从父类继承而来可以使用的成员方法!!!
*/

Method[] getDeclaredMethods();
/*
【暴力反射】
获取类内所有成员方法,包括私有成员方法类对象数组
注意:
	不包括从父类继承而来的方法
*/

Method getMethod(String methodName, Class... argumentTypes);
/*
获取指定MethodName,以及对应参数类型的非私有化成员方法
methodName:方法名
Class: Class类型,对应当前方法的参数类型
...: 不定长参数,因为参数的个数不确定
	无参数("game", null);
 	String参数("game", String.class)
*/

Method getDeclaredMethod(String methodName, Class... argumentTypes);
/*
【暴力反射】
获取指定MethodName,以及对应参数类型任意修饰的成员方法
methodName:方法名
Class: Class类型,对应当前方法的参数类型
...: 不定长参数,因为参数的个数不确定
	无参数("game", null);
 	String参数("game", String.class)
*/

Object invoke(Object obj, Object... args);
/*
使用Method类对象调用,执行对应Method类对象方法
obj: 调用当前方法的类对象
args: 对应当前方法的实际参数
	例如:
		method.invoke(p1, null);
		method.invoke(p1, "LOL");
		
*/
2.5 获取Field类对象
Field[] getFields();
/*
获取类内所有非私有化成员变量类对象
*/

Field[] getDeclaredFields();
/*
获取类内所有成员变量,包括私有化成员变量
*/

Field getField(String fieldName);
/*
获取指定成员变量名对应的非私有化成员变量Field类对象
*/

Field getDeclaredField(String fieldName);
/*
获取指定成员变量名对应的任意修饰的成员变量类对象,包括私有化成员变量
*/

void set(Object obj, Object value);
/*
设置指定类对象中的成员变量数据
obj:操作的类对象
value: 给予成员变量的数值
*/
    
Object get(Object obj);
/*
获取指定类对象中成员变量数据
obj: 指定类对象
*/
2.6 给予暴力反射操作权限
void setAccessible(boolean flag);
/*
给予暴力反射权限 参数为true
*/

希望大家关注我一波,防止以后迷路,有需要的可以加我Q讨论互相学习java ,学习路线探讨,经验分享与java Q:2415773436

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值