Java程序员面试题(基础篇)(二)

1、自增前置和后置操作符

  • ++i 在程序执行前进行自增
  • i++ 在程序执行完毕后自增

2、String,StringBuilder,StringBuffer 区别

  • String 是不可变类,线程安全的, 对象一旦被创建,字符串的内容将不能被改变。
  • StringBuffer 是可变类,线程安全的,当对象被创建后,仍然可以对字符串的内容进行修改。
  • StringBuilder是可变类,非线程安全的,当对象被创建后,仍然可以对字符串的内容进行修改 。
  • 执行效率:StringBuilder > StringBuffer > String

3、线程中方法

  • wait():使线程暂停执行的方法,如果线程对一个同步对象发出了一个 wait()调用请求,那么该线程会暂停执行,被调对象进入等待状态,直到被唤醒(通常使用 notify()唤醒)或等待时间超时。
  • sleep():使当前运行的线程休眠指定的时间。
  • stop():终止线程的执行,会释放已经锁定的所有的监视资源。
  • suspend():将一个线程挂起(暂停),并且不会自动恢复,必须通过调用对应的resume(),才能使得线程重新进入可执行状态。

4、 Hashtable和HashMap 相同点和区别

相同点:

  • 都是键值对(key-value)形式
  • 都实现了 Map 接口

区别:

  • HashMap允许空(null)键值(key)(注意,最多只允许一条记录的键为null),而Hashtable不允许。
  • Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。
  • Hashtable 的方法是线程安全的,而 HashMap 不是线程安全的。所以效率上HashMap可能高于Hashtable。
  • 由于Hashtable是线程安全的,没有采用快速失败机制;HashMap是非线程安全,迭代HashMap 采用了快速失败机制。
  • 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
  • Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

快速失败(fail-fast)是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,可能会产生 fail-fast事件。例:两个线程(线程1与线程2)当线程1通过 Iterator(迭代器)在遍历集合A中的元素,如果线程2修改了集合A(删除或增加新的元素),这个时程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast事件。

5、变量名、方法名和数组命名规范

  • 只有由字母,数字,下划线和$组成
  • 并且第一个字符只能是 字母,下滑线或$

6、List<? extends T>List<? super T>区别

  • <? extends T>表示类型的上界,参数化的类型可能是 T 或者 T 的子类。
  • <? super T>表示类型的下界,参数化的类型可能是 T 或者 T 的父类。

7、final,finally 和 finalize 有什么区别

  • final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
  • finally 是异常处理语句结构的一部分,表示总是执行,try catch finally。
  • finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

8、equals 和==的区别

  • equals 比较引用对象类型内容,对象需要 override 覆写。
  • == 基本类型,比较的是栈内存地址。

9、Java默认序列化如何去做,哪些字段不会被序列化

  • 序列化的实现:将需要被序列化的类实现 Serializable 接口,该接口没有需要实现的方法,默认序列化机制。
  • 使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。
  • 对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。
  • static和transient字段不能被序列化。

10、Vector、ArrayList和LinkedList 有什么特点

相同点

  • 都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组

不同点

  • ArrayList 是线程序不安全的,它的元素可以通过get/set方法直接访问。
  • Vector 是线程安全的,和ArrayList类似。
  • LinkedList 是线程序不安全的,一个双链表,允许所有元素(包括 null)。在添加和删除元素时具有比ArrayList更好的性能。但在get与set方面弱于ArrayList。当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比。它还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer()、peek()、poll()等。

参考资料 https://zhuanlan.zhihu.com/p/34828859

Java程序员面试题(基础篇)(一)

1、方法修饰符访问级别

  • public > default > protected > private

2、修饰符的使用范围

3、常见Java容器类型区别

4、接口和抽象类的相同和不同点

相同点:

  • 都不能被实例化
  • 只有在实现或继承后实现类或子类才能实例化

不同点:

  • 关键字:实现接口implements;继承抽象类 extends。
  • 关系:接口可以有多个实现类;抽象类只能有一个继承类。
  • 成员变量:接口只能是public static final修饰的,且必须赋初值;抽象类可以是public,default,protected,private修饰的。
  • 成员方法:接口只能public abstract修饰的;抽象类可以是public abstract的抽象方法,也可以是其他正常方法。

5、Object类中方法

6、原始类型 (8种)

  • 浮点型:float,double(包装类:Float,Double)
  • 布尔型:boolean(包装类:Boolean)
  • 字符型:char(包装类:Character)
  • 数值型:byte,short,int,long(包装类:Byte,Short,Integer,Long)

7、实现多线程的方法

  • 继承Thread类,重写run方法
  • 实现Runnable接口,实现run方法
  • 实现Callable接口,重写call方法

8、什么是不可变量类,包括哪些

  • 不可变类:是指创建实例之后,就不允许修改它的值,只允许读操作
  • 基本类型的包装类:Short, Integer, Long, Float, Double, Byte, Character, Boolean
  • 此外String类等

参考资料: https://www.cnblogs.com/jaylon/p/5721571.html https://www.zhihu.com/question/20618891

9、关键字功能介绍

static

  • 为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。
  • 在不创建对象的情况下,可以通过类来直接调用方法或使用类的属性。
  • 被static修饰的属性(方法)是类的属性(方法),不属于任何对象。

synchronized

  • 主要用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块时,同一时刻最多只有一个线程执行这段代码。

serialize

  • 序列化,将对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
  • 在网络上传送对象的字节序列。

对象的序列化指的是把对象转换为字节序列的过程。 对象的反序列化指的是把字节序列恢复为对象的过程。

transient

  • 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
  • transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
  • 被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

volatile

  • 保证变量对所有的线程的可见性,即当一个线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。
  • 禁止编译器 指令重排优化。

final

  • 修饰类,表明这个类不能被继承(断子绝孙类)。
  • 修饰方法,这个方法不能被子类重写。
  • 修饰变量,如果是基本数据类型的变量,则其数值一旦被初始化之后便不能更改,如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

supper

  • 调用父类的构造方法、父类的方法和属性

this

  • 调用当前对象的某个方法或某个成员时

10、构造方法

  • 类中的构造方法是可以省略的,当省略的时候,编译器会提供一个默认的构造方法以供使用。
  • 构造方法必须与类名相同。
  • 构造方法可以重载,一个类可以定义多个构造方法。
  • 当一个对象被 new的时候必定会调用构造方法。

docker 实践问题汇总

【问题1】 Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

【解决】 没有启动 docker 服务,执行启动docker服务 # servcei docker run  

【问题2】 Job for docker.service failed because the control process exited with error code. See “systemctl status docker.service” and “journalctl -xe” for details

【解决】 Docker启动异常的可能原因:

  • 1、内存不够:Docker 启动至少需要2G内存,首先执行free -mh命令查看剩余内存是否足够
  • 2、端口冲突:该docker监听端口已经被其他进程占用,一般此种问题容易出现在新部署的服务,或在原有机器上部署新的后台服务,所以在部署之前应该执行命令检查端口是否已经被占用,如果上线后发现占有则应改为可用端口再重启之。  

【问题3】 默认配置下,如果在 CentOS 使用 Docker CE 看到下面的这些警告信息: WARNING: bridge-nf-call-iptables is disabled WARNING: bridge-nf-call-ip6tables is disabled

【解决】 请添加内核配置参数以启用这些功能。

然后重新加载 sysctl.conf 即可 $ sudo sysctl -p  

【docker 使用注意事项】

  • 1、制作镜像尽量避免使用docker commit命令,原因这样制作的镜像像一个黑盒操作,开发人员不知道里面具体改动了那些内容。 docker commit 可以用于被攻击后记录轨迹
  • 2、docker run 宿主机端口:docker虚拟机端口 注意:在冒号前面的端口为宿主机的端口,后面的为虚拟机端口
  • 3、强烈建议将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 –link 参数。
  • 4、使用docker image prune 可以清除无用的虚悬镜像
  • 5、docker run –name 最好使用name参数配置,给启动的docker镜像起一个名字,否则docker每次回自动给其命名,且每次的名字不 一样。  

【dockerfile 编写注意事项】

  • 1、使用dockerfile制作docker镜像时,同类命令尽量使用&&拼接,减少创建的镜像层数,提高镜像创建速度 注意:docker最大镜像层数127
  • 2、dockerfile中记录使用的cmd命令,会被docker run 后面的执行的命令覆盖
  • 3、dockerfile中ADD命令可以实现自动解压的效果。注意,虽然ADD和COPY都可以复制文件,但建议只有在需要对复制文件进行自动解压时使用add。

docker使用国内镜像加速器

使用daocloud 中的国内加速器

在docker上执行上命令,当执行成功后,会自动在/etc/docker/目录下添加daemon.json和key.json

如果生效的话,需要重启docker服务

systemctl restart docker

【参考资料】
https://www.daocloud.io/mirror#accelerator-doc

tomcat重启脚本

由于近期用jenkin发版的时候,发现其中重启tomcat发布服务功能总是不能正常生效,所以我想在jenkin中调用自己写的一段shell脚本来完成重启tomcat的工作