导言:
在学习JavaSE的时候,我们会使用Java基础编程,并且了解了什么是面向对象的编程,会使用Java写一些基础算法程序,
接下来,我们需要了解Java的自动拆箱和自动装箱,单线程和多线程,反射是什么,值得注意的是,讲的是Java中的特性,但是OOP语言其实都是用这些操作的,只是小部分不同罢了
一.自动拆箱和自动装箱
不管是拆箱还是装箱,它的宏观意义就是普通类型到封装类型(对象)的转换,反之,就是封装类型到基本类型的转换
自动装箱
自动装箱指的是普通类型到封装类型(对象)的转换
我们可以看到上面的代码:
Integer b = new Integer(10);这是很标准的创建对象的方式
我们在使用 Integer a = 10 ;的时候,其实就已经发生了一次自动装箱,我们可以拆分一下这句话,Integer 是封装类型,也就是说一般是通过new的形式拿到的,
但是后面的 a = 10; 一般都是定义一个int型变量才会那么定义,你就会发现这句话好像有两个定义,一个像是在定义基本类型,另一个像是在定义封装类型,但是这样的定义是可以完成的,且不会报错
这就要基于Java的隐式调用:
如图,我们的定义在JVM处理的时候自动隐式的调用了valueOf()方法,由于是隐式的,在我们不知到的情况下完成的就叫它自动装箱
通过上面的程序,我们比较a和b的输出结果,发现是Ture,说明都是Integer类型,自动装配就等同new 出来的Integer对象
自动拆箱
自动拆箱指的是封装类型(对象)到普通类型的转换
根据上面的图片我们可以看到:
int a = 1;是很明显的int型的定义方式
Integer integer = new Integer(1); 我们是new了一个Integer的对象类型,所以integer现在是一个对象类型,他要是想和基本类型比较肯定自己也是int 但是我们使用的是 int b = integer; 让一个int 类型直接 被赋值于 integer这个对象类型,乍一眼看,类型不匹配啊,但结果也是可执行的,且不会报错 这也要归功于Java的隐式调用:它的处理也是隐式调用integer对象转为int型变量的方法,valueOf()方法,由于是隐式完成的,所以叫自动拆箱
我们再来看看上面的程序运行结果,a==b结果是Ture,所以它们最后的结果都是int型
拓展自动装箱:
自动装箱的时候在代码中我们看到了,比较a和b两个对象的时候,我是使用的equals方法,它比较的是值,也就是两个对象的值都是10,所以equals方法的结果是ture
但是我们要是通过 == 来判定的时候呢?结果是 false 这是为什么呢?
首先,Integer b = new Integer(10); 它申请的空间肯定是在堆上的,因为是程序运行时动态开辟的空间,主要是Integer a = 10;它的空间在那?
我们这个时候就需要看一波自动装箱的源码了:
这段源码的意思是,我们在使用valueOf()方法的时候,不会直接创建一个对象,而是先看看要创建的对象有没有被先加载好,因为Java在缓存中已经预加载了256个Integer对象,范围是-128~127,如果在此范围内,那么就直接拿缓存中的对象,
如果不在此范围内,才会去构建一个新的对象,这是因为大多数情况,我们在使用自动装箱和自动拆箱的时候,所转换的数据大多是用来做状态码的,它的大小不会超过三位,所以我们先预先构造一些,就避免了反复造轮子
现在我们看看都是用vlaueOf()构造出来的对象是不是相等的:
当我们把代码改成上面的方式构造对象后,a对象和b对象就是相等的了,即结果为Ture
接下来我们可以思考一下:
Integer a = 128;
Integer b = 128;
输出:a == b ,结果如何呢?
包装类型缓存池
在jvm中,缓存中会预先加载一些封装对象,目的是为了提高封装对象的重复利用率,以免我们在使用这些封装对象的是时候重复构造
如图,在jvm会预先加载这八种封装类型,也就是每个基本类型对应的封装类型:
它们预加载范围如图所示
所以,我们的程序在运行的时候,一旦发生需要装箱和拆箱的操作的时候,尽量不要使用new 直接创建,而是通过valueOf()方法,先去缓存区拿,如果拿不到,再去创建一个新的对象,
这就是我们使用valueOf()方法区去创建对象的过程,比直接new 封装对象要多了一步去查看缓存的操作
二.单线程和多线程
线程这一概念,我们在了解的时候一定是在操作系统中,随着技术的发展,我们使用的单线程编程,效率执行低,所以现在多线程编程又变的流行起来了
线程是操作系统的最小调度单位,它被包含到进程之中,是进程运行中的最小运行单位
进程是程序运行的基本实体
在操作系统中,我们了解到了进程是程序运行资源的拥有者,而线程则是负责调度可资源分配者,本身不需要分配资源
单线程:
单线程最大的特点就是程序的顺序的执行,它的编程风格通俗易懂,它只有在程序执行完成了以后才会执行后面的程序,单线程较多线程来说,系统稳定、扩展性极强、软件丰富。多用于点对点的服务。
单线程处理的优点:同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。
我们也可以看上面的实例,当a=1被处理器处理完成以后,等到b=2会有一段时间才会到达处理器,处理器的速度是很快的,从内存调过来的时间,处理器就一直处于等待的状态,所以这段时间造成了处理器的浪费,
为了节约处理器的资源,我们便研究出来了多线程
多线程:
简单引入:在程序中独立,但是可以同时运行
我们先简单的看个小实例预热一下多线程:
我们可以看到上面的图片,我们的传送带每5分钟只会来一个货物,而我们的工人呢?只需要20s就可以把货物卸载完成了,很显然,这个工人有很大的一部分时间都在摸鱼
至少有4分钟它一直在等待传送带运来货物,我们要是这么设计工作者岗位的话,肯定很浪费,有什么办法可以把它调高呢?
我们可以使用多增加几个传送带:
我们在增加了传送带后,虽然还是有空闲时间,但是利用率变高了,除去员工跑来跑去的开销,以及工作的开销,我们对整个线路的提高都是有目共睹的,
现在我们的员工执行逻辑就不再是第一次那么简单的卸载,然后一直等待了,而是需要利用等待的时间去处理下一条传输带,
这就是多线程,它旨在相同的前提下,更多的处理任务
现在我们的生活中无处不存在多线程,你有没有想过为什么在打游戏的时候,我们的手机还能听歌,在追剧的时候还能聊天,要是依旧使用单线程,肯定一个终端只能运行一个设备
多线程提高了效率,可以在同一段时间做更多的事情
多线程之并发:
在同一时刻有多个指令在CPU上交替执行
多线程之并行:
在同一时刻有多个指令在CPU上同时进行
下面我们来看看多线程在程序中是怎么执行的:
我们可以看到,理想状态下,我们的公共资源就是6,所以两个线程都可以拿到6,然后执行加一操作后输出并写回公共资源,这种执行方式肯定是多线程无错误的
但是,线程虽然可以同时间段运行,由于各种原因的混合,导致了一个先读入数据,一个后读入数据,中间的一点点空隙就会导致结果不一样,
比如第二种情况,就是在线程1已经写回了情况,线程2才去读临界资源,导致了最后的结果两者对不上,
所以我们看到了多线程带来的高效,即同时处理两个问题,但是它也带来了很多问题,就是多个线程读取数据结果不一致
当然,多线程发展到今天,我们也有很多方法解决它,解决也是要开销的
三.反射机制
在了解反射之前,我们一定要知道反射的作用是干什么的,众所周知,Java是一门静态语言,但是在Java引入了反射机制以后了它便可以编程一门准动态语言
什么是动态语言呢?
1、动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。
主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。
2、静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。如 Java、C、C++。
正常的方式编程:
引入需要使用的包类名 ---- 通过new关键字实例化 --- 取得实例化对象
反射的方式编程:
实例化的对象 --- getClass()方法 ---- 得到完整的包类名
反射就好比一面镜子,可以通过镜子找到我们所需要的方法,对象
反射相关的API:
java.lang.Class //代表一个类
java.long.reflect.method //代表一个方法
java.long.reflect.Field //代表一个成员变量
java.long.reflect.Constuctor //代表一个构造器
反射的实现方式:
Class c = Class.forName("java.long.String");java.long.String是包名,也就是包的位置
获得的就是一个class对象
通过包名拿到的类其实即使拿了两次,发现它们的hashCode()其实是相等的
这也和Java的内存模型有关,相同的类只会加载一次
通过getClass方法可以拿到任何类,原因是此方法是Object对象的,所以它默认被所有的类继承
为什么反射能拿到类也要归功于jvm中相同的类只有一个
正常解析的方式是我们在编写程序的时候,通过类名,然后使用new关键字直接创建一个对象
我们要知道,不管你有几个对象,它们都能找到是通过类名给new出来的,不管有多少个类,实际上它们都是归于了Class类
所以反射可以通过对象拿到类,即使它不知道整个类是什么,但是一定在Class类里面
这就是我们的返回值是 Class<?> 的原因
反射小结:
- 通过反射,我们可以是Java完成部分动态语言的功能
- 通过反射,可以使用到特殊的方法,比如私有方法,属性
- 很多框架都是反射机制来实现的,比如Spring AOP的思想
- 当某个功能可以不使用反射时,尽量不适用(反射麻烦,效率低)
-------------------
Java反射和多线程编程都是可实现的,以上的博客内容都是概述,真正的实现还需要我们专门花时间去学习,想通过一般的博客去搞懂反射和多线程编程,显得有些天方夜谭了
------------------