1、java中的修饰符有那些?他们各自的访问权限是怎样的?
有四种,分别是private、default、protected、public
private:java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的属性即方法只能被该类自身的对象访问,其子类不能访问,更不允许跨包访问(同包中的类和继承类和其他类不可访问)。
default:即不加任何访问权限修饰符,通常称为“默认访问权限”或者“包访问权限”。该模式下,只允许在同一个包中访问(继承类和其他类不可访问)。
protected: 介于public和private之间 的一种访问修饰符,一般称之为“保护访问权限”。被其修饰的属性以及方法只允许被类本身及其子类访问,即使子类在不同的包中也可以访问(同包中的类和其他类不可访问)。
public:java语言中访问权限最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问
2、列举你知道的基本类型,并说说个基本(数值)类型占几个字节?
Byte(1)、Short(2)、Integer(4)、Long(8)、Float(4)、Double(8)、Character(2)、Boolean(4)。
3、假设一个系统类man的定义如下,请用你所知道的方法实例化man,并代码修改Secret为I love you
public final class man {
private String name;
private int age;
private String secret="Do not tell anyone";
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(){
this.age=age;
}
public String getSecret(){
return secret;
}
}
答案:利用反射来修改对象中的私有属性
//答案代码------利用反射来修改对象中的私有属性
import java.lang.reflect.Field;
public final class man {
private String name;
private int age;
private String secret="Do not tell anyone";
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(){
this.age=age;
}
public String getSecret(){
return secret;
}
//添加的代码
public static void main(String[] args){
man manttest=new man();
Class<?> c=man.class;
try {
// 获得指定类的属性
Field secret_val=c.getDeclaredField("secret");
// 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
secret_val.setAccessible(true);
// 更改私有属性的值
secret_val.set(manttest,"I love you");
System.out.println(manttest.getSecret());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
4、String s="123"和String s=new String("123")有区别吗?你对String对象的intern()熟悉吗?说说你的理解。
1、String s="123" 是创建一个对象“123” 放入常量池中
String s=new String("123") 是创建两个对象,首先new String()的参数是String对象,创建“123”放入常量池,然后在new一个对象放入堆中。
2、intern()方法会首先从常量池中查找是否存在该常量值,如果常量池中不存在则现在常量池中创建,如果已经存在则直接返回
5、a.hashCode()有什么用?与a.equals(b)有什么关系?有没有可能两个不相等的对象有相同的hashCode?
1、hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
2、equals()相等的两个对象,hashCode()一定相等;hashCode()不相等,一定能推出equals()也不相等;hashCode()相等,equals()可能相等,也可能不等。
3、有,因为hashcode是为了确定对象保存在散列表的位置,但是我们都知道会发生哈希冲突,就是因为对象的hashcode会相同,导致哈希冲突。
6、ConncurrentHashMap和hashtable比较(两个线程并发访问map中同一条链,一个线程在尾部删除,一个线程在前面遍历查找,请问为什么前面的线程还能正确的查找到后面被另一个线程删除的节点)
ConcurrentHashMap融合了hashtable和hashmap二者的优势。hashtable是做了同步的,即线程安全,hashmap未考虑同步。所以hashmap在单线程情况下效率较高。hashtable在的多线程情况下,同步操作能保证程序执行的正确性。但是hashtable是阻塞的,每次同步执行的时候都要锁住整个结构,ConcurrentHashMap正是为了解决这个问题而诞生的,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术(一个Array保存多个Object,使用这些对象的锁作为分离锁,get/put时随机使用任意一个)。它使用了多个锁来控制对hash表的不同部分进行的修改。在JDK 1.6中,有HashEntry结构存在,每次插入将新添加节点作为链的头节点(同HashMap实现),而且每次删除一个节点时,会将删除节点之前的所有节点拷贝一份组成一个新的链,而将当前节点的上一个节点的next指向当前节点的下一个节点,从而在删除以后有两条链存在,因而可以保证即使在同一条链中,有一个线程在删除,而另一个线程在遍历,它们都能工作良好,因为遍历的线程能继续使用原有的链。
7、请介绍下java中存在那些ClassLodaer并描述下双亲委派模型?
1、主要分为:启动类加载器、扩展类加载器、应用类加载器、用户自定义类加载器
2、当需要加载一个类的时候,子类加载器并不会马上去加载,而是依次去请求父类加载器加载,一直往上请求到最高类加载器(启动类加载器)。当最高类加载器(启动类加载器)加载不了的时候,依次往下让子类加载器进行加载。当达到最底的时候,如果还是加载不到该类,就会出现ClassNotFound的情况。
8、jvm调优的常见命令行工具有那些?jvm常见的调优参数有那些?
1、有以下命令行工具:
1)jps命令用于查询正在运行的JVM进程,
2)jstat可以实时显示本地或远程JVM进程中类装载、内存、垃圾收集、JIT编译等数据
3)jinfo用于查询当前运行这的JVM属性和参数的值。
4)jmap用于显示当前Java堆和永久代的详细信息
5)jhat用于分析使用jmap生成的dump文件,是JDK自带的工具
6)jstack用于生成当前JVM的所有线程快照,线程快照是虚拟机每一条线程正在执行的方法,目的是定位线程出现长时间停顿的原因
2、有以下参数:
1)-Xms:初始堆大小,默认是物理内存的1/64。默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到–Xmx的最大限制。例如:-Xms 20m。
2)-Xmx:最大堆大小。默认是物理内存的1/4 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。
3)-XX:NewSize=n:设置年轻代大小(初始值)。
4)-XX:MaxNewSize:设置年轻代最大值。
5)**-XX:NewRatio=n:**设置年轻代和年老代的比值。
6)-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。
7)-XX:PermSize(1.8之后改为MetaspaceSize) 设置持久代(perm gen)初始值,默认是物理内存的1/64。
8)-XX:MaxPermSize=n:(1.8之后改为MaxMetaspaceSize)设置最大持久代大小。
9)-Xss:每个线程的堆栈大小。
9、java中如何实现一个线程,sleep()、suspend()和wait()之间有什么区别?
1、Thread、Runnable和Callable以及线程池
2、sleep() 此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
suspend() 方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁
wait() 对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
10、什么是ThreadLocal变量?介绍下Synchronized、ReentrantLock?
1、ThreadLocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。
2、sychronized是java中最基本同步互斥的手段,可以修饰代码块,方法,类。在修饰代码块的时候需要一个reference对象作为锁的对象。在修饰方法的时候默认是当前对象作为锁的对象。在修饰类时候默认是当前类的Class对象作为锁的对象。synchronized会在进入同步块的前后分别形成monitorenter和monitorexit字节码指令.在执行monitorenter指令时会尝试获取对象的锁,如果此没对象没有被锁,或者此对象已经被当前线程锁住,那么锁的计数器加一,每当monitorexit被锁的对象的计数器减一。直到为0就释放该对象的锁。由此synchronized是可重入的,不会出现自己把自己锁死。
3、ReentrantLock以对象的方式来操作对象锁.相对于sychronized需要在finally中去释放锁。
题外话(synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中。在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态)
11、有三个线程T1、T2,T3怎么确保他们按顺序执行?
//T3先执行,在T3的run中,调用t2.join,让t2执行完成后再执行t3。在T2的run中,调用t1.join,让t1执行完成后再让T2执行。
public class JoinTest2 {
public static void main(String[] args) {
final Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1");
}
});
final Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
//引用t1线程,等待t1线程执行完
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2");
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
//引用t2线程,等待t2线程执行完
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t3");
}
});
t3.start();
t2.start();
t1.start();
}
}
12、volatile变量和atomic变量有什么不同?
volatile保证一个线程对变量的修改对其他线程可见,无法保证原子性。当只有一个线程修改共享变量时,适合使用volatile
Atomic相对于volatile语义更强,它保证了多线程下线程安全
13、介绍下TCP和UDP的区别,TCP为什么不是两次连接?而要三次握手?
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
2、为了实现可靠数据传输, TCP 协议的通信双方,都必须维护一个序列号,以标识发送出去的数据包中,哪些是已经被对方收到的。三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认
14、基于TCP的Socket网络编程的主要步骤是什么?通信过程中可能出现粘包,请解释下这个问题出现的原因和解决办法?
1、服务器端流程:
1、创建服务器套接字---分配内存、初始化
2、服务器套接字--侦听
3、建版立与客户端配套的客户端套接字
4、与客户端通讯(可以多客户端)
5、关闭、销毁服务器端相应套接字
客户端:
1、创建客户端套接字---分配内存、初始权化
2、连接服务器
3、与服务器通讯
4、关闭、销毁客户端套接字
2、出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。
1)发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
2)接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
3、粘包的处理方式:
(1)当时短连接的情况下,不用考虑粘包的情况
(2)如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
(3)如果双方建立长连接,需要在连接后一段时间内发送不同结构数据
接收方创建预处理线程,对接收到的数据包进行预处理,将粘连的包分开;
15、什么是NIO?javaNIO中的Channel、Selector分别是什么?
1、java.nio全称java non-blocking IO(实际上是 new io),是指JDK 1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络
2、Channel通道是数据操作的工具,负责将数据读入缓冲区以及从缓冲区写入目的地;Selector则是使用IO复用模型的解决方案,支持单个线程维护管理多个通道。(Buffer即缓冲区,暂存输入输出数据的区域)
16、介绍下Netty框架,介绍下Netty的线程模型和重要组件
1、Netty主要为需要开发高性能应用的开发者解决了“技术”的和“体系结构”的问题。首先,它的基于 Java NIO 的异步的和事件驱动的实现,保证了高负载下应用程序性能的最大化和可伸缩性。其次, Netty 也包含了一组设计模式,将应用程序逻辑从网络层解耦,简化了开发过程,同时也最大限度地提高了可测试性、模块化以及代码的可重用性。
2、netty的线程模型是基于Reactor模型的。有Reactor单线程模型、Rector多线程模型、主从Reactor线程模型。
3、Netty中主要组件包括:
- Channel:代表了一个链接,与EventLoop一起用来参与IO处理。
- ChannelHandler:为了支持各种协议和处理数据的方式,便诞生了Handler组件。Handler主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。
- ChannelPipeline:提供了 ChannelHandler 链的容器,并定义了用于在该链上传播入站
和出站事件流的 API。
- EventLoop:Channel处理IO操作,一个EventLoop可以为多个Channel服务。
- EventLoopGroup:会包含多个EventLoop。