Java复习系列01-java语言基础
Table of Contents
- 1. java内存模型
- 2. BinaryTree
- 3. ClassLoader加载
- 4. HashMap源代码
- 5. Hash冲突
- 6. ArrayList原理分析
- 7. Set集合
- 8. Java调试
- 9. this关键字
- 10. default关键字
- 11. Java系列小问题
- 12. JVM核心优化策略
- 13. JVM内存组成
- 14. Map-Resize
- 15. Runtime相关说明
- 16. String转换
- 17. ThreadLocal
- 18. ThreadLocal和Threadpool
- 19. ThreadLocal引用传递
- 20. YML格式
- 21. 抽象类
- 22. 抽象类基础
- 23. 多线程应用
- 24. 动态和静态
- 25. 对象引用
- 26. 多对多关系
- 27. 多线程工具类
- 28. 反射参数
- 29. 反射与new
- 30. 各种IO
- 31. 范型通配符问题
- 32. 范型中“T”与“?”的区别
- 33. 方法变量与同步
- 34. 高并发处理包
- 35. 缓冲流与内存流的区别
- 36. 基本类型和包装类
- 37. 基本数据类型与引用传递
- 38. 集合信息取得
- 39. 接口标准
- 40. 接口的使用
- 41. 进程间通讯
- 42. 进程与线程
- 43. 链表为什么要用内部类
- 44. 内存流和管道流
- 45. 如何学习Java
- 46. 什么时候使用Object对象接收
- 47. 线程池
- 48. 线程同步工具类
- 49. 向下转型
- 50. 虚拟内存
- 51. 一道java面试题分析(代码块)
- 52. 引用传递是什么?
- 53. 转义字符处理
- 54. 资源注入
- 55. 字节流和字符流
1 java内存模型
如果说到内存,可能最直观的理解就在于Runtime类中,这个类采用了单例设计模式。
Runtime run = Runtime.getRuntime(); // 取得Runtime类的对象 MAX_MEMORY : run.maxMemory(); // 返回的是类型是long,单位是字节 TOTAL_MEMORY : run.totalMemory(); FREE_MEMORY : run.freeMemory();
在java里面对于内存的空间可以划分为如下几点:
- 伊甸园区:新生的对象都保存在此处,但是不一定这些新生的对象会一直存活;
- 此处也属于内存空间,那么既然是内存空间就一定会被占满,如果占满了,那么就会执行GC处理;
- 旧生代区:如果对象发现其要一直使用,那么就将进入到旧生代区,这属于二级回收保险;
- 如果要是先执行GC,那么肯定先清理伊甸园区,随后如果发现空间不足,继续清理旧生代区;例虚引用、软引用、幽灵引用;
- 永久区:JDK1.8后称为元空间,永久区中的数据不会清除,即使程序出现了“OutOfMemoryException”也不会清除;
调整内存:-Xms2048M -Xmx2048M -Xmn1024M
- “-Xms”:初始分配的内存大小,默认为物理内存的64分之1,但是小于1G;
- “-Xmx”:最大分配内存,默认大小为物理内存的4分之1,但是小于1G;
- “-Xmn”: 设置年轻代(伊甸园区)的堆内存大小;
只有调整之后才可以保证系统内存会得到提升,这样很明显,你就可以发挥出你电脑的性能。例如,构建工具Maven,通过进行这些设置调整内存可以提高打包效率。
2 BinaryTree
对于树的操作需要考虑的问题:
- 存储:左(Node)、右(Node)
- 遍历:前序、中序(排序)和后序
3 ClassLoader加载
ClassLoader是一个类加载器,java应用中不止一个类classloader,所以自己定义的在最后执行。
- BootStrap
- ExtClassLoader
- AppClassLoader
所有的java程序一共有两套类加载器:双亲加载。
- 系统中的类都会由一个系统内部的最高的类加载器负责加载,如果启动的时候要加载的类多就会造成启动变慢,所以JDK1.9才提出了一个模块化的设计;
- 如果是用户定义的类,会使用其它的类加载器(ExtClassLoader、AppClassLoader、自己定义的类加载器),这样可以避免系统安全问题。
在java里面有一个java.lang.String,如果你现在定义了一个完全一样的java.lang.String类,那么最终所带来的就是有可能造成安全隐患,所以JDK在设计的时候为了防止这种问题的出现,采用了双亲加载机制。
同时使用了用户自己定义的类加载器还有一个好处:可以有用户自己定义类文件的来源,默认情况下的类加载器(99%是够用的)都是通过ClassPath加载的,但是如果使用了自定义的类加载器你可以通过远程或文件进行加载。
4 HashMap源代码
- Map.Entry(内部接口)类与HashMap.Node(子类定义的默认内部)类,这两个都是内部类
static class Node<K,V> implements Map.Entry<K,v>{}
- HashMap存储数据增加到一定数量(默认8)的时候(阀值),那么就会由链表变成红黑树,性能会更好
- HashMap里面对于数据保存个数的扩充是按倍数进行的,超过增长容量(默认0.75)
- HashMap里面的方法都是异步处理的,属于非线程安全,“java.util.concurrentModificationException”表示存储的个数和操作的个数不同
5 Hash冲突
在整个Hash存储过程中,必须明确两个实际的问题:hashCode()和equals()两个方法。如果hashCode相同,这个时候会查询equals(),不过一般在使用Map的时候都会考虑使用String来实现,所以String实现的Key里面是不存在这种复杂的概念,也就是说这样的概念只存在于自定义类中,所以当hash冲突严重的时候,首先去考虑equals()方法是否正常。那么在进行数据定位的时候就会更加的快速。
从实际的数据结构的算法来讲,哈希冲突的处理方法:
- 开放定址法,为一个哈希冲突求得一个地址序列
- 链地址法,将所有哈希冲突的内容保存在一个链表里面(hashMap的实现原理)
- 再哈希法,重新做一个Hash计算
6 ArrayList原理分析
集合类中使用最多的就是ArrayList,它的线性复杂度是1,可以通过索引直接访问。实际上这个过程和数组是非常相似的。
ArrayList在整个使用过程中如果要高效操作,那么最好设置一个初始的大小。在个数固定的时候,一般使用ArrayList,不确定的情况下使用LinkedList。ArrayList底层就是通过数组实现的。
7 Set集合
基础认识:
- 本身只定义不允许重复的存储
- 接口完整的继承了Collection接口
从实际的开发来看,Hibernate使用了Set集合,还有一些批量删除的操作使用了Set集合。
常见的子类:
- HashSet:无序存储(如果发现有重复,检查子类中的hashCode()和equals()方法)
- HashSet源代码中存在一个HashMap的对象,不过只利用了key(HashMap特点:key不能重复),没有利用value。
- 在HashSet类执行add()方法时利用了Map接口的put()方法。
- 在存储过程中存在hashCode()的使用。
- 在内部的Node类处理时依然使用了equals()判断key和value的内容。
- TreeSet:使用的是Map集合(SortedMap接口子类)
- 源代码里面存放了一个TreeMap,TreeMap的特点是可排序的,排序是利用Comparable实现的。(comparator往往被忽略)。
- 利用Comparable接口中的compareTo()方法进行数据大小的判断。
- LinkedHashSet:如果需要要进行连续的保存(FIFO),可以使用这个子类。之所以可以进行顺序的保存,是因为底层使用链表实现的。
8 Java调试
断点调试:程序在设置断点的位置停止。
9 this关键字
this表示当前对象,使用this的情形:
- 调用本类的属性
- 调用本类的方法
- 调用本类的构造方法
- 扩展方法中(表示当前对象)
10 default关键字
起初的时候,default和switch配合使用。没有break的时候会执行后面的所有语句。
在JDK1.8之后,lambda表达式的出现,java重新定义了接口的定义,可以定义一个default关键字的普通方法,以前接口中不能定义普通方法。这样如果某些方法对所有的子类有同样的定义,可以利用这个实现,减少方法的定义。
11 Java系列小问题
- 字符串是匿名对象,例如“hello”.toString()。但如果已经实例化后,堆内存的地址已经有了明确的栈内存指向就不是匿名对象了,例如:String str = "hello"。
- 只要是引用对象就保存在堆内存里面,而我们所能进行的内存控制,也只有堆内存。
- 不管是对象池还是常量池都保存在堆内存中
- 对于JVM有三种实现标准,我们使用的是HotSpot虚拟机标准,这个标准的实现不是简单调用了底层的函数。它里面需要与一些底层设备交互,而整个系统设计之中,为了可以让java调用本地的函数功能,专门提供有一个native交由JVM负责实现一些具体功能。
12 JVM核心优化策略
- 取消掉伸缩区,total=max;
- CMS(Concurrent Mark Sweep)问题,频繁的CMS会导致性能下降;
- 伊甸园区、存活区、老年代的关系要说明白,JDK1.8之后取消了永久代,而使用元空间代替;
- 如果内存使用过大要使用G1收集器来进行收集;
- 在Tomcat里面由于其使用基于JVM,所以需要设置一个“JAVAOPTS”,可以将全部的内存供Tomcat使用(默认的最大可用内存为全部的四分之一,默认的total内存为全部内存的64分之1)。
13 JVM内存组成
JVM内存组成里面最为关键的几个内存:
- 栈内存:只是保存有堆内存的引用地址,而且从一个简单的角度来讲,栈内存可以保存基本类型(int、double等)
- 堆内存:java没有采用句柄的模式进行引用,所以它的引用性能是最高的,但是从另一个角度来讲,堆内存里面实际上又分为了若干个子内存空间:伊甸园区(MinorGC)、存活区、老年代(FullGC、MajorGC)。
- 原则:少产生无用的大量内存空间,因为会引发频繁的GC,而频繁的GC会带来CMS问题,那么会导致程序中断执行。
- 原则:让你初始化的空间等于整个堆内存的分配大小,避免伸缩区,这样可以进行性能的提升。
- 方法区:(JDK1.8以前可以称为永久代,在1.8之后称为元空间)
全局数据区也可以认为其规划在堆内存里面,因为可能是对象,可能是基本类型,只不过是采用了一种特殊的处理形式而已。
常见问题:JVM的堆内存组成?GC的处理流程?
14 Map-Resize
如果大于最大,将其设置整型最大值。
它的容量扩充指的是一开始放30个,如果发现不够,则进行移位处理,相当于扩大一倍(30*2),再不够,再移位一次,扩容相当于倍数处理。
15 Runtime相关说明
java.lang.Runtime类是一个系统提供的单例开发类,一个JVM中只存在一个Runtime实例。
- 可以获取系统信息
- 可以进行GC处理(对于整个的JVM内存划分是存在伸缩区,所以面对这样的问题,为了可以提升性能,将初始化内存和最大内存设为相同,如果不相同,就会一直进行空间的判断,而后不断进行空间分配。(-Xmx1g -Xmn1g))。
RuntimeException的异常子类不需要强制性处理,可以选择性处理。Exception的其它子类必须进行处理。RuntimeException是Exception的子类。
16 String转换
Object类之中提供有一个toString()方法,意味着所有的类都具有此方法,此方法的作用就是将对象的内容转化为字符串。
// object默认返回的值 getClass().getName() + '@' + Integer.toHexString(hashCode())
考虑ClassLoader的机制,强转以及子类复写的情况。
如果使用的是String,那么在不为null的情况下,使用强制转型和toString()方法效果一样,但是如果为null,则就会出现NullPointerException。保险的做法是:使用强制转型,但是如果在确定不为空的情况下,则两种方式对String操作的效果是一样的(只有String是,其它的都没有,其它的类如果要变为指定类型只能使用强制向下转型)。
17 ThreadLocal
java是多线程的,static保存的是全局数据区,属于公共的数据处理。在多线程处理中就会出现数据不同步的问题。
那么最好的做法是在可以保存数据的基础上在再多保存一个当前线程对象。而这种操作就属于ThreadLocal类的作用,也就是说ThreadLocal在每一次设置内存的时候都会保存一个当前线程对象。
在ThreadLocal开发中往往保存的最多的是数据库的连接对象。这种场景也特别适合ThreadLocal。
18 ThreadLocal和Threadpool
这两个是没有关系的。
- ThreadLocal类是可以保存一个引用数据类型,并且这个引用数据类型保存的时候会自动保存有一个currentThread对象,这样的好处就是可以避免引用传递的问题。
- ThreadPool指的是线程池,也就是说提供有一个对象池,这个对象池里有若干个线程对象,帮助我们进行可重复使用的对象的生成。线程池种类:无限制增长、定长执行、定时操作、单线程池。
ThreadLocal很少出现在程序的开发之中,主要在数据管理中。ThreadPool就是给线程重用的操作。
19 ThreadLocal引用传递
TheadLocal的本身作用就是进行操作对象信息保存,但它与传统的信息保存不同,它不仅仅保存的是一个引用对象,而且还保存有一个当前对象。也就是说进行数据保存的时候ThreaLocal更像Map集合。
在进行数据保存的引用传递的时候不再只是一个引用类型,而是包含有一个currentThread对象信息保存。这样就可以明确的知道当前操作的对象是什么,并且不会与其它线程进行混淆。
20 YML格式
yml格式是与properties对应的一种格式,基本上可以方便的描述资源配置。
21 抽象类
抽象类只是比一个普通类多了抽象方法的类而已,其它的结构和普通类是差不多。还有一个使用上的区别就是抽象类无法直接使用关键字new进行实例化控制。
普通类的最大的特征在于其定义了类的结构之后可以直接使用关键字new进行对象实例化,但是从继承的角度来看,普通类的继承里面对于子类没有强制性约束。
如果现在某些方法的必须要求子类来实现,那么就可以使用抽象类。
所有的关键字new调用构造方法实例化对象的部分可以将其理解为“匿名对象”的语法。
22 抽象类基础
理论上是抽象类的方法必须覆写,但是为什么HttpServlet的子类中覆写或者不覆写都不会报错?
关键的问题在于HttpServlet抽象类中的所有方法并不完全都是抽象方法,对于抽象类的子类需要覆写的只是抽象方法,对于非抽象方法是不需要强制覆写的。
例子:模版设计模式。
23 多线程应用
java程序上的一切都是多线程。每当使用Java命令处理java程序就相当于启动了一个进程,所以这个时候的主方法就相当于一个线程。
多线程的最大特征是将一个进程进行继续的拆分,例如:Tomcat是一个进程,那么Tomcat里面会把每一个连接上它的用户作为一个线程存在。
多线程之中最为头疼的部分就是在于同步数据处理。
24 动态和静态
EL工作在服务端,而JSON操作在客户端处理(服务端生成)。
当使用Jsp处理的时候,必须明确所有的代码是由容器负责生成,生成的是HTML代码,这些代码通过一些对象来进行生成,生成完成之后才会把生成的代码发送给客户端。客户端进行整体的解析和处理。
JSON只是一个传输格式。它要求在整个处理里面需要通过前台的JS来进行数据的控制。
25 对象引用
在Java之中对于内存关系实际上有两块内容: 内容分配、垃圾回收。
从JDK1.2开始实际上就提出有四种引用关系:强引用、软引用、弱引用、虚引用。
- 强引用:对象将一直被进行引用,即使出现了“OutOfMemoryError”错误信息。
- 软引用:对象将尽可能长时间的保存,一直到出现内存不足的情况下才会被回收,也就是说对象会尽可能的保存的时间长。所以这样的操作常常将其用在缓存的开发上,例如,在MyBatis里面就提供有对于软引用模式的缓存模式。实现起来要使用特定的类:SoftReference<Object>。
- 弱引用:一旦有了垃圾收集操作之后就会进行回收。实现起来也需要特定的类:WeakHashMap<String, Object>。
- 虚引用(幽灵引用):这种操作返回的内容永远都是null,就是不引用;特定的类:ReferenceQueue<Object>、PhantomReference<Object>。在对象的垃圾收集前一定会调用finalze()方法,但是如果说finalize()又占着其它的强引用的对象不放,那么就会出现一个逻辑上的死锁,所以这个时候可以通过虚引用来解决。
26 多对多关系
两个一对多的关系就可以变为多对多的关系,例如一个人可以借多本书,一本书可以被多个人借。
27 多线程工具类
在实际的开发之中多线程的同步处理最初提供的是一个synchronized关键字,这个关键字可以实现多个线程访问同一资源的同步处理,但是直接采用这样的类负责操作,整体的难度是很高的,这样为了解决同步的问题,在JDK1.5之后引入了一个:java.util.concurrent开发包,这个开发包的目的主要是为了解决多线程的实现工具类问题。
可以把这个开发包之中所有的程序类简单的理解为线程的工具类,线程的工具类里面就提供有一些线程的支持方法。
28 反射参数
在构造方法里面进行调用的时候为什么要使用“类.class”,而不使用“对象.getClass()”。
Class实际上主要表示一个类的结构,例如:Date有Class类、String也有与之匹配的Class类,而获得了Class就相当于获得了类的操作权限,哪怕获得的时候没有实例化对象存在,这个时候也可以操作的。
一般使用getClass()方法的时候都会在某个方法里面需要通过反射获取对象结构的是时候使用。
29 反射与new
对于反射机制而言,本质上的目的:避免具体的对象操作,而new处理是需要明确的耦合性。
30 各种IO
进行图形的用户信息输入的时候,如果用户不输入信息,则程序就进入到一种阻塞状态,那么这种阻塞的状态一定要在输入完成后才会解除,这就是同步IO。所谓的异步IO简单一点来讲在阻塞的时候其它的线程依然可以执行。
- BIO:同步阻塞IO,就是传统的操作实现模式,就是传统的IO处理,像最基础的InputStream
- NIO:异步阻塞IO,做一个零拷贝操作,正常的文件操作是通过CPU向内存要数据,而后内存向硬盘要数据,而零阻塞指的是内存直接将读取到的数据发送给客户端,中间不再经过CPU处理,里面重要的是一个Channel
- AIO:异步非阻塞IO,发出等待之后用户就继续向下执行了,完成后获得一个通知
31 范型通配符问题
范型可以设置所有的类型,对于范型的应用除了可以在自定义类上使用,可能使用最多的环境就是反射机制上,例如工厂设计模式。
“T”一般用于在范型类型的申明上,“?”永远在方法的接收参数,或者返回类型上。
32 范型中“T”与“?”的区别
对于这两种操作大不部分情况下我们是不进行比较的,因为两者的使用环境不同,在大部分情况习惯如果要进行方法的参数接收会考虑使用“?”,它的特点是可以保证程序不出现不必要的修改。
“<T>”也可以用在方法上,那么这个时候就表示这个T应该是一个具体的类型(类型、接口)。如果该类型不存在则无法使用。使用“类<?>”表示只能够取得内容,但不允许设置内容。
33 方法变量与同步
方法之中的变量都是属于局部变量,也就是说如果我们真的去考虑线程安全性问题,一定是在多个线程访问同一个资源的时候进行的,那么既然是同一个资源,就必须考虑Runnable、Callable接口来实现多线程处理关系。
方法的定义上如果使用了synchronized,那么这个方法之中就表示同步的处理操作,那么这个同步的处理操作之中指的是当前的方法只允许有一个线程进入,但是会有其它的线程等待进入处理。在一个同步线程的处理之中,变量肯定是同步的。线程同步处理之中不会去考虑方法中的参数,只会考虑类中的属性。
34 高并发处理包
在java里面有一个包:java.util.concurrent包,这组开发包是从JDK1.5的时候开始添加到JDK系统之中,主要的目的是进行高并发访问的处理,也就是说通过这个开发包实现的程序都将基于线程池的高速操作完成。
那么HashMap、Hashtable、ConcurrentHashMap有什么区别呢?
- Hashtable:进行公共数据保存的时候线程的安全性是最高的,因为每个时刻只允许一个线程进行操作;
- HashMap:所有的方法都属于异步处理的,那么属于非线程安全,这样可以保证操作速度快,前提是:处理多个用户并发访问,但是不安全;
- ConcurrentHashMap:进行数据存储或读取的时候并不是简单的按照hashCode()进行简单的存放,而是经过了一些处理(segment(分段锁))之后以保证高速的响应。但是前提是:你需要有一个并发访问的Map的高效数据。
35 缓冲流与内存流的区别
内存流的本质就是将所有的数据在内存之中进行完整的处理操作。核心的概念在于内存流可以进行整体的数据处理。
如果从实现来讲,两者是可以部分互通的,如果从实用的角度来讲,缓存流更多的是暂时的操作,缓存流操作更多的情况下有一个间隔。但是这个间隔往往不会保存过多的内容。比较适合中文处理例如,(bufferedReader)。
36 基本类型和包装类
基本类型与包装类最大的区别有两点:
- 包装类是以对象的形式运行,而且JDK1.5之后针对包装类又提供自动的装箱与拆箱处理机制;
- 包装类可以进行null的描述(使用基本类型,不设置内容就是对应数据类型默认值,如果使用了包装类就是null);
37 基本数据类型与引用传递
在Java里面数据类型有两种:基本类型、引用类型。
38 集合信息取得
get可以轻松的进行元素的定位,get方法是主要起扩充的方法。
区分(ArrayList和LinkedList)。
对于集合的输出:
- for循环
- Iterator
39 接口标准
对于接口本身而言,只是一个方法视图。继承类强制性实现。便于分层,可以实现标准化设计。
40 接口的使用
区分接口和抽象类。
接口的一个核心意义是暴露远程结构的(方法视图)。 抽象类是留给接口和子类之间做过渡使用的。
关心的点:
- 接口定义的功能是否够用?
- 结构设计是否合理(特别多的继承关系就不好),子类是否有重复?
一个接口可以有多个子类,一个子类可以实现多个接口,一个子类只能实现一个抽象类。
41 进程间通讯
JVM间的通讯,可以使用Socket编程,也可以使用公共文件,或者直接进行管道流处理。
42 进程与线程
每启动一个Jvm进程,实际上都要执行一个完整的进程生命周期,也就是说其使用的资源会更加的庞大。而对于线程优势在于启动速度快,而java采用了多线程的处理方式,整个系统运行之中进程只会执行1次。
所有的线程都受到进程的控制,如果你的进程被毁了,那么所有的线程也就完蛋了。
43 链表为什么要用内部类
内部类的特点:
- 内部类可以方便的与外部类之间进行私有属性的访问
- 内部类使用private,可以进行方法作用域控制
44 内存流和管道流
在java里面,IO的设计是非常全面的。
内存是直接基于程序内存做的一种简单的IO处理。,可以把内存想象成文件,但这个文件不会出现在磁盘上,所以内存流是在需要产生IO的情况下,但是又不希望产生实际的存储文件的时候采用的一种IO方案。
管道最早是来自与Unix系统中的一个概念,指的是两个进程之间的通讯关系,同一个程序由于运行的进程不同,所以其拥有各自的数据存储空间。Java并没有进程的开发,所以为了保证两个进程之间可以互相的沟通,提供有了管道流的概念,而java是多线程的编程语言,所以就只有在多线程的结构上使用了管道的概念。
45 如何学习Java
第一阶段:基础阶段
- SQL语句:查询、更新、建表、约束、存储过程
- Java基础:基础语法(数据类型、if…else、while、for)、面向对象、常用类库、Java类集、java Io、JDBC、DAO设计模式
- JSP开发:JSP+DAO、MVC开发
第二阶段:中级开发阶段
- 性能调优
- Json、XML和Dom解析
- 掌握一个前端框架
- 开发框架、构建工具
第三阶段:框架开发
- Struts、Hibernate
- Spring、Spring Mvc、Mybatis
- JDK源码和框架源码
46 什么时候使用Object对象接收
Object之所以会被大量的进行参数的接收处理,很大的一部分原因在于:程序里面需要接收的类型很多,并不固定。可是现在的开发理念之中强调的问题不再是这一点了,而是如何可以避免向下转型(如果避无可避,那么就用),因为JDK1.5之后引入了范型机制,现在Api文档里接收Object对象的方法也是越来越少了,所以要尽量避免。
47 线程池
典型的例子就是数据库的连接池上,可以使用一个专门的类完成:java.util.concurrent包中。
//接口 public interface ExecutorService extends Executor{} //线程执行操作: public void execute(Runnable command){} //创建一个无限大小的线程池: ExecutorService service1 = Executors.newCachedThreadPool(); //创建三个大小的线程池: ExecutorService service2 = Executors.newFixedThreadPool(3); service1.execute(new Runnable{}); //可用线程数 int x = Runtime.getRuntime().availableProcessors();
48 线程同步工具类
CycleBarrier和CountDownLatch:
- 这两个类都是在java.util.concurrent包中
- CountDownlatch线程执行完之后再执行,本质就是执行了一个阻塞的操作处理,做减法
- CycleBarrier是一个互相的等待状态,做加法
- CountDownLatch是一计到底,一直减不能重置,CycleBarrier可以重置
49 向下转型
向上转型:可以达到参数的统一,例如子类转父类,顶端是Object。
向下转型:需要使用子类特定的操作形式完成,但是从实际的开发来讲,向下转型是不推荐使用的,推荐使用的只有向上转型。不推荐的原因是因为其存在安全隐患。需要强制性处理,存在类型不匹配,抛出异常ClassCastException。
50 虚拟内存
从java8开始取消了永久代,而使用元空间来进行操作,那么也就是说java可以直接使用操作系统的内存进行处理,这样就有可能导致每一个线程分配的真实的主机内存空间越大,所以这个时候如果内存不足,操作系统会进行虚拟内存的控制。对于虚拟内存不需要做特别多的处理。
当线程访问量追加,那么JVM就有可能进行不断的内存申请以及不断的内存回收,对JVM的-Xmx、Xms的两个参数的控制就非常重要。
51 一道java面试题分析(代码块)
程序的执行是由父到子完成的。
- 代码块:代码块它一共分为4种代码块(普通代码块、构造块、static代码块、同步块)
- static代码块优先于构造方法执行,而且优先于主方法执行
- 构造块优先于构造方法执行,所以static代码块一定也优先于构造方法执行
- 在子类对象实例化的时候一定会默认先去执行父类中的构造方法,而后再执行子类自己的构造方法
实际开发中代码块比较少,在junit单元测试的时候往往会用到。
52 引用传递是什么?
java中包含数值传递和引用传递。
同一块堆内存空间可以被不同的栈内存指向,引用数据类型的真正内容在堆内存里面。传递的是一个地址。
基本数据类型的传递进行数值传递,是一个内容的拷贝,新的数值改变原来的数值没有影响。
53 转义字符处理
转义字符:\\(\)、\n、\t,这些符号是字符串定义的时候认可的。 正则的操作如果写在了字符串符号里面必须转义。例如:\\d 。
54 资源注入
@Resource、@Autowired,这两个注解都是直接利用反射进行对象的引用配置。没有相同的Bean对象的时候@Resource和@Autowired是没有区别的,而最重要的是相同的情况下,@Autowired无法使用,而@Resource则可以设置名字使用它。
使用@Resource避免了引用关系的配置,而简化了程序的开发代码。
55 字节流和字符流
区别不是很大,所有磁盘保存的数据文件以及网络传输的文件实际上都是字节数据,但是为了让处理中文的时候更方便一些(仅仅是为了更方便一些),所以使用字符流来操作,例如,在进行WEB开发的时候往往会利用Writer类来实现内容的响应,就是因为里面有中文的支持。
byte、char(String),在java里面有两套类:解决输出问题的打印流(不管字节还是字符操作的形式相同)、输入数据的Scanner。